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 // impX86HWIntrinsic: dispatch hardware intrinsics to their own implementation
160 // intrinsic -- id of the intrinsic function.
161 // method -- method handle of the intrinsic function.
162 // sig -- signature of the intrinsic call
165 // the expanded intrinsic.
167 GenTree* Compiler::impX86HWIntrinsic(NamedIntrinsic intrinsic, CORINFO_METHOD_HANDLE method, CORINFO_SIG_INFO* sig)
169 InstructionSet isa = isaOfHWIntrinsic(intrinsic);
170 if (!compSupports(isa) && strcmp("get_IsSupported", getHWIntrinsicName(intrinsic)) != 0)
172 for (unsigned i = 0; i < sig->numArgs; i++)
176 return gtNewMustThrowException(CORINFO_HELP_THROW_PLATFORM_NOT_SUPPORTED, JITtype2varType(sig->retType));
180 case InstructionSet_SSE:
181 return impSSEIntrinsic(intrinsic, method, sig);
182 case InstructionSet_SSE2:
183 return impSSE2Intrinsic(intrinsic, method, sig);
184 case InstructionSet_SSE3:
185 return impSSE3Intrinsic(intrinsic, method, sig);
186 case InstructionSet_SSSE3:
187 return impSSSE3Intrinsic(intrinsic, method, sig);
188 case InstructionSet_SSE41:
189 return impSSE41Intrinsic(intrinsic, method, sig);
190 case InstructionSet_SSE42:
191 return impSSE42Intrinsic(intrinsic, method, sig);
192 case InstructionSet_AVX:
193 return impAVXIntrinsic(intrinsic, method, sig);
194 case InstructionSet_AVX2:
195 return impAVX2Intrinsic(intrinsic, method, sig);
197 case InstructionSet_AES:
198 return impAESIntrinsic(intrinsic, method, sig);
199 case InstructionSet_BMI1:
200 return impBMI1Intrinsic(intrinsic, method, sig);
201 case InstructionSet_BMI2:
202 return impBMI2Intrinsic(intrinsic, method, sig);
203 case InstructionSet_FMA:
204 return impFMAIntrinsic(intrinsic, method, sig);
205 case InstructionSet_LZCNT:
206 return impLZCNTIntrinsic(intrinsic, method, sig);
207 case InstructionSet_PCLMULQDQ:
208 return impPCLMULQDQIntrinsic(intrinsic, method, sig);
209 case InstructionSet_POPCNT:
210 return impPOPCNTIntrinsic(intrinsic, method, sig);
216 GenTree* Compiler::impSSEIntrinsic(NamedIntrinsic intrinsic, CORINFO_METHOD_HANDLE method, CORINFO_SIG_INFO* sig)
220 case NI_SSE_IsSupported:
221 return gtNewIconNode(compSupports(InstructionSet_SSE));
228 GenTree* Compiler::impSSE2Intrinsic(NamedIntrinsic intrinsic, CORINFO_METHOD_HANDLE method, CORINFO_SIG_INFO* sig)
232 case NI_SSE2_IsSupported:
233 return gtNewIconNode(compSupports(InstructionSet_SSE2));
240 GenTree* Compiler::impSSE3Intrinsic(NamedIntrinsic intrinsic, CORINFO_METHOD_HANDLE method, CORINFO_SIG_INFO* sig)
244 case NI_SSE3_IsSupported:
245 return gtNewIconNode(compSupports(InstructionSet_SSE3));
252 GenTree* Compiler::impSSSE3Intrinsic(NamedIntrinsic intrinsic, CORINFO_METHOD_HANDLE method, CORINFO_SIG_INFO* sig)
256 case NI_SSSE3_IsSupported:
257 return gtNewIconNode(compSupports(InstructionSet_SSSE3));
264 GenTree* Compiler::impSSE41Intrinsic(NamedIntrinsic intrinsic, CORINFO_METHOD_HANDLE method, CORINFO_SIG_INFO* sig)
268 case NI_SSE41_IsSupported:
269 return gtNewIconNode(compSupports(InstructionSet_SSE41));
276 GenTree* Compiler::impSSE42Intrinsic(NamedIntrinsic intrinsic, CORINFO_METHOD_HANDLE method, CORINFO_SIG_INFO* sig)
278 GenTree* retNode = nullptr;
279 GenTree* op1 = nullptr;
280 GenTree* op2 = nullptr;
281 var_types callType = JITtype2varType(sig->retType);
283 CORINFO_ARG_LIST_HANDLE argLst = sig->args;
284 CORINFO_CLASS_HANDLE argClass;
288 case NI_SSE42_IsSupported:
289 retNode = gtNewIconNode(compSupports(InstructionSet_SSE42));
293 assert(sig->numArgs == 2);
294 op2 = impPopStack().val;
295 op1 = impPopStack().val;
297 if (varTypeIsLong(callType))
299 return gtNewMustThrowException(CORINFO_HELP_THROW_PLATFORM_NOT_SUPPORTED, callType);
302 argLst = info.compCompHnd->getArgNext(argLst); // the second argument
303 corType = strip(info.compCompHnd->getArgType(sig, argLst, &argClass)); // type of the second argument
305 retNode = gtNewScalarHWIntrinsicNode(callType, op1, op2, NI_SSE42_Crc32);
307 // TODO - currently we use the BaseType to bring the type of the second argument
308 // to the code generator. May encode the overload info in other way.
309 retNode->gtHWIntrinsic.gtSIMDBaseType = JITtype2varType(corType);
313 JITDUMP("Not implemented hardware intrinsic");
319 GenTree* Compiler::impAVXIntrinsic(NamedIntrinsic intrinsic, CORINFO_METHOD_HANDLE method, CORINFO_SIG_INFO* sig)
323 case NI_AVX_IsSupported:
324 return gtNewIconNode(compSupports(InstructionSet_AVX));
331 GenTree* Compiler::impAVX2Intrinsic(NamedIntrinsic intrinsic, CORINFO_METHOD_HANDLE method, CORINFO_SIG_INFO* sig)
335 case NI_AVX2_IsSupported:
336 return gtNewIconNode(compSupports(InstructionSet_AVX2));
343 GenTree* Compiler::impAESIntrinsic(NamedIntrinsic intrinsic, CORINFO_METHOD_HANDLE method, CORINFO_SIG_INFO* sig)
347 case NI_AES_IsSupported:
348 return gtNewIconNode(compSupports(InstructionSet_AES));
355 GenTree* Compiler::impBMI1Intrinsic(NamedIntrinsic intrinsic, CORINFO_METHOD_HANDLE method, CORINFO_SIG_INFO* sig)
359 case NI_BMI1_IsSupported:
360 return gtNewIconNode(compSupports(InstructionSet_BMI1));
367 GenTree* Compiler::impBMI2Intrinsic(NamedIntrinsic intrinsic, CORINFO_METHOD_HANDLE method, CORINFO_SIG_INFO* sig)
371 case NI_BMI2_IsSupported:
372 return gtNewIconNode(compSupports(InstructionSet_BMI2));
379 GenTree* Compiler::impFMAIntrinsic(NamedIntrinsic intrinsic, CORINFO_METHOD_HANDLE method, CORINFO_SIG_INFO* sig)
383 case NI_FMA_IsSupported:
384 return gtNewIconNode(compSupports(InstructionSet_FMA));
391 GenTree* Compiler::impLZCNTIntrinsic(NamedIntrinsic intrinsic, CORINFO_METHOD_HANDLE method, CORINFO_SIG_INFO* sig)
393 GenTree* retNode = nullptr;
394 GenTree* op1 = nullptr;
395 var_types callType = JITtype2varType(sig->retType);
399 case NI_LZCNT_IsSupported:
400 retNode = gtNewIconNode(compSupports(InstructionSet_LZCNT));
403 case NI_LZCNT_LeadingZeroCount:
404 assert(sig->numArgs == 1);
405 op1 = impPopStack().val;
407 if (varTypeIsLong(callType))
409 return gtNewMustThrowException(CORINFO_HELP_THROW_PLATFORM_NOT_SUPPORTED, callType);
412 retNode = gtNewScalarHWIntrinsicNode(callType, op1, NI_LZCNT_LeadingZeroCount);
416 JITDUMP("Not implemented hardware intrinsic");
422 GenTree* Compiler::impPCLMULQDQIntrinsic(NamedIntrinsic intrinsic, CORINFO_METHOD_HANDLE method, CORINFO_SIG_INFO* sig)
426 case NI_PCLMULQDQ_IsSupported:
427 return gtNewIconNode(compSupports(InstructionSet_PCLMULQDQ));
434 GenTree* Compiler::impPOPCNTIntrinsic(NamedIntrinsic intrinsic, CORINFO_METHOD_HANDLE method, CORINFO_SIG_INFO* sig)
436 GenTree* retNode = nullptr;
437 GenTree* op1 = nullptr;
438 var_types callType = JITtype2varType(sig->retType);
442 case NI_POPCNT_IsSupported:
443 retNode = gtNewIconNode(compSupports(InstructionSet_POPCNT));
446 case NI_POPCNT_PopCount:
447 assert(sig->numArgs == 1);
448 op1 = impPopStack().val;
450 if (varTypeIsLong(callType))
452 return gtNewMustThrowException(CORINFO_HELP_THROW_PLATFORM_NOT_SUPPORTED, callType);
455 retNode = gtNewScalarHWIntrinsicNode(callType, op1, NI_POPCNT_PopCount);
459 JITDUMP("Not implemented hardware intrinsic");
465 #endif // FEATURE_HW_INTRINSICS