Adding support for the SSE Set scalar intrinsic
[platform/upstream/coreclr.git] / src / jit / hwintrinsicxarch.cpp
1 // Licensed to the .NET Foundation under one or more agreements.
2 // The .NET Foundation licenses this file to you under the MIT license.
3 // See the LICENSE file in the project root for more information.
4
5 #include "jitpch.h"
6
7 #if FEATURE_HW_INTRINSICS
8
9 struct HWIntrinsicInfo
10 {
11     NamedIntrinsic intrinsicID;
12     const char*    intrinsicName;
13     InstructionSet isa;
14 }
15
16 static const hwIntrinsicInfoArray[] = {
17 #define HARDWARE_INTRINSIC(id, name, isa) {NI_##id, name, InstructionSet_##isa},
18 #include "hwintrinsiclistxarch.h"
19 };
20
21 extern const char* getHWIntrinsicName(NamedIntrinsic intrinsic)
22 {
23     return hwIntrinsicInfoArray[intrinsic - NI_HW_INTRINSIC_START - 1].intrinsicName;
24 }
25
26 static const bool isNumericType(var_types type)
27 {
28     switch (type)
29     {
30         case TYP_BYTE:
31         case TYP_UBYTE:
32         case TYP_SHORT:
33         case TYP_USHORT:
34         case TYP_INT:
35         case TYP_UINT:
36         case TYP_LONG:
37         case TYP_ULONG:
38         case TYP_FLOAT:
39         case TYP_DOUBLE:
40             return true;
41
42         default:
43             return false;
44     }
45 }
46
47 //------------------------------------------------------------------------
48 // lookupHWIntrinsicISA: map class name to InstructionSet value
49 //
50 // Arguments:
51 //    className -- class name in System.Runtime.Intrinsics.X86
52 //
53 // Return Value:
54 //    Id for the ISA class.
55 //
56 InstructionSet Compiler::lookupHWIntrinsicISA(const char* className)
57 {
58     if (className != nullptr)
59     {
60         if (className[0] == 'A')
61         {
62             if (strcmp(className, "Aes") == 0)
63             {
64                 return InstructionSet_AES;
65             }
66             else if (strcmp(className, "Avx") == 0)
67             {
68                 return InstructionSet_AVX;
69             }
70             else if (strcmp(className, "Avx2") == 0)
71             {
72                 return InstructionSet_AVX2;
73             }
74         }
75         if (className[0] == 'S')
76         {
77             if (strcmp(className, "Sse") == 0)
78             {
79                 return InstructionSet_SSE;
80             }
81             else if (strcmp(className, "Sse2") == 0)
82             {
83                 return InstructionSet_SSE2;
84             }
85             else if (strcmp(className, "Sse3") == 0)
86             {
87                 return InstructionSet_SSE3;
88             }
89             else if (strcmp(className, "Ssse3") == 0)
90             {
91                 return InstructionSet_SSSE3;
92             }
93             else if (strcmp(className, "Sse41") == 0)
94             {
95                 return InstructionSet_SSE41;
96             }
97             else if (strcmp(className, "Sse42") == 0)
98             {
99                 return InstructionSet_SSE42;
100             }
101         }
102
103         if (strcmp(className, "Bmi1") == 0)
104         {
105             return InstructionSet_BMI1;
106         }
107         else if (strcmp(className, "Bmi2") == 0)
108         {
109             return InstructionSet_BMI2;
110         }
111         else if (strcmp(className, "Fma") == 0)
112         {
113             return InstructionSet_FMA;
114         }
115         else if (strcmp(className, "Lzcnt") == 0)
116         {
117             return InstructionSet_LZCNT;
118         }
119         else if (strcmp(className, "Pclmulqdq") == 0)
120         {
121             return InstructionSet_PCLMULQDQ;
122         }
123         else if (strcmp(className, "Popcnt") == 0)
124         {
125             return InstructionSet_POPCNT;
126         }
127     }
128
129     JITDUMP("Unsupported ISA.\n");
130     return InstructionSet_ILLEGAL;
131 }
132
133 //------------------------------------------------------------------------
134 // lookupHWIntrinsic: map intrinsic name to named intrinsic value
135 //
136 // Arguments:
137 //    methodName -- name of the intrinsic function.
138 //    isa        -- instruction set of the intrinsic.
139 //
140 // Return Value:
141 //    Id for the hardware intrinsic.
142 //
143 // TODO-Throughput: replace sequential search by binary search
144 NamedIntrinsic Compiler::lookupHWIntrinsic(const char* methodName, InstructionSet isa)
145 {
146     NamedIntrinsic result = NI_Illegal;
147     if (isa != InstructionSet_ILLEGAL)
148     {
149         for (int i = 0; i < NI_HW_INTRINSIC_END - NI_HW_INTRINSIC_START; i++)
150         {
151             if (isa == hwIntrinsicInfoArray[i].isa && strcmp(methodName, hwIntrinsicInfoArray[i].intrinsicName) == 0)
152             {
153                 result = hwIntrinsicInfoArray[i].intrinsicID;
154             }
155         }
156     }
157     return result;
158 }
159
160 //------------------------------------------------------------------------
161 // isaOfHWIntrinsic: map named intrinsic value to its instruction set
162 //
163 // Arguments:
164 //    intrinsic -- id of the intrinsic function.
165 //
166 // Return Value:
167 //    instruction set of the intrinsic.
168 //
169 InstructionSet Compiler::isaOfHWIntrinsic(NamedIntrinsic intrinsic)
170 {
171     assert(intrinsic != NI_Illegal);
172     assert(intrinsic > NI_HW_INTRINSIC_START && intrinsic < NI_HW_INTRINSIC_END);
173     return hwIntrinsicInfoArray[intrinsic - NI_HW_INTRINSIC_START - 1].isa;
174 }
175
176 //------------------------------------------------------------------------
177 // isIntrinsicAnIsSupportedPropertyGetter: return true if the intrinsic is "get_IsSupported"
178 //
179 // Arguments:
180 //    intrinsic -- id of the intrinsic function.
181 //
182 // Return Value:
183 //    true if the intrinsic is "get_IsSupported"
184 //    Sometimes we need to specially treat "get_IsSupported"
185 bool Compiler::isIntrinsicAnIsSupportedPropertyGetter(NamedIntrinsic intrinsic)
186 {
187     switch (intrinsic)
188     {
189         case NI_SSE_IsSupported:
190         case NI_SSE2_IsSupported:
191         case NI_SSE3_IsSupported:
192         case NI_SSSE3_IsSupported:
193         case NI_SSE41_IsSupported:
194         case NI_SSE42_IsSupported:
195         case NI_AVX_IsSupported:
196         case NI_AVX2_IsSupported:
197         case NI_AES_IsSupported:
198         case NI_BMI1_IsSupported:
199         case NI_BMI2_IsSupported:
200         case NI_FMA_IsSupported:
201         case NI_LZCNT_IsSupported:
202         case NI_PCLMULQDQ_IsSupported:
203         case NI_POPCNT_IsSupported:
204             return true;
205         default:
206             return false;
207     }
208 }
209
210 //------------------------------------------------------------------------
211 // isFullyImplmentedISAClass: return true if all the hardware intrinsics
212 //    of this ISA are implemented in RyuJIT.
213 //
214 // Arguments:
215 //    isa - Instruction set
216 // Return Value:
217 //    true - all the hardware intrinsics of "isa" are implemented in RyuJIT.
218 //
219 bool Compiler::isFullyImplmentedISAClass(InstructionSet isa)
220 {
221     switch (isa)
222     {
223         case InstructionSet_SSE:
224         case InstructionSet_SSE2:
225         case InstructionSet_SSE3:
226         case InstructionSet_SSSE3:
227         case InstructionSet_SSE41:
228         case InstructionSet_SSE42:
229         case InstructionSet_AVX:
230         case InstructionSet_AVX2:
231         case InstructionSet_AES:
232         case InstructionSet_BMI1:
233         case InstructionSet_BMI2:
234         case InstructionSet_FMA:
235         case InstructionSet_PCLMULQDQ:
236             return false;
237
238         case InstructionSet_LZCNT:
239         case InstructionSet_POPCNT:
240             return true;
241
242         default:
243             unreached();
244     }
245 }
246
247 //------------------------------------------------------------------------
248 // isScalarISA:
249 //
250 // Arguments:
251 //    isa - Instruction set
252 // Return Value:
253 //    true - if "isa" only contains scalar instructions
254 //
255 bool Compiler::isScalarISA(InstructionSet isa)
256 {
257     switch (isa)
258     {
259         case InstructionSet_BMI1:
260         case InstructionSet_BMI2:
261         case InstructionSet_LZCNT:
262         case InstructionSet_POPCNT:
263             return true;
264
265         default:
266             return false;
267     }
268 }
269
270 //------------------------------------------------------------------------
271 // compSupportsHWIntrinsic: compiler support of hardware intrinsics
272 //
273 // Arguments:
274 //    isa - Instruction set
275 // Return Value:
276 //    true if
277 //    - isa is a scalar ISA
278 //    - isa is a SIMD ISA and featureSIMD=true
279 //    - isa is fully implemented or EnableIncompleteISAClass=true
280 bool Compiler::compSupportsHWIntrinsic(InstructionSet isa)
281 {
282     return (featureSIMD || isScalarISA(isa)) && (
283 #ifdef DEBUG
284                                                     JitConfig.EnableIncompleteISAClass() ||
285 #endif
286                                                     isFullyImplmentedISAClass(isa));
287 }
288
289 //------------------------------------------------------------------------
290 // impUnsupportedHWIntrinsic: returns a node for an unsupported HWIntrinsic
291 //
292 // Arguments:
293 //    helper     - JIT helper ID for the exception to be thrown
294 //    method     - method handle of the intrinsic function.
295 //    sig        - signature of the intrinsic call
296 //    mustExpand - true if the intrinsic must return a GenTree*; otherwise, false
297 //
298 // Return Value:
299 //    a gtNewMustThrowException if mustExpand is true; otherwise, nullptr
300 //
301 GenTree* Compiler::impUnsupportedHWIntrinsic(unsigned              helper,
302                                              CORINFO_METHOD_HANDLE method,
303                                              CORINFO_SIG_INFO*     sig,
304                                              bool                  mustExpand)
305 {
306     // We've hit some error case and may need to return a node for the given error.
307     //
308     // When `mustExpand=false`, we are attempting to inline the intrinsic directly into another method. In this
309     // scenario, we need to return `nullptr` so that a GT_CALL to the intrinsic is emitted instead. This is to
310     // ensure that everything continues to behave correctly when optimizations are enabled (e.g. things like the
311     // inliner may expect the node we return to have a certain signature, and the `MustThrowException` node won't
312     // match that).
313     //
314     // When `mustExpand=true`, we are in a GT_CALL to the intrinsic and are attempting to JIT it. This will generally
315     // be in response to an indirect call (e.g. done via reflection) or in response to an earlier attempt returning
316     // `nullptr` (under `mustExpand=false`). In that scenario, we are safe to return the `MustThrowException` node.
317
318     if (mustExpand)
319     {
320         for (unsigned i = 0; i < sig->numArgs; i++)
321         {
322             impPopStack();
323         }
324
325         return gtNewMustThrowException(helper, JITtype2varType(sig->retType), sig->retTypeClass);
326     }
327     else
328     {
329         return nullptr;
330     }
331 }
332
333 //------------------------------------------------------------------------
334 // impX86HWIntrinsic: dispatch hardware intrinsics to their own implementation
335 // function
336 //
337 // Arguments:
338 //    intrinsic -- id of the intrinsic function.
339 //    method    -- method handle of the intrinsic function.
340 //    sig       -- signature of the intrinsic call
341 //
342 // Return Value:
343 //    the expanded intrinsic.
344 //
345 GenTree* Compiler::impX86HWIntrinsic(NamedIntrinsic        intrinsic,
346                                      CORINFO_METHOD_HANDLE method,
347                                      CORINFO_SIG_INFO*     sig,
348                                      bool                  mustExpand)
349 {
350     InstructionSet isa = isaOfHWIntrinsic(intrinsic);
351
352     // This intrinsic is supported if
353     // - the ISA is available on the underlying hardware (compSupports returns true)
354     // - the compiler supports this hardware intrinsics (compSupportsHWIntrinsic returns true)
355     bool issupported = compSupports(isa) && compSupportsHWIntrinsic(isa);
356
357     if (isIntrinsicAnIsSupportedPropertyGetter(intrinsic))
358     {
359         return gtNewIconNode(issupported);
360     }
361     else if (!issupported)
362     {
363         return impUnsupportedHWIntrinsic(CORINFO_HELP_THROW_PLATFORM_NOT_SUPPORTED, method, sig, mustExpand);
364     }
365
366     switch (isa)
367     {
368         case InstructionSet_SSE:
369             return impSSEIntrinsic(intrinsic, method, sig, mustExpand);
370         case InstructionSet_SSE2:
371             return impSSE2Intrinsic(intrinsic, method, sig, mustExpand);
372         case InstructionSet_SSE3:
373             return impSSE3Intrinsic(intrinsic, method, sig, mustExpand);
374         case InstructionSet_SSSE3:
375             return impSSSE3Intrinsic(intrinsic, method, sig, mustExpand);
376         case InstructionSet_SSE41:
377             return impSSE41Intrinsic(intrinsic, method, sig, mustExpand);
378         case InstructionSet_SSE42:
379             return impSSE42Intrinsic(intrinsic, method, sig, mustExpand);
380         case InstructionSet_AVX:
381             return impAVXIntrinsic(intrinsic, method, sig, mustExpand);
382         case InstructionSet_AVX2:
383             return impAVX2Intrinsic(intrinsic, method, sig, mustExpand);
384
385         case InstructionSet_AES:
386             return impAESIntrinsic(intrinsic, method, sig, mustExpand);
387         case InstructionSet_BMI1:
388             return impBMI1Intrinsic(intrinsic, method, sig, mustExpand);
389         case InstructionSet_BMI2:
390             return impBMI2Intrinsic(intrinsic, method, sig, mustExpand);
391         case InstructionSet_FMA:
392             return impFMAIntrinsic(intrinsic, method, sig, mustExpand);
393         case InstructionSet_LZCNT:
394             return impLZCNTIntrinsic(intrinsic, method, sig, mustExpand);
395         case InstructionSet_PCLMULQDQ:
396             return impPCLMULQDQIntrinsic(intrinsic, method, sig, mustExpand);
397         case InstructionSet_POPCNT:
398             return impPOPCNTIntrinsic(intrinsic, method, sig, mustExpand);
399         default:
400             return nullptr;
401     }
402 }
403
404 CORINFO_CLASS_HANDLE Compiler::gtGetStructHandleForHWSIMD(var_types simdType, var_types simdBaseType)
405 {
406     if (simdType == TYP_SIMD16)
407     {
408         switch (simdBaseType)
409         {
410             case TYP_FLOAT:
411                 return Vector128FloatHandle;
412             case TYP_DOUBLE:
413                 return Vector128DoubleHandle;
414             case TYP_INT:
415                 return Vector128IntHandle;
416             case TYP_USHORT:
417                 return Vector128UShortHandle;
418             case TYP_UBYTE:
419                 return Vector128UByteHandle;
420             case TYP_SHORT:
421                 return Vector128ShortHandle;
422             case TYP_BYTE:
423                 return Vector128ByteHandle;
424             case TYP_LONG:
425                 return Vector128LongHandle;
426             case TYP_UINT:
427                 return Vector128UIntHandle;
428             case TYP_ULONG:
429                 return Vector128ULongHandle;
430             default:
431                 assert(!"Didn't find a class handle for simdType");
432         }
433     }
434     else if (simdType == TYP_SIMD32)
435     {
436         switch (simdBaseType)
437         {
438             case TYP_FLOAT:
439                 return Vector256FloatHandle;
440             case TYP_DOUBLE:
441                 return Vector256DoubleHandle;
442             case TYP_INT:
443                 return Vector256IntHandle;
444             case TYP_USHORT:
445                 return Vector256UShortHandle;
446             case TYP_UBYTE:
447                 return Vector256UByteHandle;
448             case TYP_SHORT:
449                 return Vector256ShortHandle;
450             case TYP_BYTE:
451                 return Vector256ByteHandle;
452             case TYP_LONG:
453                 return Vector256LongHandle;
454             case TYP_UINT:
455                 return Vector256UIntHandle;
456             case TYP_ULONG:
457                 return Vector256ULongHandle;
458             default:
459                 assert(!"Didn't find a class handle for simdType");
460         }
461     }
462
463     return NO_CLASS_HANDLE;
464 }
465
466 GenTree* Compiler::impSSEIntrinsic(NamedIntrinsic        intrinsic,
467                                    CORINFO_METHOD_HANDLE method,
468                                    CORINFO_SIG_INFO*     sig,
469                                    bool                  mustExpand)
470 {
471     GenTree* retNode = nullptr;
472     GenTree* op1     = nullptr;
473     GenTree* op2     = nullptr;
474     GenTree* op3     = nullptr;
475     GenTree* op4     = nullptr;
476
477     switch (intrinsic)
478     {
479         case NI_SSE_SetVector128:
480         {
481             assert(sig->numArgs == 4);
482             assert(getBaseTypeOfSIMDType(sig->retTypeSigClass) == TYP_FLOAT);
483
484             op4 = impPopStack().val;
485             op3 = impPopStack().val;
486             op2 = impPopStack().val;
487             op1 = impPopStack().val;
488
489             GenTree* left    = gtNewSimdHWIntrinsicNode(TYP_SIMD16, op4, op3, NI_SSE_UnpackLow, TYP_FLOAT, 16);
490             GenTree* right   = gtNewSimdHWIntrinsicNode(TYP_SIMD16, op2, op1, NI_SSE_UnpackLow, TYP_FLOAT, 16);
491             GenTree* control = gtNewIconNode(68, TYP_UBYTE);
492
493             retNode = gtNewSimdHWIntrinsicNode(TYP_SIMD16, left, right, control, NI_SSE_Shuffle, TYP_FLOAT, 16);
494             break;
495         }
496
497         case NI_SSE_Shuffle:
498         {
499             assert(sig->numArgs == 3);
500             assert(getBaseTypeOfSIMDType(sig->retTypeSigClass) == TYP_FLOAT);
501
502             op3 = impStackTop().val;
503
504             if (op3->IsCnsIntOrI() || mustExpand)
505             {
506                 impPopStack(); // Pop the value we peeked at
507                 op2     = impSIMDPopStack(TYP_SIMD16);
508                 op1     = impSIMDPopStack(TYP_SIMD16);
509                 retNode = gtNewSimdHWIntrinsicNode(TYP_SIMD16, op1, op2, op3, intrinsic, TYP_FLOAT, 16);
510             }
511             else
512             {
513                 // When op3 is not a constant and we are not being forced to expand, we need to
514                 // return nullptr so a GT_CALL to the intrinsic method is emitted instead. The
515                 // intrinsic method is recursive and will be forced to expand, at which point
516                 // we emit some less efficient fallback code.
517
518                 return nullptr;
519             }
520             break;
521         }
522
523         case NI_SSE_Add:
524         case NI_SSE_AddScalar:
525         case NI_SSE_And:
526         case NI_SSE_AndNot:
527         case NI_SSE_CompareEqual:
528         case NI_SSE_CompareEqualScalar:
529         case NI_SSE_CompareGreaterThan:
530         case NI_SSE_CompareGreaterThanScalar:
531         case NI_SSE_CompareGreaterThanOrEqual:
532         case NI_SSE_CompareGreaterThanOrEqualScalar:
533         case NI_SSE_CompareLessThan:
534         case NI_SSE_CompareLessThanScalar:
535         case NI_SSE_CompareLessThanOrEqual:
536         case NI_SSE_CompareLessThanOrEqualScalar:
537         case NI_SSE_CompareNotEqual:
538         case NI_SSE_CompareNotEqualScalar:
539         case NI_SSE_CompareNotGreaterThan:
540         case NI_SSE_CompareNotGreaterThanScalar:
541         case NI_SSE_CompareNotGreaterThanOrEqual:
542         case NI_SSE_CompareNotGreaterThanOrEqualScalar:
543         case NI_SSE_CompareNotLessThan:
544         case NI_SSE_CompareNotLessThanScalar:
545         case NI_SSE_CompareNotLessThanOrEqual:
546         case NI_SSE_CompareNotLessThanOrEqualScalar:
547         case NI_SSE_CompareOrdered:
548         case NI_SSE_CompareOrderedScalar:
549         case NI_SSE_CompareUnordered:
550         case NI_SSE_CompareUnorderedScalar:
551         case NI_SSE_Divide:
552         case NI_SSE_DivideScalar:
553         case NI_SSE_Max:
554         case NI_SSE_MaxScalar:
555         case NI_SSE_Min:
556         case NI_SSE_MinScalar:
557         case NI_SSE_MoveHighToLow:
558         case NI_SSE_MoveLowToHigh:
559         case NI_SSE_MoveScalar:
560         case NI_SSE_Multiply:
561         case NI_SSE_MultiplyScalar:
562         case NI_SSE_Or:
563         case NI_SSE_Subtract:
564         case NI_SSE_SubtractScalar:
565         case NI_SSE_UnpackHigh:
566         case NI_SSE_UnpackLow:
567         case NI_SSE_Xor:
568             assert(sig->numArgs == 2);
569             assert(getBaseTypeOfSIMDType(sig->retTypeSigClass) == TYP_FLOAT);
570             op2     = impSIMDPopStack(TYP_SIMD16);
571             op1     = impSIMDPopStack(TYP_SIMD16);
572             retNode = gtNewSimdHWIntrinsicNode(TYP_SIMD16, op1, op2, intrinsic, TYP_FLOAT, 16);
573             break;
574
575         case NI_SSE_CompareEqualOrderedScalar:
576         case NI_SSE_CompareEqualUnorderedScalar:
577         case NI_SSE_CompareGreaterThanOrderedScalar:
578         case NI_SSE_CompareGreaterThanUnorderedScalar:
579         case NI_SSE_CompareGreaterThanOrEqualOrderedScalar:
580         case NI_SSE_CompareGreaterThanOrEqualUnorderedScalar:
581         case NI_SSE_CompareLessThanOrderedScalar:
582         case NI_SSE_CompareLessThanUnorderedScalar:
583         case NI_SSE_CompareLessThanOrEqualOrderedScalar:
584         case NI_SSE_CompareLessThanOrEqualUnorderedScalar:
585         case NI_SSE_CompareNotEqualOrderedScalar:
586         case NI_SSE_CompareNotEqualUnorderedScalar:
587             assert(sig->numArgs == 2);
588             assert(JITtype2varType(sig->retType) == TYP_BOOL);
589             assert(getBaseTypeOfSIMDType(info.compCompHnd->getArgClass(sig, sig->args)) == TYP_FLOAT);
590             op2     = impSIMDPopStack(TYP_SIMD16);
591             op1     = impSIMDPopStack(TYP_SIMD16);
592             retNode = gtNewSimdHWIntrinsicNode(TYP_BOOL, op1, op2, intrinsic, TYP_FLOAT, 16);
593             break;
594
595         case NI_SSE_ConvertToVector128SingleScalar:
596         {
597             assert(sig->numArgs == 2);
598             assert(getBaseTypeOfSIMDType(sig->retTypeSigClass) == TYP_FLOAT);
599
600 #ifdef _TARGET_X86_
601             CORINFO_CLASS_HANDLE argClass;
602
603             CORINFO_ARG_LIST_HANDLE argLst = info.compCompHnd->getArgNext(sig->args);
604             CorInfoType             corType =
605                 strip(info.compCompHnd->getArgType(sig, argLst, &argClass)); // type of the second argument
606
607             if (varTypeIsLong(JITtype2varType(corType)))
608             {
609                 return impUnsupportedHWIntrinsic(CORINFO_HELP_THROW_PLATFORM_NOT_SUPPORTED, method, sig, mustExpand);
610             }
611 #endif // _TARGET_X86_
612
613             op2     = impPopStack().val;
614             op1     = impSIMDPopStack(TYP_SIMD16);
615             retNode = gtNewSimdHWIntrinsicNode(TYP_SIMD16, op1, op2, intrinsic, TYP_FLOAT, 16);
616             break;
617         }
618
619         case NI_SSE_StaticCast:
620         {
621             assert(sig->numArgs == 1);
622             var_types tgtType = getBaseTypeOfSIMDType(sig->retTypeSigClass);
623             var_types srcType = getBaseTypeOfSIMDType(info.compCompHnd->getArgClass(sig, sig->args));
624
625             if (isNumericType(tgtType) && isNumericType(srcType))
626             {
627                 op1     = impSIMDPopStack(TYP_SIMD16);
628                 retNode = gtNewSimdHWIntrinsicNode(TYP_SIMD16, op1, intrinsic, tgtType, 16);
629             }
630             else
631             {
632                 return impUnsupportedHWIntrinsic(CORINFO_HELP_THROW_PLATFORM_NOT_SUPPORTED, method, sig, mustExpand);
633             }
634             break;
635         }
636
637         case NI_SSE_SetAllVector128:
638         case NI_SSE_SetScalar:
639             assert(sig->numArgs == 1);
640             assert(getBaseTypeOfSIMDType(sig->retTypeSigClass) == TYP_FLOAT);
641             op1     = impPopStack().val;
642             retNode = gtNewSimdHWIntrinsicNode(TYP_SIMD16, op1, intrinsic, TYP_FLOAT, 16);
643             break;
644
645         case NI_SSE_Reciprocal:
646         case NI_SSE_ReciprocalScalar:
647         case NI_SSE_ReciprocalSqrt:
648         case NI_SSE_ReciprocalSqrtScalar:
649         case NI_SSE_Sqrt:
650         case NI_SSE_SqrtScalar:
651             assert(sig->numArgs == 1);
652             assert(getBaseTypeOfSIMDType(sig->retTypeSigClass) == TYP_FLOAT);
653             op1     = impSIMDPopStack(TYP_SIMD16);
654             retNode = gtNewSimdHWIntrinsicNode(TYP_SIMD16, op1, intrinsic, TYP_FLOAT, 16);
655             break;
656
657         case NI_SSE_ConvertToInt32:
658         case NI_SSE_ConvertToInt32WithTruncation:
659         case NI_SSE_ConvertToInt64:
660         case NI_SSE_ConvertToInt64WithTruncation:
661         case NI_SSE_ConvertToSingle:
662         {
663             assert(sig->numArgs == 1);
664             assert(getBaseTypeOfSIMDType(info.compCompHnd->getArgClass(sig, sig->args)) == TYP_FLOAT);
665             var_types callType = JITtype2varType(sig->retType);
666
667 #ifdef _TARGET_X86_
668             if (varTypeIsLong(callType))
669             {
670                 assert(intrinsic == NI_SSE_ConvertToInt64 || intrinsic == NI_SSE_ConvertToInt64WithTruncation);
671                 return impUnsupportedHWIntrinsic(CORINFO_HELP_THROW_PLATFORM_NOT_SUPPORTED, method, sig, mustExpand);
672             }
673 #endif // _TARGET_X86_
674
675             op1     = impSIMDPopStack(TYP_SIMD16);
676             retNode = gtNewSimdHWIntrinsicNode(callType, op1, intrinsic, TYP_FLOAT, 16);
677             break;
678         }
679
680         case NI_SSE_SetZeroVector128:
681             assert(sig->numArgs == 0);
682             assert(getBaseTypeOfSIMDType(sig->retTypeSigClass) == TYP_FLOAT);
683             retNode = gtNewSimdHWIntrinsicNode(TYP_SIMD16, intrinsic, TYP_FLOAT, 16);
684             break;
685
686         default:
687             JITDUMP("Not implemented hardware intrinsic");
688             break;
689     }
690     return retNode;
691 }
692
693 GenTree* Compiler::impSSE2Intrinsic(NamedIntrinsic        intrinsic,
694                                     CORINFO_METHOD_HANDLE method,
695                                     CORINFO_SIG_INFO*     sig,
696                                     bool                  mustExpand)
697 {
698     GenTree*  retNode  = nullptr;
699     GenTree*  op1      = nullptr;
700     GenTree*  op2      = nullptr;
701     var_types baseType = TYP_UNKNOWN;
702     switch (intrinsic)
703     {
704         case NI_SSE2_Add:
705             assert(sig->numArgs == 2);
706             op2      = impSIMDPopStack(TYP_SIMD16);
707             op1      = impSIMDPopStack(TYP_SIMD16);
708             baseType = getBaseTypeOfSIMDType(sig->retTypeSigClass);
709             retNode  = gtNewSimdHWIntrinsicNode(TYP_SIMD16, op1, op2, NI_SSE2_Add, baseType, 16);
710             break;
711
712         default:
713             JITDUMP("Not implemented hardware intrinsic");
714             break;
715     }
716     return retNode;
717 }
718
719 GenTree* Compiler::impSSE3Intrinsic(NamedIntrinsic        intrinsic,
720                                     CORINFO_METHOD_HANDLE method,
721                                     CORINFO_SIG_INFO*     sig,
722                                     bool                  mustExpand)
723 {
724     return nullptr;
725 }
726
727 GenTree* Compiler::impSSSE3Intrinsic(NamedIntrinsic        intrinsic,
728                                      CORINFO_METHOD_HANDLE method,
729                                      CORINFO_SIG_INFO*     sig,
730                                      bool                  mustExpand)
731 {
732     return nullptr;
733 }
734
735 GenTree* Compiler::impSSE41Intrinsic(NamedIntrinsic        intrinsic,
736                                      CORINFO_METHOD_HANDLE method,
737                                      CORINFO_SIG_INFO*     sig,
738                                      bool                  mustExpand)
739 {
740     return nullptr;
741 }
742
743 GenTree* Compiler::impSSE42Intrinsic(NamedIntrinsic        intrinsic,
744                                      CORINFO_METHOD_HANDLE method,
745                                      CORINFO_SIG_INFO*     sig,
746                                      bool                  mustExpand)
747 {
748     GenTree*  retNode  = nullptr;
749     GenTree*  op1      = nullptr;
750     GenTree*  op2      = nullptr;
751     var_types callType = JITtype2varType(sig->retType);
752
753     CORINFO_ARG_LIST_HANDLE argLst = sig->args;
754     CORINFO_CLASS_HANDLE    argClass;
755     CorInfoType             corType;
756     switch (intrinsic)
757     {
758         case NI_SSE42_Crc32:
759             assert(sig->numArgs == 2);
760
761 #ifdef _TARGET_X86_
762             if (varTypeIsLong(callType))
763             {
764                 return impUnsupportedHWIntrinsic(CORINFO_HELP_THROW_PLATFORM_NOT_SUPPORTED, method, sig, mustExpand);
765             }
766 #endif
767
768             op2 = impPopStack().val;
769             op1 = impPopStack().val;
770
771             argLst  = info.compCompHnd->getArgNext(argLst);                        // the second argument
772             corType = strip(info.compCompHnd->getArgType(sig, argLst, &argClass)); // type of the second argument
773
774             retNode = gtNewScalarHWIntrinsicNode(callType, op1, op2, NI_SSE42_Crc32);
775
776             // TODO - currently we use the BaseType to bring the type of the second argument
777             // to the code generator. May encode the overload info in other way.
778             retNode->gtHWIntrinsic.gtSIMDBaseType = JITtype2varType(corType);
779             break;
780
781         default:
782             JITDUMP("Not implemented hardware intrinsic");
783             break;
784     }
785     return retNode;
786 }
787
788 GenTree* Compiler::impAVXIntrinsic(NamedIntrinsic        intrinsic,
789                                    CORINFO_METHOD_HANDLE method,
790                                    CORINFO_SIG_INFO*     sig,
791                                    bool                  mustExpand)
792 {
793     GenTree*  retNode  = nullptr;
794     GenTree*  op1      = nullptr;
795     GenTree*  op2      = nullptr;
796     var_types baseType = TYP_UNKNOWN;
797     switch (intrinsic)
798     {
799         case NI_AVX_Add:
800             assert(sig->numArgs == 2);
801             op2      = impSIMDPopStack(TYP_SIMD32);
802             op1      = impSIMDPopStack(TYP_SIMD32);
803             baseType = getBaseTypeOfSIMDType(sig->retTypeSigClass);
804             retNode  = gtNewSimdHWIntrinsicNode(TYP_SIMD32, op1, op2, NI_AVX_Add, baseType, 32);
805             break;
806
807         default:
808             JITDUMP("Not implemented hardware intrinsic");
809             break;
810     }
811     return retNode;
812 }
813
814 GenTree* Compiler::impAVX2Intrinsic(NamedIntrinsic        intrinsic,
815                                     CORINFO_METHOD_HANDLE method,
816                                     CORINFO_SIG_INFO*     sig,
817                                     bool                  mustExpand)
818 {
819     GenTree*  retNode  = nullptr;
820     GenTree*  op1      = nullptr;
821     GenTree*  op2      = nullptr;
822     var_types baseType = TYP_UNKNOWN;
823     switch (intrinsic)
824     {
825         case NI_AVX2_Add:
826             assert(sig->numArgs == 2);
827             op2      = impSIMDPopStack(TYP_SIMD32);
828             op1      = impSIMDPopStack(TYP_SIMD32);
829             baseType = getBaseTypeOfSIMDType(sig->retTypeSigClass);
830             retNode  = gtNewSimdHWIntrinsicNode(TYP_SIMD32, op1, op2, NI_AVX2_Add, baseType, 32);
831             break;
832
833         default:
834             JITDUMP("Not implemented hardware intrinsic");
835             break;
836     }
837     return retNode;
838 }
839
840 GenTree* Compiler::impAESIntrinsic(NamedIntrinsic        intrinsic,
841                                    CORINFO_METHOD_HANDLE method,
842                                    CORINFO_SIG_INFO*     sig,
843                                    bool                  mustExpand)
844 {
845     return nullptr;
846 }
847
848 GenTree* Compiler::impBMI1Intrinsic(NamedIntrinsic        intrinsic,
849                                     CORINFO_METHOD_HANDLE method,
850                                     CORINFO_SIG_INFO*     sig,
851                                     bool                  mustExpand)
852 {
853     return nullptr;
854 }
855
856 GenTree* Compiler::impBMI2Intrinsic(NamedIntrinsic        intrinsic,
857                                     CORINFO_METHOD_HANDLE method,
858                                     CORINFO_SIG_INFO*     sig,
859                                     bool                  mustExpand)
860 {
861     return nullptr;
862 }
863
864 GenTree* Compiler::impFMAIntrinsic(NamedIntrinsic        intrinsic,
865                                    CORINFO_METHOD_HANDLE method,
866                                    CORINFO_SIG_INFO*     sig,
867                                    bool                  mustExpand)
868 {
869     return nullptr;
870 }
871
872 GenTree* Compiler::impLZCNTIntrinsic(NamedIntrinsic        intrinsic,
873                                      CORINFO_METHOD_HANDLE method,
874                                      CORINFO_SIG_INFO*     sig,
875                                      bool                  mustExpand)
876 {
877     assert(sig->numArgs == 1);
878     var_types callType = JITtype2varType(sig->retType);
879
880 #ifdef _TARGET_X86_
881     if (varTypeIsLong(callType))
882     {
883         return impUnsupportedHWIntrinsic(CORINFO_HELP_THROW_PLATFORM_NOT_SUPPORTED, method, sig, mustExpand);
884     }
885 #endif
886
887     return gtNewScalarHWIntrinsicNode(callType, impPopStack().val, NI_LZCNT_LeadingZeroCount);
888 }
889
890 GenTree* Compiler::impPCLMULQDQIntrinsic(NamedIntrinsic        intrinsic,
891                                          CORINFO_METHOD_HANDLE method,
892                                          CORINFO_SIG_INFO*     sig,
893                                          bool                  mustExpand)
894 {
895     return nullptr;
896 }
897
898 GenTree* Compiler::impPOPCNTIntrinsic(NamedIntrinsic        intrinsic,
899                                       CORINFO_METHOD_HANDLE method,
900                                       CORINFO_SIG_INFO*     sig,
901                                       bool                  mustExpand)
902 {
903     assert(sig->numArgs == 1);
904     var_types callType = JITtype2varType(sig->retType);
905
906 #ifdef _TARGET_X86_
907     if (varTypeIsLong(callType))
908     {
909         return impUnsupportedHWIntrinsic(CORINFO_HELP_THROW_PLATFORM_NOT_SUPPORTED, method, sig, mustExpand);
910     }
911 #endif
912
913     return gtNewScalarHWIntrinsicNode(callType, impPopStack().val, NI_POPCNT_PopCount);
914 }
915
916 #endif // FEATURE_HW_INTRINSICS