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.
7 #if FEATURE_HW_INTRINSICS
11 NamedIntrinsic intrinsicID;
12 const char* intrinsicName;
16 static const hwIntrinsicInfoArray[] = {
17 #define HARDWARE_INTRINSIC(id, name, isa) {NI_##id, name, InstructionSet_##isa},
18 #include "hwintrinsiclistxarch.h"
21 extern const char* getHWIntrinsicName(NamedIntrinsic intrinsic)
23 return hwIntrinsicInfoArray[intrinsic - NI_HW_INTRINSIC_START - 1].intrinsicName;
26 //------------------------------------------------------------------------
27 // lookupHWIntrinsicISA: map class name to InstructionSet value
30 // className -- class name in System.Runtime.Intrinsics.X86
33 // Id for the ISA class.
35 InstructionSet Compiler::lookupHWIntrinsicISA(const char* className)
37 if (className != nullptr)
39 if (className[0] == 'A')
41 if (strcmp(className, "Aes") == 0)
43 return InstructionSet_AES;
45 else if (strcmp(className, "Avx") == 0)
47 return InstructionSet_AVX;
49 else if (strcmp(className, "Avx2") == 0)
51 return InstructionSet_AVX2;
54 if (className[0] == 'S')
56 if (strcmp(className, "Sse") == 0)
58 return InstructionSet_SSE;
60 else if (strcmp(className, "Sse2") == 0)
62 return InstructionSet_SSE2;
64 else if (strcmp(className, "Sse3") == 0)
66 return InstructionSet_SSE3;
68 else if (strcmp(className, "Ssse3") == 0)
70 return InstructionSet_SSSE3;
72 else if (strcmp(className, "Sse41") == 0)
74 return InstructionSet_SSE41;
76 else if (strcmp(className, "Sse42") == 0)
78 return InstructionSet_SSE42;
82 if (strcmp(className, "Bmi1") == 0)
84 return InstructionSet_BMI1;
86 else if (strcmp(className, "Bmi2") == 0)
88 return InstructionSet_BMI2;
90 else if (strcmp(className, "Fma") == 0)
92 return InstructionSet_FMA;
94 else if (strcmp(className, "Lzcnt") == 0)
96 return InstructionSet_LZCNT;
98 else if (strcmp(className, "Pclmulqdq") == 0)
100 return InstructionSet_PCLMULQDQ;
102 else if (strcmp(className, "Popcnt") == 0)
104 return InstructionSet_POPCNT;
108 JITDUMP("Unsupported ISA.\n");
109 return InstructionSet_ILLEGAL;
112 //------------------------------------------------------------------------
113 // lookupHWIntrinsic: map intrinsic name to named intrinsic value
116 // methodName -- name of the intrinsic function.
117 // isa -- instruction set of the intrinsic.
120 // Id for the hardware intrinsic.
122 // TODO-Throughput: replace sequential search by binary search
123 NamedIntrinsic Compiler::lookupHWIntrinsic(const char* methodName, InstructionSet isa)
125 NamedIntrinsic result = NI_Illegal;
126 if (isa != InstructionSet_ILLEGAL)
128 for (int i = 0; i < NI_HW_INTRINSIC_END - NI_HW_INTRINSIC_START; i++)
130 if (isa == hwIntrinsicInfoArray[i].isa && strcmp(methodName, hwIntrinsicInfoArray[i].intrinsicName) == 0)
132 result = hwIntrinsicInfoArray[i].intrinsicID;
139 //------------------------------------------------------------------------
140 // isaOfHWIntrinsic: map named intrinsic value to its instruction set
143 // intrinsic -- id of the intrinsic function.
146 // instruction set of the intrinsic.
148 InstructionSet Compiler::isaOfHWIntrinsic(NamedIntrinsic intrinsic)
150 assert(intrinsic != NI_Illegal);
151 assert(intrinsic > NI_HW_INTRINSIC_START && intrinsic < NI_HW_INTRINSIC_END);
152 return hwIntrinsicInfoArray[intrinsic - NI_HW_INTRINSIC_START - 1].isa;
155 //------------------------------------------------------------------------
156 // ivalOfHWIntrinsic: get the imm8 value of the given intrinsic
159 // intrinsic -- id of the intrinsic function.
162 // the imm8 value of the intrinsic, -1 for non-IMM intrinsics
164 int Compiler::ivalOfHWIntrinsic(NamedIntrinsic intrinsic)
166 assert(intrinsic != NI_Illegal);
167 assert(intrinsic > NI_HW_INTRINSIC_START && intrinsic < NI_HW_INTRINSIC_END);
171 case NI_SSE_CompareEqual:
172 case NI_SSE_CompareEqualScalar:
175 case NI_SSE_CompareLessThan:
176 case NI_SSE_CompareLessThanScalar:
177 case NI_SSE_CompareNotGreaterThanOrEqual:
178 case NI_SSE_CompareNotGreaterThanOrEqualScalar:
181 case NI_SSE_CompareLessThanOrEqual:
182 case NI_SSE_CompareLessThanOrEqualScalar:
183 case NI_SSE_CompareNotGreaterThan:
184 case NI_SSE_CompareNotGreaterThanScalar:
187 case NI_SSE_CompareUnordered:
188 case NI_SSE_CompareUnorderedScalar:
191 case NI_SSE_CompareNotEqual:
192 case NI_SSE_CompareNotEqualScalar:
195 case NI_SSE_CompareGreaterThanOrEqual:
196 case NI_SSE_CompareGreaterThanOrEqualScalar:
197 case NI_SSE_CompareNotLessThan:
198 case NI_SSE_CompareNotLessThanScalar:
201 case NI_SSE_CompareGreaterThan:
202 case NI_SSE_CompareGreaterThanScalar:
203 case NI_SSE_CompareNotLessThanOrEqual:
204 case NI_SSE_CompareNotLessThanOrEqualScalar:
207 case NI_SSE_CompareOrdered:
208 case NI_SSE_CompareOrderedScalar:
216 //------------------------------------------------------------------------
217 // insOfHWIntrinsic: get the instruction of the given intrinsic
220 // intrinsic -- id of the intrinsic function.
221 // type -- vector base type of this intrinsic
224 // the instruction of the given intrinsic on the base type
225 // return INS_invalid for unsupported base types
227 instruction Compiler::insOfHWIntrinsic(NamedIntrinsic intrinsic, var_types type)
229 assert(intrinsic != NI_Illegal);
230 assert(intrinsic > NI_HW_INTRINSIC_START && intrinsic < NI_HW_INTRINSIC_END);
237 case NI_SSE_AddScalar:
246 case NI_SSE_CompareEqual:
247 case NI_SSE_CompareGreaterThan:
248 case NI_SSE_CompareGreaterThanOrEqual:
249 case NI_SSE_CompareLessThan:
250 case NI_SSE_CompareLessThanOrEqual:
251 case NI_SSE_CompareNotEqual:
252 case NI_SSE_CompareNotGreaterThan:
253 case NI_SSE_CompareNotGreaterThanOrEqual:
254 case NI_SSE_CompareNotLessThan:
255 case NI_SSE_CompareNotLessThanOrEqual:
256 case NI_SSE_CompareOrdered:
257 case NI_SSE_CompareUnordered:
260 case NI_SSE_CompareEqualScalar:
261 case NI_SSE_CompareGreaterThanScalar:
262 case NI_SSE_CompareGreaterThanOrEqualScalar:
263 case NI_SSE_CompareLessThanScalar:
264 case NI_SSE_CompareLessThanOrEqualScalar:
265 case NI_SSE_CompareNotEqualScalar:
266 case NI_SSE_CompareNotGreaterThanScalar:
267 case NI_SSE_CompareNotGreaterThanOrEqualScalar:
268 case NI_SSE_CompareNotLessThanScalar:
269 case NI_SSE_CompareNotLessThanOrEqualScalar:
270 case NI_SSE_CompareOrderedScalar:
271 case NI_SSE_CompareUnorderedScalar:
274 case NI_SSE_CompareEqualOrderedScalar:
275 case NI_SSE_CompareGreaterThanOrderedScalar:
276 case NI_SSE_CompareGreaterThanOrEqualOrderedScalar:
277 case NI_SSE_CompareLessThanOrderedScalar:
278 case NI_SSE_CompareLessThanOrEqualOrderedScalar:
279 case NI_SSE_CompareNotEqualOrderedScalar:
282 case NI_SSE_CompareEqualUnorderedScalar:
283 case NI_SSE_CompareGreaterThanUnorderedScalar:
284 case NI_SSE_CompareGreaterThanOrEqualUnorderedScalar:
285 case NI_SSE_CompareLessThanUnorderedScalar:
286 case NI_SSE_CompareLessThanOrEqualUnorderedScalar:
287 case NI_SSE_CompareNotEqualUnorderedScalar:
290 case NI_SSE_ConvertToInt32:
291 case NI_SSE_ConvertToInt64:
294 case NI_SSE_ConvertToInt32WithTruncation:
295 case NI_SSE_ConvertToInt64WithTruncation:
296 return INS_cvttss2si;
298 case NI_SSE_ConvertToSingle:
299 case NI_SSE_LoadScalar:
300 case NI_SSE_MoveScalar:
303 case NI_SSE_ConvertToVector128SingleScalar:
309 case NI_SSE_DivideScalar:
312 case NI_SSE_LoadAlignedVector128:
313 case NI_SSE_StaticCast:
316 case NI_SSE_LoadHigh:
322 case NI_SSE_LoadVector128:
328 case NI_SSE_MaxScalar:
334 case NI_SSE_MinScalar:
337 case NI_SSE_MoveHighToLow:
340 case NI_SSE_MoveLowToHigh:
343 case NI_SSE_MoveMask:
346 case NI_SSE_Multiply:
349 case NI_SSE_MultiplyScalar:
355 case NI_SSE_Reciprocal:
358 case NI_SSE_ReciprocalScalar:
361 case NI_SSE_ReciprocalSqrt:
364 case NI_SSE_ReciprocalSqrtScalar:
370 case NI_SSE_SqrtScalar:
373 case NI_SSE_Subtract:
376 case NI_SSE_SubtractScalar:
379 case NI_SSE_UnpackHigh:
382 case NI_SSE_UnpackLow:
393 //------------------------------------------------------------------------
394 // isIntrinsicAnIsSupportedPropertyGetter: return true if the intrinsic is "get_IsSupported"
397 // intrinsic -- id of the intrinsic function.
400 // true if the intrinsic is "get_IsSupported"
401 // Sometimes we need to specially treat "get_IsSupported"
402 bool Compiler::isIntrinsicAnIsSupportedPropertyGetter(NamedIntrinsic intrinsic)
406 case NI_SSE_IsSupported:
407 case NI_SSE2_IsSupported:
408 case NI_SSE3_IsSupported:
409 case NI_SSSE3_IsSupported:
410 case NI_SSE41_IsSupported:
411 case NI_SSE42_IsSupported:
412 case NI_AVX_IsSupported:
413 case NI_AVX2_IsSupported:
414 case NI_AES_IsSupported:
415 case NI_BMI1_IsSupported:
416 case NI_BMI2_IsSupported:
417 case NI_FMA_IsSupported:
418 case NI_LZCNT_IsSupported:
419 case NI_PCLMULQDQ_IsSupported:
420 case NI_POPCNT_IsSupported:
427 //------------------------------------------------------------------------
428 // isFullyImplmentedISAClass: return true if all the hardware intrinsics
429 // of this ISA are implemented in RyuJIT.
432 // isa - Instruction set
434 // true - all the hardware intrinsics of "isa" are implemented in RyuJIT.
436 bool Compiler::isFullyImplmentedISAClass(InstructionSet isa)
440 case InstructionSet_SSE:
441 case InstructionSet_SSE2:
442 case InstructionSet_SSE3:
443 case InstructionSet_SSSE3:
444 case InstructionSet_SSE41:
445 case InstructionSet_SSE42:
446 case InstructionSet_AVX:
447 case InstructionSet_AVX2:
448 case InstructionSet_AES:
449 case InstructionSet_BMI1:
450 case InstructionSet_BMI2:
451 case InstructionSet_FMA:
452 case InstructionSet_PCLMULQDQ:
455 case InstructionSet_LZCNT:
456 case InstructionSet_POPCNT:
464 //------------------------------------------------------------------------
468 // isa - Instruction set
470 // true - if "isa" only contains scalar instructions
472 bool Compiler::isScalarISA(InstructionSet isa)
476 case InstructionSet_BMI1:
477 case InstructionSet_BMI2:
478 case InstructionSet_LZCNT:
479 case InstructionSet_POPCNT:
487 //------------------------------------------------------------------------
488 // compSupportsHWIntrinsic: compiler support of hardware intrinsics
491 // isa - Instruction set
494 // - isa is a scalar ISA
495 // - isa is a SIMD ISA and featureSIMD=true
496 // - isa is fully implemented or EnableIncompleteISAClass=true
497 bool Compiler::compSupportsHWIntrinsic(InstructionSet isa)
499 return (featureSIMD || isScalarISA(isa)) && (
501 JitConfig.EnableIncompleteISAClass() ||
503 isFullyImplmentedISAClass(isa));
506 //------------------------------------------------------------------------
507 // impUnsupportedHWIntrinsic: returns a node for an unsupported HWIntrinsic
510 // helper - JIT helper ID for the exception to be thrown
511 // method - method handle of the intrinsic function.
512 // sig - signature of the intrinsic call
513 // mustExpand - true if the intrinsic must return a GenTree*; otherwise, false
516 // a gtNewMustThrowException if mustExpand is true; otherwise, nullptr
518 GenTree* Compiler::impUnsupportedHWIntrinsic(unsigned helper,
519 CORINFO_METHOD_HANDLE method,
520 CORINFO_SIG_INFO* sig,
523 // We've hit some error case and may need to return a node for the given error.
525 // When `mustExpand=false`, we are attempting to inline the intrinsic directly into another method. In this
526 // scenario, we need to return `nullptr` so that a GT_CALL to the intrinsic is emitted instead. This is to
527 // ensure that everything continues to behave correctly when optimizations are enabled (e.g. things like the
528 // inliner may expect the node we return to have a certain signature, and the `MustThrowException` node won't
531 // When `mustExpand=true`, we are in a GT_CALL to the intrinsic and are attempting to JIT it. This will generally
532 // be in response to an indirect call (e.g. done via reflection) or in response to an earlier attempt returning
533 // `nullptr` (under `mustExpand=false`). In that scenario, we are safe to return the `MustThrowException` node.
537 for (unsigned i = 0; i < sig->numArgs; i++)
542 return gtNewMustThrowException(helper, JITtype2varType(sig->retType), sig->retTypeClass);
550 //------------------------------------------------------------------------
551 // impX86HWIntrinsic: dispatch hardware intrinsics to their own implementation
555 // intrinsic -- id of the intrinsic function.
556 // method -- method handle of the intrinsic function.
557 // sig -- signature of the intrinsic call
560 // the expanded intrinsic.
562 GenTree* Compiler::impX86HWIntrinsic(NamedIntrinsic intrinsic,
563 CORINFO_METHOD_HANDLE method,
564 CORINFO_SIG_INFO* sig,
567 InstructionSet isa = isaOfHWIntrinsic(intrinsic);
569 // This intrinsic is supported if
570 // - the ISA is available on the underlying hardware (compSupports returns true)
571 // - the compiler supports this hardware intrinsics (compSupportsHWIntrinsic returns true)
572 bool issupported = compSupports(isa) && compSupportsHWIntrinsic(isa);
574 if (isIntrinsicAnIsSupportedPropertyGetter(intrinsic))
576 return gtNewIconNode(issupported);
578 else if (!issupported)
580 return impUnsupportedHWIntrinsic(CORINFO_HELP_THROW_PLATFORM_NOT_SUPPORTED, method, sig, mustExpand);
585 case InstructionSet_SSE:
586 return impSSEIntrinsic(intrinsic, method, sig, mustExpand);
587 case InstructionSet_SSE2:
588 return impSSE2Intrinsic(intrinsic, method, sig, mustExpand);
589 case InstructionSet_SSE3:
590 return impSSE3Intrinsic(intrinsic, method, sig, mustExpand);
591 case InstructionSet_SSSE3:
592 return impSSSE3Intrinsic(intrinsic, method, sig, mustExpand);
593 case InstructionSet_SSE41:
594 return impSSE41Intrinsic(intrinsic, method, sig, mustExpand);
595 case InstructionSet_SSE42:
596 return impSSE42Intrinsic(intrinsic, method, sig, mustExpand);
597 case InstructionSet_AVX:
598 return impAVXIntrinsic(intrinsic, method, sig, mustExpand);
599 case InstructionSet_AVX2:
600 return impAVX2Intrinsic(intrinsic, method, sig, mustExpand);
602 case InstructionSet_AES:
603 return impAESIntrinsic(intrinsic, method, sig, mustExpand);
604 case InstructionSet_BMI1:
605 return impBMI1Intrinsic(intrinsic, method, sig, mustExpand);
606 case InstructionSet_BMI2:
607 return impBMI2Intrinsic(intrinsic, method, sig, mustExpand);
608 case InstructionSet_FMA:
609 return impFMAIntrinsic(intrinsic, method, sig, mustExpand);
610 case InstructionSet_LZCNT:
611 return impLZCNTIntrinsic(intrinsic, method, sig, mustExpand);
612 case InstructionSet_PCLMULQDQ:
613 return impPCLMULQDQIntrinsic(intrinsic, method, sig, mustExpand);
614 case InstructionSet_POPCNT:
615 return impPOPCNTIntrinsic(intrinsic, method, sig, mustExpand);
621 CORINFO_CLASS_HANDLE Compiler::gtGetStructHandleForHWSIMD(var_types simdType, var_types simdBaseType)
623 if (simdType == TYP_SIMD16)
625 switch (simdBaseType)
628 return Vector128FloatHandle;
630 return Vector128DoubleHandle;
632 return Vector128IntHandle;
634 return Vector128UShortHandle;
636 return Vector128UByteHandle;
638 return Vector128ShortHandle;
640 return Vector128ByteHandle;
642 return Vector128LongHandle;
644 return Vector128UIntHandle;
646 return Vector128ULongHandle;
648 assert(!"Didn't find a class handle for simdType");
651 else if (simdType == TYP_SIMD32)
653 switch (simdBaseType)
656 return Vector256FloatHandle;
658 return Vector256DoubleHandle;
660 return Vector256IntHandle;
662 return Vector256UShortHandle;
664 return Vector256UByteHandle;
666 return Vector256ShortHandle;
668 return Vector256ByteHandle;
670 return Vector256LongHandle;
672 return Vector256UIntHandle;
674 return Vector256ULongHandle;
676 assert(!"Didn't find a class handle for simdType");
680 return NO_CLASS_HANDLE;
683 GenTree* Compiler::impSSEIntrinsic(NamedIntrinsic intrinsic,
684 CORINFO_METHOD_HANDLE method,
685 CORINFO_SIG_INFO* sig,
688 GenTree* retNode = nullptr;
689 GenTree* op1 = nullptr;
690 GenTree* op2 = nullptr;
691 GenTree* op3 = nullptr;
692 GenTree* op4 = nullptr;
696 case NI_SSE_SetVector128:
698 assert(sig->numArgs == 4);
699 assert(getBaseTypeOfSIMDType(sig->retTypeSigClass) == TYP_FLOAT);
701 op4 = impPopStack().val;
702 op3 = impPopStack().val;
703 op2 = impPopStack().val;
704 op1 = impPopStack().val;
706 GenTree* left = gtNewSimdHWIntrinsicNode(TYP_SIMD16, op4, op3, NI_SSE_UnpackLow, TYP_FLOAT, 16);
707 GenTree* right = gtNewSimdHWIntrinsicNode(TYP_SIMD16, op2, op1, NI_SSE_UnpackLow, TYP_FLOAT, 16);
708 GenTree* control = gtNewIconNode(68, TYP_UBYTE);
710 retNode = gtNewSimdHWIntrinsicNode(TYP_SIMD16, left, right, control, NI_SSE_Shuffle, TYP_FLOAT, 16);
716 assert(sig->numArgs == 3);
717 assert(getBaseTypeOfSIMDType(sig->retTypeSigClass) == TYP_FLOAT);
719 op3 = impStackTop().val;
721 if (op3->IsCnsIntOrI() || mustExpand)
723 impPopStack(); // Pop the value we peeked at
724 op2 = impSIMDPopStack(TYP_SIMD16);
725 op1 = impSIMDPopStack(TYP_SIMD16);
726 retNode = gtNewSimdHWIntrinsicNode(TYP_SIMD16, op1, op2, op3, intrinsic, TYP_FLOAT, 16);
730 // When op3 is not a constant and we are not being forced to expand, we need to
731 // return nullptr so a GT_CALL to the intrinsic method is emitted instead. The
732 // intrinsic method is recursive and will be forced to expand, at which point
733 // we emit some less efficient fallback code.
741 case NI_SSE_AddScalar:
744 case NI_SSE_CompareEqual:
745 case NI_SSE_CompareEqualScalar:
746 case NI_SSE_CompareGreaterThan:
747 case NI_SSE_CompareGreaterThanScalar:
748 case NI_SSE_CompareGreaterThanOrEqual:
749 case NI_SSE_CompareGreaterThanOrEqualScalar:
750 case NI_SSE_CompareLessThan:
751 case NI_SSE_CompareLessThanScalar:
752 case NI_SSE_CompareLessThanOrEqual:
753 case NI_SSE_CompareLessThanOrEqualScalar:
754 case NI_SSE_CompareNotEqual:
755 case NI_SSE_CompareNotEqualScalar:
756 case NI_SSE_CompareNotGreaterThan:
757 case NI_SSE_CompareNotGreaterThanScalar:
758 case NI_SSE_CompareNotGreaterThanOrEqual:
759 case NI_SSE_CompareNotGreaterThanOrEqualScalar:
760 case NI_SSE_CompareNotLessThan:
761 case NI_SSE_CompareNotLessThanScalar:
762 case NI_SSE_CompareNotLessThanOrEqual:
763 case NI_SSE_CompareNotLessThanOrEqualScalar:
764 case NI_SSE_CompareOrdered:
765 case NI_SSE_CompareOrderedScalar:
766 case NI_SSE_CompareUnordered:
767 case NI_SSE_CompareUnorderedScalar:
769 case NI_SSE_DivideScalar:
771 case NI_SSE_MaxScalar:
773 case NI_SSE_MinScalar:
774 case NI_SSE_MoveHighToLow:
775 case NI_SSE_MoveLowToHigh:
776 case NI_SSE_MoveScalar:
777 case NI_SSE_Multiply:
778 case NI_SSE_MultiplyScalar:
780 case NI_SSE_Subtract:
781 case NI_SSE_SubtractScalar:
782 case NI_SSE_UnpackHigh:
783 case NI_SSE_UnpackLow:
785 assert(sig->numArgs == 2);
786 assert(getBaseTypeOfSIMDType(sig->retTypeSigClass) == TYP_FLOAT);
787 op2 = impSIMDPopStack(TYP_SIMD16);
788 op1 = impSIMDPopStack(TYP_SIMD16);
789 retNode = gtNewSimdHWIntrinsicNode(TYP_SIMD16, op1, op2, intrinsic, TYP_FLOAT, 16);
792 case NI_SSE_CompareEqualOrderedScalar:
793 case NI_SSE_CompareEqualUnorderedScalar:
794 case NI_SSE_CompareGreaterThanOrderedScalar:
795 case NI_SSE_CompareGreaterThanUnorderedScalar:
796 case NI_SSE_CompareGreaterThanOrEqualOrderedScalar:
797 case NI_SSE_CompareGreaterThanOrEqualUnorderedScalar:
798 case NI_SSE_CompareLessThanOrderedScalar:
799 case NI_SSE_CompareLessThanUnorderedScalar:
800 case NI_SSE_CompareLessThanOrEqualOrderedScalar:
801 case NI_SSE_CompareLessThanOrEqualUnorderedScalar:
802 case NI_SSE_CompareNotEqualOrderedScalar:
803 case NI_SSE_CompareNotEqualUnorderedScalar:
804 assert(sig->numArgs == 2);
805 assert(JITtype2varType(sig->retType) == TYP_BOOL);
806 assert(getBaseTypeOfSIMDType(info.compCompHnd->getArgClass(sig, sig->args)) == TYP_FLOAT);
807 op2 = impSIMDPopStack(TYP_SIMD16);
808 op1 = impSIMDPopStack(TYP_SIMD16);
809 retNode = gtNewSimdHWIntrinsicNode(TYP_BOOL, op1, op2, intrinsic, TYP_FLOAT, 16);
812 case NI_SSE_ConvertToVector128SingleScalar:
814 assert(sig->numArgs == 2);
815 assert(getBaseTypeOfSIMDType(sig->retTypeSigClass) == TYP_FLOAT);
818 CORINFO_CLASS_HANDLE argClass;
820 CORINFO_ARG_LIST_HANDLE argLst = info.compCompHnd->getArgNext(sig->args);
821 CorInfoType corType =
822 strip(info.compCompHnd->getArgType(sig, argLst, &argClass)); // type of the second argument
824 if (varTypeIsLong(JITtype2varType(corType)))
826 return impUnsupportedHWIntrinsic(CORINFO_HELP_THROW_PLATFORM_NOT_SUPPORTED, method, sig, mustExpand);
828 #endif // _TARGET_X86_
830 op2 = impPopStack().val;
831 op1 = impSIMDPopStack(TYP_SIMD16);
832 retNode = gtNewSimdHWIntrinsicNode(TYP_SIMD16, op1, op2, intrinsic, TYP_FLOAT, 16);
836 case NI_SSE_LoadHigh:
839 assert(sig->numArgs == 2);
840 assert(getBaseTypeOfSIMDType(sig->retTypeSigClass) == TYP_FLOAT);
841 op2 = impPopStack().val;
842 op1 = impSIMDPopStack(TYP_SIMD16);
843 retNode = gtNewSimdHWIntrinsicNode(TYP_SIMD16, op1, op2, intrinsic, TYP_FLOAT, 16);
847 case NI_SSE_MoveMask:
848 assert(sig->numArgs == 1);
849 assert(JITtype2varType(sig->retType) == TYP_INT);
850 assert(getBaseTypeOfSIMDType(info.compCompHnd->getArgClass(sig, sig->args)) == TYP_FLOAT);
851 op1 = impSIMDPopStack(TYP_SIMD16);
852 retNode = gtNewSimdHWIntrinsicNode(TYP_INT, op1, intrinsic, TYP_FLOAT, 16);
855 case NI_SSE_StaticCast:
857 assert(sig->numArgs == 1);
858 var_types tgtType = getBaseTypeOfSIMDType(sig->retTypeSigClass);
859 var_types srcType = getBaseTypeOfSIMDType(info.compCompHnd->getArgClass(sig, sig->args));
861 if (varTypeIsArithmetic(tgtType) && varTypeIsArithmetic(srcType))
863 op1 = impSIMDPopStack(TYP_SIMD16);
864 retNode = gtNewSimdHWIntrinsicNode(TYP_SIMD16, op1, intrinsic, tgtType, 16);
868 return impUnsupportedHWIntrinsic(CORINFO_HELP_THROW_PLATFORM_NOT_SUPPORTED, method, sig, mustExpand);
873 case NI_SSE_LoadAlignedVector128:
874 case NI_SSE_LoadScalar:
875 case NI_SSE_LoadVector128:
876 case NI_SSE_SetAllVector128:
877 case NI_SSE_SetScalar:
878 assert(sig->numArgs == 1);
879 assert(getBaseTypeOfSIMDType(sig->retTypeSigClass) == TYP_FLOAT);
880 op1 = impPopStack().val;
881 retNode = gtNewSimdHWIntrinsicNode(TYP_SIMD16, op1, intrinsic, TYP_FLOAT, 16);
884 case NI_SSE_Reciprocal:
885 case NI_SSE_ReciprocalScalar:
886 case NI_SSE_ReciprocalSqrt:
887 case NI_SSE_ReciprocalSqrtScalar:
889 case NI_SSE_SqrtScalar:
890 assert(sig->numArgs == 1);
891 assert(getBaseTypeOfSIMDType(sig->retTypeSigClass) == TYP_FLOAT);
892 op1 = impSIMDPopStack(TYP_SIMD16);
893 retNode = gtNewSimdHWIntrinsicNode(TYP_SIMD16, op1, intrinsic, TYP_FLOAT, 16);
896 case NI_SSE_ConvertToInt32:
897 case NI_SSE_ConvertToInt32WithTruncation:
898 case NI_SSE_ConvertToInt64:
899 case NI_SSE_ConvertToInt64WithTruncation:
900 case NI_SSE_ConvertToSingle:
902 assert(sig->numArgs == 1);
903 assert(getBaseTypeOfSIMDType(info.compCompHnd->getArgClass(sig, sig->args)) == TYP_FLOAT);
904 var_types callType = JITtype2varType(sig->retType);
907 if (varTypeIsLong(callType))
909 assert(intrinsic == NI_SSE_ConvertToInt64 || intrinsic == NI_SSE_ConvertToInt64WithTruncation);
910 return impUnsupportedHWIntrinsic(CORINFO_HELP_THROW_PLATFORM_NOT_SUPPORTED, method, sig, mustExpand);
912 #endif // _TARGET_X86_
914 op1 = impSIMDPopStack(TYP_SIMD16);
915 retNode = gtNewSimdHWIntrinsicNode(callType, op1, intrinsic, TYP_FLOAT, 16);
919 case NI_SSE_SetZeroVector128:
920 assert(sig->numArgs == 0);
921 assert(getBaseTypeOfSIMDType(sig->retTypeSigClass) == TYP_FLOAT);
922 retNode = gtNewSimdHWIntrinsicNode(TYP_SIMD16, intrinsic, TYP_FLOAT, 16);
926 JITDUMP("Not implemented hardware intrinsic");
932 GenTree* Compiler::impSSE2Intrinsic(NamedIntrinsic intrinsic,
933 CORINFO_METHOD_HANDLE method,
934 CORINFO_SIG_INFO* sig,
937 GenTree* retNode = nullptr;
938 GenTree* op1 = nullptr;
939 GenTree* op2 = nullptr;
940 var_types baseType = TYP_UNKNOWN;
944 assert(sig->numArgs == 2);
945 op2 = impSIMDPopStack(TYP_SIMD16);
946 op1 = impSIMDPopStack(TYP_SIMD16);
947 baseType = getBaseTypeOfSIMDType(sig->retTypeSigClass);
948 retNode = gtNewSimdHWIntrinsicNode(TYP_SIMD16, op1, op2, NI_SSE2_Add, baseType, 16);
952 JITDUMP("Not implemented hardware intrinsic");
958 GenTree* Compiler::impSSE3Intrinsic(NamedIntrinsic intrinsic,
959 CORINFO_METHOD_HANDLE method,
960 CORINFO_SIG_INFO* sig,
966 GenTree* Compiler::impSSSE3Intrinsic(NamedIntrinsic intrinsic,
967 CORINFO_METHOD_HANDLE method,
968 CORINFO_SIG_INFO* sig,
974 GenTree* Compiler::impSSE41Intrinsic(NamedIntrinsic intrinsic,
975 CORINFO_METHOD_HANDLE method,
976 CORINFO_SIG_INFO* sig,
982 GenTree* Compiler::impSSE42Intrinsic(NamedIntrinsic intrinsic,
983 CORINFO_METHOD_HANDLE method,
984 CORINFO_SIG_INFO* sig,
987 GenTree* retNode = nullptr;
988 GenTree* op1 = nullptr;
989 GenTree* op2 = nullptr;
990 var_types callType = JITtype2varType(sig->retType);
992 CORINFO_ARG_LIST_HANDLE argLst = sig->args;
993 CORINFO_CLASS_HANDLE argClass;
998 assert(sig->numArgs == 2);
1001 if (varTypeIsLong(callType))
1003 return impUnsupportedHWIntrinsic(CORINFO_HELP_THROW_PLATFORM_NOT_SUPPORTED, method, sig, mustExpand);
1007 op2 = impPopStack().val;
1008 op1 = impPopStack().val;
1010 argLst = info.compCompHnd->getArgNext(argLst); // the second argument
1011 corType = strip(info.compCompHnd->getArgType(sig, argLst, &argClass)); // type of the second argument
1013 retNode = gtNewScalarHWIntrinsicNode(callType, op1, op2, NI_SSE42_Crc32);
1015 // TODO - currently we use the BaseType to bring the type of the second argument
1016 // to the code generator. May encode the overload info in other way.
1017 retNode->gtHWIntrinsic.gtSIMDBaseType = JITtype2varType(corType);
1021 JITDUMP("Not implemented hardware intrinsic");
1027 GenTree* Compiler::impAVXIntrinsic(NamedIntrinsic intrinsic,
1028 CORINFO_METHOD_HANDLE method,
1029 CORINFO_SIG_INFO* sig,
1032 GenTree* retNode = nullptr;
1033 GenTree* op1 = nullptr;
1034 GenTree* op2 = nullptr;
1035 var_types baseType = TYP_UNKNOWN;
1039 assert(sig->numArgs == 2);
1040 op2 = impSIMDPopStack(TYP_SIMD32);
1041 op1 = impSIMDPopStack(TYP_SIMD32);
1042 baseType = getBaseTypeOfSIMDType(sig->retTypeSigClass);
1043 retNode = gtNewSimdHWIntrinsicNode(TYP_SIMD32, op1, op2, NI_AVX_Add, baseType, 32);
1047 JITDUMP("Not implemented hardware intrinsic");
1053 GenTree* Compiler::impAVX2Intrinsic(NamedIntrinsic intrinsic,
1054 CORINFO_METHOD_HANDLE method,
1055 CORINFO_SIG_INFO* sig,
1058 GenTree* retNode = nullptr;
1059 GenTree* op1 = nullptr;
1060 GenTree* op2 = nullptr;
1061 var_types baseType = TYP_UNKNOWN;
1065 assert(sig->numArgs == 2);
1066 op2 = impSIMDPopStack(TYP_SIMD32);
1067 op1 = impSIMDPopStack(TYP_SIMD32);
1068 baseType = getBaseTypeOfSIMDType(sig->retTypeSigClass);
1069 retNode = gtNewSimdHWIntrinsicNode(TYP_SIMD32, op1, op2, NI_AVX2_Add, baseType, 32);
1073 JITDUMP("Not implemented hardware intrinsic");
1079 GenTree* Compiler::impAESIntrinsic(NamedIntrinsic intrinsic,
1080 CORINFO_METHOD_HANDLE method,
1081 CORINFO_SIG_INFO* sig,
1087 GenTree* Compiler::impBMI1Intrinsic(NamedIntrinsic intrinsic,
1088 CORINFO_METHOD_HANDLE method,
1089 CORINFO_SIG_INFO* sig,
1095 GenTree* Compiler::impBMI2Intrinsic(NamedIntrinsic intrinsic,
1096 CORINFO_METHOD_HANDLE method,
1097 CORINFO_SIG_INFO* sig,
1103 GenTree* Compiler::impFMAIntrinsic(NamedIntrinsic intrinsic,
1104 CORINFO_METHOD_HANDLE method,
1105 CORINFO_SIG_INFO* sig,
1111 GenTree* Compiler::impLZCNTIntrinsic(NamedIntrinsic intrinsic,
1112 CORINFO_METHOD_HANDLE method,
1113 CORINFO_SIG_INFO* sig,
1116 assert(sig->numArgs == 1);
1117 var_types callType = JITtype2varType(sig->retType);
1120 if (varTypeIsLong(callType))
1122 return impUnsupportedHWIntrinsic(CORINFO_HELP_THROW_PLATFORM_NOT_SUPPORTED, method, sig, mustExpand);
1126 return gtNewScalarHWIntrinsicNode(callType, impPopStack().val, NI_LZCNT_LeadingZeroCount);
1129 GenTree* Compiler::impPCLMULQDQIntrinsic(NamedIntrinsic intrinsic,
1130 CORINFO_METHOD_HANDLE method,
1131 CORINFO_SIG_INFO* sig,
1137 GenTree* Compiler::impPOPCNTIntrinsic(NamedIntrinsic intrinsic,
1138 CORINFO_METHOD_HANDLE method,
1139 CORINFO_SIG_INFO* sig,
1142 assert(sig->numArgs == 1);
1143 var_types callType = JITtype2varType(sig->retType);
1146 if (varTypeIsLong(callType))
1148 return impUnsupportedHWIntrinsic(CORINFO_HELP_THROW_PLATFORM_NOT_SUPPORTED, method, sig, mustExpand);
1152 return gtNewScalarHWIntrinsicNode(callType, impPopStack().val, NI_POPCNT_PopCount);
1155 #endif // FEATURE_HW_INTRINSICS