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 static const bool isNumericType(var_types type)
47 //------------------------------------------------------------------------
48 // lookupHWIntrinsicISA: map class name to InstructionSet value
51 // className -- class name in System.Runtime.Intrinsics.X86
54 // Id for the ISA class.
56 InstructionSet Compiler::lookupHWIntrinsicISA(const char* className)
58 if (className != nullptr)
60 if (className[0] == 'A')
62 if (strcmp(className, "Aes") == 0)
64 return InstructionSet_AES;
66 else if (strcmp(className, "Avx") == 0)
68 return InstructionSet_AVX;
70 else if (strcmp(className, "Avx2") == 0)
72 return InstructionSet_AVX2;
75 if (className[0] == 'S')
77 if (strcmp(className, "Sse") == 0)
79 return InstructionSet_SSE;
81 else if (strcmp(className, "Sse2") == 0)
83 return InstructionSet_SSE2;
85 else if (strcmp(className, "Sse3") == 0)
87 return InstructionSet_SSE3;
89 else if (strcmp(className, "Ssse3") == 0)
91 return InstructionSet_SSSE3;
93 else if (strcmp(className, "Sse41") == 0)
95 return InstructionSet_SSE41;
97 else if (strcmp(className, "Sse42") == 0)
99 return InstructionSet_SSE42;
103 if (strcmp(className, "Bmi1") == 0)
105 return InstructionSet_BMI1;
107 else if (strcmp(className, "Bmi2") == 0)
109 return InstructionSet_BMI2;
111 else if (strcmp(className, "Fma") == 0)
113 return InstructionSet_FMA;
115 else if (strcmp(className, "Lzcnt") == 0)
117 return InstructionSet_LZCNT;
119 else if (strcmp(className, "Pclmulqdq") == 0)
121 return InstructionSet_PCLMULQDQ;
123 else if (strcmp(className, "Popcnt") == 0)
125 return InstructionSet_POPCNT;
129 JITDUMP("Unsupported ISA.\n");
130 return InstructionSet_ILLEGAL;
133 //------------------------------------------------------------------------
134 // lookupHWIntrinsic: map intrinsic name to named intrinsic value
137 // methodName -- name of the intrinsic function.
138 // isa -- instruction set of the intrinsic.
141 // Id for the hardware intrinsic.
143 // TODO-Throughput: replace sequential search by binary search
144 NamedIntrinsic Compiler::lookupHWIntrinsic(const char* methodName, InstructionSet isa)
146 NamedIntrinsic result = NI_Illegal;
147 if (isa != InstructionSet_ILLEGAL)
149 for (int i = 0; i < NI_HW_INTRINSIC_END - NI_HW_INTRINSIC_START; i++)
151 if (isa == hwIntrinsicInfoArray[i].isa && strcmp(methodName, hwIntrinsicInfoArray[i].intrinsicName) == 0)
153 result = hwIntrinsicInfoArray[i].intrinsicID;
160 //------------------------------------------------------------------------
161 // isaOfHWIntrinsic: map named intrinsic value to its instruction set
164 // intrinsic -- id of the intrinsic function.
167 // instruction set of the intrinsic.
169 InstructionSet Compiler::isaOfHWIntrinsic(NamedIntrinsic intrinsic)
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;
176 //------------------------------------------------------------------------
177 // isIntrinsicAnIsSupportedPropertyGetter: return true if the intrinsic is "get_IsSupported"
180 // intrinsic -- id of the intrinsic function.
183 // true if the intrinsic is "get_IsSupported"
184 // Sometimes we need to specially treat "get_IsSupported"
185 bool Compiler::isIntrinsicAnIsSupportedPropertyGetter(NamedIntrinsic intrinsic)
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:
210 //------------------------------------------------------------------------
211 // isFullyImplmentedISAClass: return true if all the hardware intrinsics
212 // of this ISA are implemented in RyuJIT.
215 // isa - Instruction set
217 // true - all the hardware intrinsics of "isa" are implemented in RyuJIT.
219 bool Compiler::isFullyImplmentedISAClass(InstructionSet isa)
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:
238 case InstructionSet_LZCNT:
239 case InstructionSet_POPCNT:
247 //------------------------------------------------------------------------
251 // isa - Instruction set
253 // true - if "isa" only contains scalar instructions
255 bool Compiler::isScalarISA(InstructionSet isa)
259 case InstructionSet_BMI1:
260 case InstructionSet_BMI2:
261 case InstructionSet_LZCNT:
262 case InstructionSet_POPCNT:
270 //------------------------------------------------------------------------
271 // compSupportsHWIntrinsic: compiler support of hardware intrinsics
274 // isa - Instruction set
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)
282 return (featureSIMD || isScalarISA(isa)) && (
284 JitConfig.EnableIncompleteISAClass() ||
286 isFullyImplmentedISAClass(isa));
289 //------------------------------------------------------------------------
290 // impUnsupportedHWIntrinsic: returns a node for an unsupported HWIntrinsic
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
299 // a gtNewMustThrowException if mustExpand is true; otherwise, nullptr
301 GenTree* Compiler::impUnsupportedHWIntrinsic(unsigned helper,
302 CORINFO_METHOD_HANDLE method,
303 CORINFO_SIG_INFO* sig,
306 // We've hit some error case and may need to return a node for the given error.
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
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.
320 for (unsigned i = 0; i < sig->numArgs; i++)
325 return gtNewMustThrowException(helper, JITtype2varType(sig->retType), sig->retTypeClass);
333 //------------------------------------------------------------------------
334 // impX86HWIntrinsic: dispatch hardware intrinsics to their own implementation
338 // intrinsic -- id of the intrinsic function.
339 // method -- method handle of the intrinsic function.
340 // sig -- signature of the intrinsic call
343 // the expanded intrinsic.
345 GenTree* Compiler::impX86HWIntrinsic(NamedIntrinsic intrinsic,
346 CORINFO_METHOD_HANDLE method,
347 CORINFO_SIG_INFO* sig,
350 InstructionSet isa = isaOfHWIntrinsic(intrinsic);
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);
357 if (isIntrinsicAnIsSupportedPropertyGetter(intrinsic))
359 return gtNewIconNode(issupported);
361 else if (!issupported)
363 return impUnsupportedHWIntrinsic(CORINFO_HELP_THROW_PLATFORM_NOT_SUPPORTED, method, sig, mustExpand);
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);
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);
404 CORINFO_CLASS_HANDLE Compiler::gtGetStructHandleForHWSIMD(var_types simdType, var_types simdBaseType)
406 if (simdType == TYP_SIMD16)
408 switch (simdBaseType)
411 return Vector128FloatHandle;
413 return Vector128DoubleHandle;
415 return Vector128IntHandle;
417 return Vector128UShortHandle;
419 return Vector128UByteHandle;
421 return Vector128ShortHandle;
423 return Vector128ByteHandle;
425 return Vector128LongHandle;
427 return Vector128UIntHandle;
429 return Vector128ULongHandle;
431 assert(!"Didn't find a class handle for simdType");
434 else if (simdType == TYP_SIMD32)
436 switch (simdBaseType)
439 return Vector256FloatHandle;
441 return Vector256DoubleHandle;
443 return Vector256IntHandle;
445 return Vector256UShortHandle;
447 return Vector256UByteHandle;
449 return Vector256ShortHandle;
451 return Vector256ByteHandle;
453 return Vector256LongHandle;
455 return Vector256UIntHandle;
457 return Vector256ULongHandle;
459 assert(!"Didn't find a class handle for simdType");
463 return NO_CLASS_HANDLE;
466 GenTree* Compiler::impSSEIntrinsic(NamedIntrinsic intrinsic,
467 CORINFO_METHOD_HANDLE method,
468 CORINFO_SIG_INFO* sig,
471 GenTree* retNode = nullptr;
472 GenTree* op1 = nullptr;
473 GenTree* op2 = nullptr;
474 GenTree* op3 = nullptr;
475 GenTree* op4 = nullptr;
479 case NI_SSE_SetVector128:
481 assert(sig->numArgs == 4);
482 assert(getBaseTypeOfSIMDType(sig->retTypeSigClass) == TYP_FLOAT);
484 op4 = impPopStack().val;
485 op3 = impPopStack().val;
486 op2 = impPopStack().val;
487 op1 = impPopStack().val;
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);
493 retNode = gtNewSimdHWIntrinsicNode(TYP_SIMD16, left, right, control, NI_SSE_Shuffle, TYP_FLOAT, 16);
499 assert(sig->numArgs == 3);
500 assert(getBaseTypeOfSIMDType(sig->retTypeSigClass) == TYP_FLOAT);
502 op3 = impStackTop().val;
504 if (op3->IsCnsIntOrI() || mustExpand)
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);
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.
524 case NI_SSE_AddScalar:
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:
552 case NI_SSE_DivideScalar:
554 case NI_SSE_MaxScalar:
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:
563 case NI_SSE_Subtract:
564 case NI_SSE_SubtractScalar:
565 case NI_SSE_UnpackHigh:
566 case NI_SSE_UnpackLow:
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);
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);
595 case NI_SSE_ConvertToVector128SingleScalar:
597 assert(sig->numArgs == 2);
598 assert(getBaseTypeOfSIMDType(sig->retTypeSigClass) == TYP_FLOAT);
601 CORINFO_CLASS_HANDLE argClass;
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
607 if (varTypeIsLong(JITtype2varType(corType)))
609 return impUnsupportedHWIntrinsic(CORINFO_HELP_THROW_PLATFORM_NOT_SUPPORTED, method, sig, mustExpand);
611 #endif // _TARGET_X86_
613 op2 = impPopStack().val;
614 op1 = impSIMDPopStack(TYP_SIMD16);
615 retNode = gtNewSimdHWIntrinsicNode(TYP_SIMD16, op1, op2, intrinsic, TYP_FLOAT, 16);
619 case NI_SSE_StaticCast:
621 assert(sig->numArgs == 1);
622 var_types tgtType = getBaseTypeOfSIMDType(sig->retTypeSigClass);
623 var_types srcType = getBaseTypeOfSIMDType(info.compCompHnd->getArgClass(sig, sig->args));
625 if (isNumericType(tgtType) && isNumericType(srcType))
627 op1 = impSIMDPopStack(TYP_SIMD16);
628 retNode = gtNewSimdHWIntrinsicNode(TYP_SIMD16, op1, intrinsic, tgtType, 16);
632 return impUnsupportedHWIntrinsic(CORINFO_HELP_THROW_PLATFORM_NOT_SUPPORTED, method, sig, mustExpand);
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);
645 case NI_SSE_Reciprocal:
646 case NI_SSE_ReciprocalScalar:
647 case NI_SSE_ReciprocalSqrt:
648 case NI_SSE_ReciprocalSqrtScalar:
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);
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:
663 assert(sig->numArgs == 1);
664 assert(getBaseTypeOfSIMDType(info.compCompHnd->getArgClass(sig, sig->args)) == TYP_FLOAT);
665 var_types callType = JITtype2varType(sig->retType);
668 if (varTypeIsLong(callType))
670 assert(intrinsic == NI_SSE_ConvertToInt64 || intrinsic == NI_SSE_ConvertToInt64WithTruncation);
671 return impUnsupportedHWIntrinsic(CORINFO_HELP_THROW_PLATFORM_NOT_SUPPORTED, method, sig, mustExpand);
673 #endif // _TARGET_X86_
675 op1 = impSIMDPopStack(TYP_SIMD16);
676 retNode = gtNewSimdHWIntrinsicNode(callType, op1, intrinsic, TYP_FLOAT, 16);
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);
687 JITDUMP("Not implemented hardware intrinsic");
693 GenTree* Compiler::impSSE2Intrinsic(NamedIntrinsic intrinsic,
694 CORINFO_METHOD_HANDLE method,
695 CORINFO_SIG_INFO* sig,
698 GenTree* retNode = nullptr;
699 GenTree* op1 = nullptr;
700 GenTree* op2 = nullptr;
701 var_types baseType = TYP_UNKNOWN;
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);
713 JITDUMP("Not implemented hardware intrinsic");
719 GenTree* Compiler::impSSE3Intrinsic(NamedIntrinsic intrinsic,
720 CORINFO_METHOD_HANDLE method,
721 CORINFO_SIG_INFO* sig,
727 GenTree* Compiler::impSSSE3Intrinsic(NamedIntrinsic intrinsic,
728 CORINFO_METHOD_HANDLE method,
729 CORINFO_SIG_INFO* sig,
735 GenTree* Compiler::impSSE41Intrinsic(NamedIntrinsic intrinsic,
736 CORINFO_METHOD_HANDLE method,
737 CORINFO_SIG_INFO* sig,
743 GenTree* Compiler::impSSE42Intrinsic(NamedIntrinsic intrinsic,
744 CORINFO_METHOD_HANDLE method,
745 CORINFO_SIG_INFO* sig,
748 GenTree* retNode = nullptr;
749 GenTree* op1 = nullptr;
750 GenTree* op2 = nullptr;
751 var_types callType = JITtype2varType(sig->retType);
753 CORINFO_ARG_LIST_HANDLE argLst = sig->args;
754 CORINFO_CLASS_HANDLE argClass;
759 assert(sig->numArgs == 2);
762 if (varTypeIsLong(callType))
764 return impUnsupportedHWIntrinsic(CORINFO_HELP_THROW_PLATFORM_NOT_SUPPORTED, method, sig, mustExpand);
768 op2 = impPopStack().val;
769 op1 = impPopStack().val;
771 argLst = info.compCompHnd->getArgNext(argLst); // the second argument
772 corType = strip(info.compCompHnd->getArgType(sig, argLst, &argClass)); // type of the second argument
774 retNode = gtNewScalarHWIntrinsicNode(callType, op1, op2, NI_SSE42_Crc32);
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);
782 JITDUMP("Not implemented hardware intrinsic");
788 GenTree* Compiler::impAVXIntrinsic(NamedIntrinsic intrinsic,
789 CORINFO_METHOD_HANDLE method,
790 CORINFO_SIG_INFO* sig,
793 GenTree* retNode = nullptr;
794 GenTree* op1 = nullptr;
795 GenTree* op2 = nullptr;
796 var_types baseType = TYP_UNKNOWN;
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);
808 JITDUMP("Not implemented hardware intrinsic");
814 GenTree* Compiler::impAVX2Intrinsic(NamedIntrinsic intrinsic,
815 CORINFO_METHOD_HANDLE method,
816 CORINFO_SIG_INFO* sig,
819 GenTree* retNode = nullptr;
820 GenTree* op1 = nullptr;
821 GenTree* op2 = nullptr;
822 var_types baseType = TYP_UNKNOWN;
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);
834 JITDUMP("Not implemented hardware intrinsic");
840 GenTree* Compiler::impAESIntrinsic(NamedIntrinsic intrinsic,
841 CORINFO_METHOD_HANDLE method,
842 CORINFO_SIG_INFO* sig,
848 GenTree* Compiler::impBMI1Intrinsic(NamedIntrinsic intrinsic,
849 CORINFO_METHOD_HANDLE method,
850 CORINFO_SIG_INFO* sig,
856 GenTree* Compiler::impBMI2Intrinsic(NamedIntrinsic intrinsic,
857 CORINFO_METHOD_HANDLE method,
858 CORINFO_SIG_INFO* sig,
864 GenTree* Compiler::impFMAIntrinsic(NamedIntrinsic intrinsic,
865 CORINFO_METHOD_HANDLE method,
866 CORINFO_SIG_INFO* sig,
872 GenTree* Compiler::impLZCNTIntrinsic(NamedIntrinsic intrinsic,
873 CORINFO_METHOD_HANDLE method,
874 CORINFO_SIG_INFO* sig,
877 assert(sig->numArgs == 1);
878 var_types callType = JITtype2varType(sig->retType);
881 if (varTypeIsLong(callType))
883 return impUnsupportedHWIntrinsic(CORINFO_HELP_THROW_PLATFORM_NOT_SUPPORTED, method, sig, mustExpand);
887 return gtNewScalarHWIntrinsicNode(callType, impPopStack().val, NI_LZCNT_LeadingZeroCount);
890 GenTree* Compiler::impPCLMULQDQIntrinsic(NamedIntrinsic intrinsic,
891 CORINFO_METHOD_HANDLE method,
892 CORINFO_SIG_INFO* sig,
898 GenTree* Compiler::impPOPCNTIntrinsic(NamedIntrinsic intrinsic,
899 CORINFO_METHOD_HANDLE method,
900 CORINFO_SIG_INFO* sig,
903 assert(sig->numArgs == 1);
904 var_types callType = JITtype2varType(sig->retType);
907 if (varTypeIsLong(callType))
909 return impUnsupportedHWIntrinsic(CORINFO_HELP_THROW_PLATFORM_NOT_SUPPORTED, method, sig, mustExpand);
913 return gtNewScalarHWIntrinsicNode(callType, impPopStack().val, NI_POPCNT_PopCount);
916 #endif // FEATURE_HW_INTRINSICS