3b4634bcd6b7ff3016e975400fc5dd63ffd7cefa
[platform/upstream/coreclr.git] / src / jit / hwintrinsicxarch.h
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 #ifndef _HW_INTRINSIC_XARCH_H_
6 #define _HW_INTRINSIC_XARCH_H_
7
8 #ifdef FEATURE_HW_INTRINSICS
9
10 enum HWIntrinsicCategory : unsigned int
11 {
12     // Simple SIMD intrinsics
13     // - take Vector128/256<T> parameters
14     // - return a Vector128/256<T>
15     // - the codegen of overloads can be determined by intrinsicID and base type of returned vector
16     HW_Category_SimpleSIMD,
17
18     // IsSupported Property
19     // - each ISA class has an "IsSupported" property
20     HW_Category_IsSupportedProperty,
21
22     // IMM intrinsics
23     // - some SIMD intrinsics requires immediate value (i.e. imm8) to generate instruction
24     HW_Category_IMM,
25
26     // Scalar intrinsics
27     // - operate over general purpose registers, like crc32, lzcnt, popcnt, etc.
28     HW_Category_Scalar,
29
30     // SIMD scalar
31     // - operate over vector registers(XMM), but just compute on the first element
32     HW_Category_SIMDScalar,
33
34     // Memory access intrinsics
35     // - e.g., Avx.Load, Avx.Store, Sse.LoadAligned
36     HW_Category_MemoryLoad,
37     HW_Category_MemoryStore,
38
39     // Helper intrinsics
40     // - do not directly correspond to a instruction, such as Avx.SetAllVector256
41     HW_Category_Helper,
42
43     // Special intrinsics
44     // - have to be addressed specially
45     HW_Category_Special
46 };
47
48 enum HWIntrinsicFlag : unsigned int
49 {
50     HW_Flag_NoFlag = 0,
51
52     // Commutative
53     // - if a binary-op intrinsic is commutative (e.g., Add, Multiply), its op1 can be contained
54     HW_Flag_Commutative = 0x1,
55
56     // Full range IMM intrinsic
57     // - the immediate value is valid on the full range of imm8 (0-255)
58     HW_Flag_FullRangeIMM = 0x2,
59
60     // Generic
61     // - must throw NotSupportException if the type argument is not numeric type
62     HW_Flag_OneTypeGeneric = 0x4,
63     // Two-type Generic
64     // - the intrinsic has two type parameters
65     HW_Flag_TwoTypeGeneric = 0x8,
66
67     // NoCodeGen
68     // - should be transformed in the compiler front-end, cannot reach CodeGen
69     HW_Flag_NoCodeGen = 0x10,
70
71     // Unfixed SIMD-size
72     // - overloaded on multiple vector sizes (SIMD size in the table is unreliable)
73     HW_Flag_UnfixedSIMDSize = 0x20,
74
75     // Multi-instruction
76     // - that one intrinsic can generate multiple instructions
77     HW_Flag_MultiIns = 0x80,
78
79     // NoContainment
80     // the intrinsic cannot be handled by comtainment,
81     // all the intrinsic that have explicit memory load/store semantics should have this flag
82     HW_Flag_NoContainment = 0x100,
83
84     // Copy Upper bits
85     // some SIMD scalar intrinsics need the semantics of copying upper bits from the source operand
86     HW_Flag_CopyUpperBits = 0x200,
87
88     // Select base type using the first argument type
89     HW_Flag_BaseTypeFromFirstArg = 0x400,
90
91     // Indicates compFloatingPointUsed does not need to be set.
92     HW_Flag_NoFloatingPointUsed = 0x800,
93
94     // Maybe IMM
95     // the intrinsic has either imm or Vector overloads
96     HW_Flag_MaybeIMM = 0x1000,
97
98     // NoJmpTable IMM
99     // the imm intrinsic does not need jumptable fallback when it gets non-const argument
100     HW_Flag_NoJmpTableIMM = 0x2000,
101
102     // 64-bit intrinsics
103     // Intrinsics that operate over 64-bit general purpose registers are not supported on 32-bit platform
104     HW_Flag_64BitOnly           = 0x4000,
105     HW_Flag_SecondArgMaybe64Bit = 0x8000,
106
107     // Select base type using the second argument type
108     HW_Flag_BaseTypeFromSecondArg = 0x10000,
109
110     // Special codegen
111     // the intrinsics need special rules in CodeGen,
112     // but may be table-driven in the front-end
113     HW_Flag_SpecialCodeGen = 0x20000,
114
115     // No Read/Modify/Write Semantics
116     // the intrinsic doesn't have read/modify/write semantics in two/three-operand form.
117     HW_Flag_NoRMWSemantics = 0x40000,
118
119     // Special import
120     // the intrinsics need special rules in importer,
121     // but may be table-driven in the back-end
122     HW_Flag_SpecialImport = 0x80000,
123
124     // Maybe Memory Load/Store
125     // - some intrinsics may have pointer overloads but without HW_Category_MemoryLoad/HW_Category_MemoryStore
126     HW_Flag_MaybeMemoryLoad  = 0x100000,
127     HW_Flag_MaybeMemoryStore = 0x200000,
128 };
129
130 struct HWIntrinsicInfo
131 {
132     NamedIntrinsic      id;
133     const char*         name;
134     InstructionSet      isa;
135     int                 ival;
136     unsigned            simdSize;
137     int                 numArgs;
138     instruction         ins[10];
139     HWIntrinsicCategory category;
140     HWIntrinsicFlag     flags;
141
142     static const HWIntrinsicInfo& lookup(NamedIntrinsic id);
143
144     static NamedIntrinsic lookupId(const char* className, const char* methodName);
145     static InstructionSet lookupIsa(const char* className);
146
147     static unsigned lookupSimdSize(Compiler* comp, NamedIntrinsic id, CORINFO_SIG_INFO* sig);
148
149     static int lookupNumArgs(const GenTreeHWIntrinsic* node);
150     static GenTree* lookupLastOp(const GenTreeHWIntrinsic* node);
151     static bool isImmOp(NamedIntrinsic id, const GenTree* op);
152
153     static int lookupImmUpperBound(NamedIntrinsic id);
154     static bool isInImmRange(NamedIntrinsic id, int ival);
155     static bool isAVX2GatherIntrinsic(NamedIntrinsic id);
156
157     static bool isFullyImplementedIsa(InstructionSet isa);
158     static bool isScalarIsa(InstructionSet isa);
159
160     // Member lookup
161
162     static NamedIntrinsic lookupId(NamedIntrinsic id)
163     {
164         return lookup(id).id;
165     }
166
167     static const char* lookupName(NamedIntrinsic id)
168     {
169         return lookup(id).name;
170     }
171
172     static InstructionSet lookupIsa(NamedIntrinsic id)
173     {
174         return lookup(id).isa;
175     }
176
177     static int lookupIval(NamedIntrinsic id)
178     {
179         return lookup(id).ival;
180     }
181
182     static unsigned lookupSimdSize(NamedIntrinsic id)
183     {
184         return lookup(id).simdSize;
185     }
186
187     static int lookupNumArgs(NamedIntrinsic id)
188     {
189         return lookup(id).numArgs;
190     }
191
192     static instruction lookupIns(NamedIntrinsic id, var_types type)
193     {
194         assert((type >= TYP_BYTE) && (type <= TYP_DOUBLE));
195         return lookup(id).ins[type - TYP_BYTE];
196     }
197
198     static HWIntrinsicCategory lookupCategory(NamedIntrinsic id)
199     {
200         return lookup(id).category;
201     }
202
203     static HWIntrinsicFlag lookupFlags(NamedIntrinsic id)
204     {
205         return lookup(id).flags;
206     }
207
208     // Flags lookup
209
210     static const bool IsCommutative(NamedIntrinsic id)
211     {
212         HWIntrinsicFlag flags = lookupFlags(id);
213         return (flags & HW_Flag_Commutative) != 0;
214     }
215
216     static const bool HasFullRangeImm(NamedIntrinsic id)
217     {
218         HWIntrinsicFlag flags = lookupFlags(id);
219         return (flags & HW_Flag_FullRangeIMM) != 0;
220     }
221
222     static const bool IsOneTypeGeneric(NamedIntrinsic id)
223     {
224         HWIntrinsicFlag flags = lookupFlags(id);
225         return (flags & HW_Flag_OneTypeGeneric) != 0;
226     }
227
228     static const bool IsTwoTypeGeneric(NamedIntrinsic id)
229     {
230         HWIntrinsicFlag flags = lookupFlags(id);
231         return (flags & HW_Flag_TwoTypeGeneric) != 0;
232     }
233
234     static const bool RequiresCodegen(NamedIntrinsic id)
235     {
236         HWIntrinsicFlag flags = lookupFlags(id);
237         return (flags & HW_Flag_NoCodeGen) == 0;
238     }
239
240     static const bool HasFixedSimdSize(NamedIntrinsic id)
241     {
242         HWIntrinsicFlag flags = lookupFlags(id);
243         return (flags & HW_Flag_UnfixedSIMDSize) == 0;
244     }
245
246     static const bool GeneratesMultipleIns(NamedIntrinsic id)
247     {
248         HWIntrinsicFlag flags = lookupFlags(id);
249         return (flags & HW_Flag_MultiIns) != 0;
250     }
251
252     static const bool SupportsContainment(NamedIntrinsic id)
253     {
254         HWIntrinsicFlag flags = lookupFlags(id);
255         return (flags & HW_Flag_NoContainment) == 0;
256     }
257
258     static const bool CopiesUpperBits(NamedIntrinsic id)
259     {
260         HWIntrinsicFlag flags = lookupFlags(id);
261         return (flags & HW_Flag_CopyUpperBits) != 0;
262     }
263
264     static const bool BaseTypeFromFirstArg(NamedIntrinsic id)
265     {
266         HWIntrinsicFlag flags = lookupFlags(id);
267         return (flags & HW_Flag_BaseTypeFromFirstArg) != 0;
268     }
269
270     static const bool IsFloatingPointUsed(NamedIntrinsic id)
271     {
272         HWIntrinsicFlag flags = lookupFlags(id);
273         return (flags & HW_Flag_NoFloatingPointUsed) == 0;
274     }
275
276     static const bool MaybeImm(NamedIntrinsic id)
277     {
278         HWIntrinsicFlag flags = lookupFlags(id);
279         return (flags & HW_Flag_MaybeIMM) != 0;
280     }
281
282     static const bool MaybeMemoryLoad(NamedIntrinsic id)
283     {
284         HWIntrinsicFlag flags = lookupFlags(id);
285         return (flags & HW_Flag_MaybeMemoryLoad) != 0;
286     }
287
288     static const bool MaybeMemoryStore(NamedIntrinsic id)
289     {
290         HWIntrinsicFlag flags = lookupFlags(id);
291         return (flags & HW_Flag_MaybeMemoryStore) != 0;
292     }
293
294     static const bool NoJmpTableImm(NamedIntrinsic id)
295     {
296         HWIntrinsicFlag flags = lookupFlags(id);
297         return (flags & HW_Flag_NoJmpTableIMM) != 0;
298     }
299
300     static const bool Is64BitOnly(NamedIntrinsic id)
301     {
302         HWIntrinsicFlag flags = lookupFlags(id);
303         return (flags & HW_Flag_64BitOnly) != 0;
304     }
305
306     static const bool SecondArgMaybe64Bit(NamedIntrinsic id)
307     {
308         HWIntrinsicFlag flags = lookupFlags(id);
309         return (flags & HW_Flag_SecondArgMaybe64Bit) != 0;
310     }
311
312     static const bool BaseTypeFromSecondArg(NamedIntrinsic id)
313     {
314         HWIntrinsicFlag flags = lookupFlags(id);
315         return (flags & HW_Flag_BaseTypeFromSecondArg) != 0;
316     }
317
318     static const bool HasSpecialCodegen(NamedIntrinsic id)
319     {
320         HWIntrinsicFlag flags = lookupFlags(id);
321         return (flags & HW_Flag_SpecialCodeGen) != 0;
322     }
323
324     static const bool HasRMWSemantics(NamedIntrinsic id)
325     {
326         HWIntrinsicFlag flags = lookupFlags(id);
327         return (flags & HW_Flag_NoRMWSemantics) == 0;
328     }
329
330     static const bool HasSpecialImport(NamedIntrinsic id)
331     {
332         HWIntrinsicFlag flags = lookupFlags(id);
333         return (flags & HW_Flag_SpecialImport) != 0;
334     }
335 };
336
337 #endif // FEATURE_HW_INTRINSICS
338
339 #endif // _HW_INTRINSIC_XARCH_H_