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 // isIntrinsicAnIsSupportedPropertyGetter: return true if the intrinsic is "get_IsSupported"
159 // intrinsic -- id of the intrinsic function.
162 // true if the intrinsic is "get_IsSupported"
163 // Sometimes we need to specially treat "get_IsSupported"
164 bool Compiler::isIntrinsicAnIsSupportedPropertyGetter(NamedIntrinsic intrinsic)
168 case NI_SSE_IsSupported:
169 case NI_SSE2_IsSupported:
170 case NI_SSE3_IsSupported:
171 case NI_SSSE3_IsSupported:
172 case NI_SSE41_IsSupported:
173 case NI_SSE42_IsSupported:
174 case NI_AVX_IsSupported:
175 case NI_AVX2_IsSupported:
176 case NI_AES_IsSupported:
177 case NI_BMI1_IsSupported:
178 case NI_BMI2_IsSupported:
179 case NI_FMA_IsSupported:
180 case NI_LZCNT_IsSupported:
181 case NI_PCLMULQDQ_IsSupported:
182 case NI_POPCNT_IsSupported:
189 //------------------------------------------------------------------------
190 // impX86HWIntrinsic: dispatch hardware intrinsics to their own implementation
194 // intrinsic -- id of the intrinsic function.
195 // method -- method handle of the intrinsic function.
196 // sig -- signature of the intrinsic call
199 // the expanded intrinsic.
201 GenTree* Compiler::impX86HWIntrinsic(NamedIntrinsic intrinsic, CORINFO_METHOD_HANDLE method, CORINFO_SIG_INFO* sig)
203 InstructionSet isa = isaOfHWIntrinsic(intrinsic);
204 // Will throw PlatformNotSupportedException if
205 // - calling hardware intrinsics on unsupported hardware
206 // - calling SIMD hardware intrinsics with featureSIMD=false
207 if ((!compSupports(isa) || (!featureSIMD && isa != InstructionSet_BMI1 && isa != InstructionSet_BMI2 &&
208 isa != InstructionSet_LZCNT && isa != InstructionSet_POPCNT)) &&
209 !isIntrinsicAnIsSupportedPropertyGetter(intrinsic))
211 for (unsigned i = 0; i < sig->numArgs; i++)
215 return gtNewMustThrowException(CORINFO_HELP_THROW_PLATFORM_NOT_SUPPORTED, JITtype2varType(sig->retType),
220 case InstructionSet_SSE:
221 return impSSEIntrinsic(intrinsic, method, sig);
222 case InstructionSet_SSE2:
223 return impSSE2Intrinsic(intrinsic, method, sig);
224 case InstructionSet_SSE3:
225 return impSSE3Intrinsic(intrinsic, method, sig);
226 case InstructionSet_SSSE3:
227 return impSSSE3Intrinsic(intrinsic, method, sig);
228 case InstructionSet_SSE41:
229 return impSSE41Intrinsic(intrinsic, method, sig);
230 case InstructionSet_SSE42:
231 return impSSE42Intrinsic(intrinsic, method, sig);
232 case InstructionSet_AVX:
233 return impAVXIntrinsic(intrinsic, method, sig);
234 case InstructionSet_AVX2:
235 return impAVX2Intrinsic(intrinsic, method, sig);
237 case InstructionSet_AES:
238 return impAESIntrinsic(intrinsic, method, sig);
239 case InstructionSet_BMI1:
240 return impBMI1Intrinsic(intrinsic, method, sig);
241 case InstructionSet_BMI2:
242 return impBMI2Intrinsic(intrinsic, method, sig);
243 case InstructionSet_FMA:
244 return impFMAIntrinsic(intrinsic, method, sig);
245 case InstructionSet_LZCNT:
246 return impLZCNTIntrinsic(intrinsic, method, sig);
247 case InstructionSet_PCLMULQDQ:
248 return impPCLMULQDQIntrinsic(intrinsic, method, sig);
249 case InstructionSet_POPCNT:
250 return impPOPCNTIntrinsic(intrinsic, method, sig);
256 CORINFO_CLASS_HANDLE Compiler::gtGetStructHandleForHWSIMD(var_types simdType, var_types simdBaseType)
258 if (simdType == TYP_SIMD16)
260 switch (simdBaseType)
263 return Vector128FloatHandle;
265 return Vector128DoubleHandle;
267 return Vector128IntHandle;
269 return Vector128UShortHandle;
271 return Vector128UByteHandle;
273 return Vector128ShortHandle;
275 return Vector128ByteHandle;
277 return Vector128LongHandle;
279 return Vector128UIntHandle;
281 return Vector128ULongHandle;
283 assert(!"Didn't find a class handle for simdType");
286 else if (simdType == TYP_SIMD32)
288 switch (simdBaseType)
291 return Vector256FloatHandle;
293 return Vector256DoubleHandle;
295 return Vector256IntHandle;
297 return Vector256UShortHandle;
299 return Vector256UByteHandle;
301 return Vector256ShortHandle;
303 return Vector256ByteHandle;
305 return Vector256LongHandle;
307 return Vector256UIntHandle;
309 return Vector256ULongHandle;
311 assert(!"Didn't find a class handle for simdType");
315 return NO_CLASS_HANDLE;
318 GenTree* Compiler::impSSEIntrinsic(NamedIntrinsic intrinsic, CORINFO_METHOD_HANDLE method, CORINFO_SIG_INFO* sig)
320 GenTree* retNode = nullptr;
321 GenTree* op1 = nullptr;
322 GenTree* op2 = nullptr;
325 case NI_SSE_IsSupported:
326 retNode = gtNewIconNode(featureSIMD && compSupports(InstructionSet_SSE));
330 assert(sig->numArgs == 2);
331 op2 = impSIMDPopStack(TYP_SIMD16);
332 op1 = impSIMDPopStack(TYP_SIMD16);
333 retNode = gtNewSimdHWIntrinsicNode(TYP_SIMD16, op1, op2, NI_SSE_Add, TYP_FLOAT, 16);
337 JITDUMP("Not implemented hardware intrinsic");
343 GenTree* Compiler::impSSE2Intrinsic(NamedIntrinsic intrinsic, CORINFO_METHOD_HANDLE method, CORINFO_SIG_INFO* sig)
345 GenTree* retNode = nullptr;
346 GenTree* op1 = nullptr;
347 GenTree* op2 = nullptr;
348 var_types baseType = TYP_UNKNOWN;
351 case NI_SSE2_IsSupported:
352 retNode = gtNewIconNode(featureSIMD && compSupports(InstructionSet_SSE2));
356 assert(sig->numArgs == 2);
357 op2 = impSIMDPopStack(TYP_SIMD16);
358 op1 = impSIMDPopStack(TYP_SIMD16);
359 baseType = getBaseTypeOfSIMDType(sig->retTypeSigClass);
360 retNode = gtNewSimdHWIntrinsicNode(TYP_SIMD16, op1, op2, NI_SSE2_Add, baseType, 16);
364 JITDUMP("Not implemented hardware intrinsic");
370 GenTree* Compiler::impSSE3Intrinsic(NamedIntrinsic intrinsic, CORINFO_METHOD_HANDLE method, CORINFO_SIG_INFO* sig)
374 case NI_SSE3_IsSupported:
375 return gtNewIconNode(featureSIMD && compSupports(InstructionSet_SSE3));
382 GenTree* Compiler::impSSSE3Intrinsic(NamedIntrinsic intrinsic, CORINFO_METHOD_HANDLE method, CORINFO_SIG_INFO* sig)
386 case NI_SSSE3_IsSupported:
387 return gtNewIconNode(featureSIMD && compSupports(InstructionSet_SSSE3));
394 GenTree* Compiler::impSSE41Intrinsic(NamedIntrinsic intrinsic, CORINFO_METHOD_HANDLE method, CORINFO_SIG_INFO* sig)
398 case NI_SSE41_IsSupported:
399 return gtNewIconNode(featureSIMD && compSupports(InstructionSet_SSE41));
406 GenTree* Compiler::impSSE42Intrinsic(NamedIntrinsic intrinsic, CORINFO_METHOD_HANDLE method, CORINFO_SIG_INFO* sig)
408 GenTree* retNode = nullptr;
409 GenTree* op1 = nullptr;
410 GenTree* op2 = nullptr;
411 var_types callType = JITtype2varType(sig->retType);
413 CORINFO_ARG_LIST_HANDLE argLst = sig->args;
414 CORINFO_CLASS_HANDLE argClass;
418 case NI_SSE42_IsSupported:
419 retNode = gtNewIconNode(featureSIMD && compSupports(InstructionSet_SSE42));
423 assert(sig->numArgs == 2);
424 op2 = impPopStack().val;
425 op1 = impPopStack().val;
427 if (varTypeIsLong(callType))
429 return gtNewMustThrowException(CORINFO_HELP_THROW_PLATFORM_NOT_SUPPORTED, callType, sig->retTypeClass);
432 argLst = info.compCompHnd->getArgNext(argLst); // the second argument
433 corType = strip(info.compCompHnd->getArgType(sig, argLst, &argClass)); // type of the second argument
435 retNode = gtNewScalarHWIntrinsicNode(callType, op1, op2, NI_SSE42_Crc32);
437 // TODO - currently we use the BaseType to bring the type of the second argument
438 // to the code generator. May encode the overload info in other way.
439 retNode->gtHWIntrinsic.gtSIMDBaseType = JITtype2varType(corType);
443 JITDUMP("Not implemented hardware intrinsic");
449 GenTree* Compiler::impAVXIntrinsic(NamedIntrinsic intrinsic, CORINFO_METHOD_HANDLE method, CORINFO_SIG_INFO* sig)
451 GenTree* retNode = nullptr;
452 GenTree* op1 = nullptr;
453 GenTree* op2 = nullptr;
454 var_types baseType = TYP_UNKNOWN;
457 case NI_AVX_IsSupported:
458 retNode = gtNewIconNode(featureSIMD && compSupports(InstructionSet_AVX));
462 assert(sig->numArgs == 2);
463 op2 = impSIMDPopStack(TYP_SIMD32);
464 op1 = impSIMDPopStack(TYP_SIMD32);
465 baseType = getBaseTypeOfSIMDType(sig->retTypeSigClass);
466 retNode = gtNewSimdHWIntrinsicNode(TYP_SIMD32, op1, op2, NI_AVX_Add, baseType, 32);
470 JITDUMP("Not implemented hardware intrinsic");
476 GenTree* Compiler::impAVX2Intrinsic(NamedIntrinsic intrinsic, CORINFO_METHOD_HANDLE method, CORINFO_SIG_INFO* sig)
478 GenTree* retNode = nullptr;
479 GenTree* op1 = nullptr;
480 GenTree* op2 = nullptr;
481 var_types baseType = TYP_UNKNOWN;
484 case NI_AVX2_IsSupported:
485 retNode = gtNewIconNode(featureSIMD && compSupports(InstructionSet_AVX2));
489 assert(sig->numArgs == 2);
490 op2 = impSIMDPopStack(TYP_SIMD32);
491 op1 = impSIMDPopStack(TYP_SIMD32);
492 baseType = getBaseTypeOfSIMDType(sig->retTypeSigClass);
493 retNode = gtNewSimdHWIntrinsicNode(TYP_SIMD32, op1, op2, NI_AVX2_Add, baseType, 32);
497 JITDUMP("Not implemented hardware intrinsic");
503 GenTree* Compiler::impAESIntrinsic(NamedIntrinsic intrinsic, CORINFO_METHOD_HANDLE method, CORINFO_SIG_INFO* sig)
507 case NI_AES_IsSupported:
508 return gtNewIconNode(featureSIMD && compSupports(InstructionSet_AES));
515 GenTree* Compiler::impBMI1Intrinsic(NamedIntrinsic intrinsic, CORINFO_METHOD_HANDLE method, CORINFO_SIG_INFO* sig)
519 case NI_BMI1_IsSupported:
520 return gtNewIconNode(compSupports(InstructionSet_BMI1));
527 GenTree* Compiler::impBMI2Intrinsic(NamedIntrinsic intrinsic, CORINFO_METHOD_HANDLE method, CORINFO_SIG_INFO* sig)
531 case NI_BMI2_IsSupported:
532 return gtNewIconNode(compSupports(InstructionSet_BMI2));
539 GenTree* Compiler::impFMAIntrinsic(NamedIntrinsic intrinsic, CORINFO_METHOD_HANDLE method, CORINFO_SIG_INFO* sig)
543 case NI_FMA_IsSupported:
544 return gtNewIconNode(featureSIMD && compSupports(InstructionSet_FMA));
551 GenTree* Compiler::impLZCNTIntrinsic(NamedIntrinsic intrinsic, CORINFO_METHOD_HANDLE method, CORINFO_SIG_INFO* sig)
553 GenTree* retNode = nullptr;
554 GenTree* op1 = nullptr;
555 var_types callType = JITtype2varType(sig->retType);
559 case NI_LZCNT_IsSupported:
560 retNode = gtNewIconNode(compSupports(InstructionSet_LZCNT));
563 case NI_LZCNT_LeadingZeroCount:
564 assert(sig->numArgs == 1);
565 op1 = impPopStack().val;
567 if (varTypeIsLong(callType))
569 return gtNewMustThrowException(CORINFO_HELP_THROW_PLATFORM_NOT_SUPPORTED, callType, sig->retTypeClass);
572 retNode = gtNewScalarHWIntrinsicNode(callType, op1, NI_LZCNT_LeadingZeroCount);
576 JITDUMP("Not implemented hardware intrinsic");
582 GenTree* Compiler::impPCLMULQDQIntrinsic(NamedIntrinsic intrinsic, CORINFO_METHOD_HANDLE method, CORINFO_SIG_INFO* sig)
586 case NI_PCLMULQDQ_IsSupported:
587 return gtNewIconNode(featureSIMD && compSupports(InstructionSet_PCLMULQDQ));
594 GenTree* Compiler::impPOPCNTIntrinsic(NamedIntrinsic intrinsic, CORINFO_METHOD_HANDLE method, CORINFO_SIG_INFO* sig)
596 GenTree* retNode = nullptr;
597 GenTree* op1 = nullptr;
598 var_types callType = JITtype2varType(sig->retType);
602 case NI_POPCNT_IsSupported:
603 retNode = gtNewIconNode(compSupports(InstructionSet_POPCNT));
606 case NI_POPCNT_PopCount:
607 assert(sig->numArgs == 1);
608 op1 = impPopStack().val;
610 if (varTypeIsLong(callType))
612 return gtNewMustThrowException(CORINFO_HELP_THROW_PLATFORM_NOT_SUPPORTED, callType, sig->retTypeClass);
615 retNode = gtNewScalarHWIntrinsicNode(callType, op1, NI_POPCNT_PopCount);
619 JITDUMP("Not implemented hardware intrinsic");
625 #endif // FEATURE_HW_INTRINSICS