Merge pull request #14027 from mikedn/simd-eq-opt
[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 #ifdef _TARGET_XARCH_
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 //------------------------------------------------------------------------
22 // lookupHWIntrinsicISA: map class name to InstructionSet value
23 //
24 // Arguments:
25 //    className -- class name in System.Runtime.Intrinsics.X86
26 //
27 // Return Value:
28 //    Id for the ISA class.
29 //
30 InstructionSet Compiler::lookupHWIntrinsicISA(const char* className)
31 {
32     if (className != nullptr)
33     {
34         if (className[0] == 'A')
35         {
36             if (strcmp(className, "Aes") == 0)
37             {
38                 return InstructionSet_AES;
39             }
40             else if (strcmp(className, "Avx") == 0)
41             {
42                 return InstructionSet_AVX;
43             }
44             else if (strcmp(className, "Avx2") == 0)
45             {
46                 return InstructionSet_AVX2;
47             }
48         }
49         if (className[0] == 'S')
50         {
51             if (strcmp(className, "Sse") == 0)
52             {
53                 return InstructionSet_SSE;
54             }
55             else if (strcmp(className, "Sse2") == 0)
56             {
57                 return InstructionSet_SSE2;
58             }
59             else if (strcmp(className, "Sse3") == 0)
60             {
61                 return InstructionSet_SSE3;
62             }
63             else if (strcmp(className, "Ssse3") == 0)
64             {
65                 return InstructionSet_SSSE3;
66             }
67             else if (strcmp(className, "Sse41") == 0)
68             {
69                 return InstructionSet_SSE41;
70             }
71             else if (strcmp(className, "Sse42") == 0)
72             {
73                 return InstructionSet_SSE42;
74             }
75         }
76
77         if (strcmp(className, "Bmi1") == 0)
78         {
79             return InstructionSet_BMI1;
80         }
81         else if (strcmp(className, "Bmi2") == 0)
82         {
83             return InstructionSet_BMI2;
84         }
85         else if (strcmp(className, "Fma") == 0)
86         {
87             return InstructionSet_FMA;
88         }
89         else if (strcmp(className, "Lzcnt") == 0)
90         {
91             return InstructionSet_LZCNT;
92         }
93         else if (strcmp(className, "Pclmulqdq") == 0)
94         {
95             return InstructionSet_PCLMULQDQ;
96         }
97         else if (strcmp(className, "Popcnt") == 0)
98         {
99             return InstructionSet_POPCNT;
100         }
101     }
102
103     JITDUMP("Unsupported ISA.\n");
104     return InstructionSet_ILLEGAL;
105 }
106
107 //------------------------------------------------------------------------
108 // lookupHWIntrinsic: map intrinsic name to named intrinsic value
109 //
110 // Arguments:
111 //    methodName -- name of the intrinsic function.
112 //    isa        -- instruction set of the intrinsic.
113 //
114 // Return Value:
115 //    Id for the hardware intrinsic.
116 //
117 // TODO-Throughput: replace sequential search by binary search
118 NamedIntrinsic Compiler::lookupHWIntrinsic(const char* methodName, InstructionSet isa)
119 {
120     NamedIntrinsic result = NI_Illegal;
121     if (isa != InstructionSet_ILLEGAL)
122     {
123         for (int i = 0; i < NI_HW_INTRINSIC_END - NI_HW_INTRINSIC_START; i++)
124         {
125             if (isa == hwIntrinsicInfoArray[i].isa && strcmp(methodName, hwIntrinsicInfoArray[i].intrinsicName) == 0)
126             {
127                 result = hwIntrinsicInfoArray[i].intrinsicID;
128             }
129         }
130     }
131     return result;
132 }
133
134 //------------------------------------------------------------------------
135 // isaOfHWIntrinsic: map named intrinsic value to its instruction set
136 //
137 // Arguments:
138 //    intrinsic -- id of the intrinsic function.
139 //
140 // Return Value:
141 //    instruction set of the intrinsic.
142 //
143 InstructionSet Compiler::isaOfHWIntrinsic(NamedIntrinsic intrinsic)
144 {
145     assert(intrinsic != NI_Illegal);
146     assert(intrinsic > NI_HW_INTRINSIC_START && intrinsic < NI_HW_INTRINSIC_END);
147     return hwIntrinsicInfoArray[intrinsic - NI_HW_INTRINSIC_START - 1].isa;
148 }
149
150 //------------------------------------------------------------------------
151 // impX86HWIntrinsic: dispatch hardware intrinsics to their own implementation
152 // function
153 //
154 // Arguments:
155 //    intrinsic -- id of the intrinsic function.
156 //    method    -- method handle of the intrinsic function.
157 //    sig       -- signature of the intrinsic call
158 //
159 // Return Value:
160 //    the expanded intrinsic.
161 //
162 GenTree* Compiler::impX86HWIntrinsic(NamedIntrinsic intrinsic, CORINFO_METHOD_HANDLE method, CORINFO_SIG_INFO* sig)
163 {
164     InstructionSet isa = isaOfHWIntrinsic(intrinsic);
165     switch (isa)
166     {
167         case InstructionSet_SSE:
168             return impSSEIntrinsic(intrinsic, method, sig);
169         case InstructionSet_SSE2:
170             return impSSE2Intrinsic(intrinsic, method, sig);
171         case InstructionSet_SSE3:
172             return impSSE3Intrinsic(intrinsic, method, sig);
173         case InstructionSet_SSSE3:
174             return impSSSE3Intrinsic(intrinsic, method, sig);
175         case InstructionSet_SSE41:
176             return impSSE41Intrinsic(intrinsic, method, sig);
177         case InstructionSet_SSE42:
178             return impSSE42Intrinsic(intrinsic, method, sig);
179         case InstructionSet_AVX:
180             return impAVXIntrinsic(intrinsic, method, sig);
181         case InstructionSet_AVX2:
182             return impAVX2Intrinsic(intrinsic, method, sig);
183
184         case InstructionSet_AES:
185             return impAESIntrinsic(intrinsic, method, sig);
186         case InstructionSet_BMI1:
187             return impBMI1Intrinsic(intrinsic, method, sig);
188         case InstructionSet_BMI2:
189             return impBMI2Intrinsic(intrinsic, method, sig);
190         case InstructionSet_FMA:
191             return impFMAIntrinsic(intrinsic, method, sig);
192         case InstructionSet_LZCNT:
193             return impLZCNTIntrinsic(intrinsic, method, sig);
194         case InstructionSet_PCLMULQDQ:
195             return impPCLMULQDQIntrinsic(intrinsic, method, sig);
196         case InstructionSet_POPCNT:
197             return impPOPCNTIntrinsic(intrinsic, method, sig);
198         default:
199             return nullptr;
200     }
201 }
202
203 GenTree* Compiler::impSSEIntrinsic(NamedIntrinsic intrinsic, CORINFO_METHOD_HANDLE method, CORINFO_SIG_INFO* sig)
204 {
205     switch (intrinsic)
206     {
207         case NI_SSE_IsSupported:
208             return gtNewIconNode(compSupports(InstructionSet_SSE));
209
210         default:
211             return nullptr;
212     }
213 }
214
215 GenTree* Compiler::impSSE2Intrinsic(NamedIntrinsic intrinsic, CORINFO_METHOD_HANDLE method, CORINFO_SIG_INFO* sig)
216 {
217     switch (intrinsic)
218     {
219         case NI_SSE2_IsSupported:
220             return gtNewIconNode(compSupports(InstructionSet_SSE2));
221
222         default:
223             return nullptr;
224     }
225 }
226
227 GenTree* Compiler::impSSE3Intrinsic(NamedIntrinsic intrinsic, CORINFO_METHOD_HANDLE method, CORINFO_SIG_INFO* sig)
228 {
229     switch (intrinsic)
230     {
231         case NI_SSE3_IsSupported:
232             return gtNewIconNode(compSupports(InstructionSet_SSE3));
233
234         default:
235             return nullptr;
236     }
237 }
238
239 GenTree* Compiler::impSSSE3Intrinsic(NamedIntrinsic intrinsic, CORINFO_METHOD_HANDLE method, CORINFO_SIG_INFO* sig)
240 {
241     switch (intrinsic)
242     {
243         case NI_SSSE3_IsSupported:
244             return gtNewIconNode(compSupports(InstructionSet_SSSE3));
245
246         default:
247             return nullptr;
248     }
249 }
250
251 GenTree* Compiler::impSSE41Intrinsic(NamedIntrinsic intrinsic, CORINFO_METHOD_HANDLE method, CORINFO_SIG_INFO* sig)
252 {
253     switch (intrinsic)
254     {
255         case NI_SSE41_IsSupported:
256             return gtNewIconNode(compSupports(InstructionSet_SSE41));
257
258         default:
259             return nullptr;
260     }
261 }
262
263 GenTree* Compiler::impSSE42Intrinsic(NamedIntrinsic intrinsic, CORINFO_METHOD_HANDLE method, CORINFO_SIG_INFO* sig)
264 {
265     switch (intrinsic)
266     {
267         case NI_SSE42_IsSupported:
268             return gtNewIconNode(compSupports(InstructionSet_SSE42));
269
270         default:
271             return nullptr;
272     }
273 }
274
275 GenTree* Compiler::impAVXIntrinsic(NamedIntrinsic intrinsic, CORINFO_METHOD_HANDLE method, CORINFO_SIG_INFO* sig)
276 {
277     switch (intrinsic)
278     {
279         case NI_AVX_IsSupported:
280             return gtNewIconNode(compSupports(InstructionSet_AVX));
281
282         default:
283             return nullptr;
284     }
285 }
286
287 GenTree* Compiler::impAVX2Intrinsic(NamedIntrinsic intrinsic, CORINFO_METHOD_HANDLE method, CORINFO_SIG_INFO* sig)
288 {
289     switch (intrinsic)
290     {
291         case NI_AVX2_IsSupported:
292             return gtNewIconNode(compSupports(InstructionSet_AVX2));
293
294         default:
295             return nullptr;
296     }
297 }
298
299 GenTree* Compiler::impAESIntrinsic(NamedIntrinsic intrinsic, CORINFO_METHOD_HANDLE method, CORINFO_SIG_INFO* sig)
300 {
301     switch (intrinsic)
302     {
303         case NI_AES_IsSupported:
304             return gtNewIconNode(compSupports(InstructionSet_AES));
305
306         default:
307             return nullptr;
308     }
309 }
310
311 GenTree* Compiler::impBMI1Intrinsic(NamedIntrinsic intrinsic, CORINFO_METHOD_HANDLE method, CORINFO_SIG_INFO* sig)
312 {
313     switch (intrinsic)
314     {
315         case NI_BMI1_IsSupported:
316             return gtNewIconNode(compSupports(InstructionSet_BMI1));
317
318         default:
319             return nullptr;
320     }
321 }
322
323 GenTree* Compiler::impBMI2Intrinsic(NamedIntrinsic intrinsic, CORINFO_METHOD_HANDLE method, CORINFO_SIG_INFO* sig)
324 {
325     switch (intrinsic)
326     {
327         case NI_BMI2_IsSupported:
328             return gtNewIconNode(compSupports(InstructionSet_BMI2));
329
330         default:
331             return nullptr;
332     }
333 }
334
335 GenTree* Compiler::impFMAIntrinsic(NamedIntrinsic intrinsic, CORINFO_METHOD_HANDLE method, CORINFO_SIG_INFO* sig)
336 {
337     switch (intrinsic)
338     {
339         case NI_FMA_IsSupported:
340             return gtNewIconNode(compSupports(InstructionSet_FMA));
341
342         default:
343             return nullptr;
344     }
345 }
346
347 GenTree* Compiler::impLZCNTIntrinsic(NamedIntrinsic intrinsic, CORINFO_METHOD_HANDLE method, CORINFO_SIG_INFO* sig)
348 {
349     switch (intrinsic)
350     {
351         case NI_LZCNT_IsSupported:
352             return gtNewIconNode(compSupports(InstructionSet_LZCNT));
353
354         default:
355             return nullptr;
356     }
357 }
358
359 GenTree* Compiler::impPCLMULQDQIntrinsic(NamedIntrinsic intrinsic, CORINFO_METHOD_HANDLE method, CORINFO_SIG_INFO* sig)
360 {
361     switch (intrinsic)
362     {
363         case NI_PCLMULQDQ_IsSupported:
364             return gtNewIconNode(compSupports(InstructionSet_PCLMULQDQ));
365
366         default:
367             return nullptr;
368     }
369 }
370
371 GenTree* Compiler::impPOPCNTIntrinsic(NamedIntrinsic intrinsic, CORINFO_METHOD_HANDLE method, CORINFO_SIG_INFO* sig)
372 {
373     switch (intrinsic)
374     {
375         case NI_POPCNT_IsSupported:
376             return gtNewIconNode(compSupports(InstructionSet_POPCNT));
377
378         default:
379             return nullptr;
380     }
381 }
382
383 #endif // _TARGET_XARCH_