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.
5 #ifndef _HW_INTRINSIC_XARCH_H_
6 #define _HW_INTRINSIC_XARCH_H_
8 #ifdef FEATURE_HW_INTRINSICS
10 enum HWIntrinsicCategory : unsigned int
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,
18 // IsSupported Property
19 // - each ISA class has an "IsSupported" property
20 HW_Category_IsSupportedProperty,
23 // - some SIMD intrinsics requires immediate value (i.e. imm8) to generate instruction
27 // - operate over general purpose registers, like crc32, lzcnt, popcnt, etc.
31 // - operate over vector registers(XMM), but just compute on the first element
32 HW_Category_SIMDScalar,
34 // Memory access intrinsics
35 // - e.g., Avx.Load, Avx.Store, Sse.LoadAligned
36 HW_Category_MemoryLoad,
37 HW_Category_MemoryStore,
40 // - do not directly correspond to a instruction, such as Avx.SetAllVector256
44 // - have to be addressed specially
48 enum HWIntrinsicFlag : unsigned int
53 // - if a binary-op intrinsic is commutative (e.g., Add, Multiply), its op1 can be contained
54 HW_Flag_Commutative = 0x1,
56 // Full range IMM intrinsic
57 // - the immediate value is valid on the full range of imm8 (0-255)
58 HW_Flag_FullRangeIMM = 0x2,
61 // - must throw NotSupportException if the type argument is not numeric type
62 HW_Flag_OneTypeGeneric = 0x4,
64 // - the intrinsic has two type parameters
65 HW_Flag_TwoTypeGeneric = 0x8,
68 // - should be transformed in the compiler front-end, cannot reach CodeGen
69 HW_Flag_NoCodeGen = 0x10,
72 // - overloaded on multiple vector sizes (SIMD size in the table is unreliable)
73 HW_Flag_UnfixedSIMDSize = 0x20,
76 // - that one intrinsic can generate multiple instructions
77 HW_Flag_MultiIns = 0x80,
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,
85 // some SIMD scalar intrinsics need the semantics of copying upper bits from the source operand
86 HW_Flag_CopyUpperBits = 0x200,
88 // Select base type using the first argument type
89 HW_Flag_BaseTypeFromFirstArg = 0x400,
91 // Indicates compFloatingPointUsed does not need to be set.
92 HW_Flag_NoFloatingPointUsed = 0x800,
95 // the intrinsic has either imm or Vector overloads
96 HW_Flag_MaybeIMM = 0x1000,
99 // the imm intrinsic does not need jumptable fallback when it gets non-const argument
100 HW_Flag_NoJmpTableIMM = 0x2000,
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,
107 // Select base type using the second argument type
108 HW_Flag_BaseTypeFromSecondArg = 0x10000,
111 // the intrinsics need special rules in CodeGen,
112 // but may be table-driven in the front-end
113 HW_Flag_SpecialCodeGen = 0x20000,
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,
120 // the intrinsics need special rules in importer,
121 // but may be table-driven in the back-end
122 HW_Flag_SpecialImport = 0x80000,
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,
130 struct HWIntrinsicInfo
139 HWIntrinsicCategory category;
140 HWIntrinsicFlag flags;
142 static const HWIntrinsicInfo& lookup(NamedIntrinsic id);
144 static NamedIntrinsic lookupId(const char* className, const char* methodName);
145 static InstructionSet lookupIsa(const char* className);
147 static unsigned lookupSimdSize(Compiler* comp, NamedIntrinsic id, CORINFO_SIG_INFO* sig);
149 static int lookupNumArgs(const GenTreeHWIntrinsic* node);
150 static GenTree* lookupLastOp(const GenTreeHWIntrinsic* node);
151 static bool isImmOp(NamedIntrinsic id, const GenTree* op);
153 static int lookupImmUpperBound(NamedIntrinsic id);
154 static bool isInImmRange(NamedIntrinsic id, int ival);
155 static bool isAVX2GatherIntrinsic(NamedIntrinsic id);
157 static bool isFullyImplementedIsa(InstructionSet isa);
158 static bool isScalarIsa(InstructionSet isa);
162 static NamedIntrinsic lookupId(NamedIntrinsic id)
164 return lookup(id).id;
167 static const char* lookupName(NamedIntrinsic id)
169 return lookup(id).name;
172 static InstructionSet lookupIsa(NamedIntrinsic id)
174 return lookup(id).isa;
177 static int lookupIval(NamedIntrinsic id)
179 return lookup(id).ival;
182 static unsigned lookupSimdSize(NamedIntrinsic id)
184 return lookup(id).simdSize;
187 static int lookupNumArgs(NamedIntrinsic id)
189 return lookup(id).numArgs;
192 static instruction lookupIns(NamedIntrinsic id, var_types type)
194 assert((type >= TYP_BYTE) && (type <= TYP_DOUBLE));
195 return lookup(id).ins[type - TYP_BYTE];
198 static HWIntrinsicCategory lookupCategory(NamedIntrinsic id)
200 return lookup(id).category;
203 static HWIntrinsicFlag lookupFlags(NamedIntrinsic id)
205 return lookup(id).flags;
210 static bool IsCommutative(NamedIntrinsic id)
212 HWIntrinsicFlag flags = lookupFlags(id);
213 return (flags & HW_Flag_Commutative) != 0;
216 static bool HasFullRangeImm(NamedIntrinsic id)
218 HWIntrinsicFlag flags = lookupFlags(id);
219 return (flags & HW_Flag_FullRangeIMM) != 0;
222 static bool IsOneTypeGeneric(NamedIntrinsic id)
224 HWIntrinsicFlag flags = lookupFlags(id);
225 return (flags & HW_Flag_OneTypeGeneric) != 0;
228 static bool IsTwoTypeGeneric(NamedIntrinsic id)
230 HWIntrinsicFlag flags = lookupFlags(id);
231 return (flags & HW_Flag_TwoTypeGeneric) != 0;
234 static bool RequiresCodegen(NamedIntrinsic id)
236 HWIntrinsicFlag flags = lookupFlags(id);
237 return (flags & HW_Flag_NoCodeGen) == 0;
240 static bool HasFixedSimdSize(NamedIntrinsic id)
242 HWIntrinsicFlag flags = lookupFlags(id);
243 return (flags & HW_Flag_UnfixedSIMDSize) == 0;
246 static bool GeneratesMultipleIns(NamedIntrinsic id)
248 HWIntrinsicFlag flags = lookupFlags(id);
249 return (flags & HW_Flag_MultiIns) != 0;
252 static bool SupportsContainment(NamedIntrinsic id)
254 HWIntrinsicFlag flags = lookupFlags(id);
255 return (flags & HW_Flag_NoContainment) == 0;
258 static bool CopiesUpperBits(NamedIntrinsic id)
260 HWIntrinsicFlag flags = lookupFlags(id);
261 return (flags & HW_Flag_CopyUpperBits) != 0;
264 static bool BaseTypeFromFirstArg(NamedIntrinsic id)
266 HWIntrinsicFlag flags = lookupFlags(id);
267 return (flags & HW_Flag_BaseTypeFromFirstArg) != 0;
270 static bool IsFloatingPointUsed(NamedIntrinsic id)
272 HWIntrinsicFlag flags = lookupFlags(id);
273 return (flags & HW_Flag_NoFloatingPointUsed) == 0;
276 static bool MaybeImm(NamedIntrinsic id)
278 HWIntrinsicFlag flags = lookupFlags(id);
279 return (flags & HW_Flag_MaybeIMM) != 0;
282 static bool MaybeMemoryLoad(NamedIntrinsic id)
284 HWIntrinsicFlag flags = lookupFlags(id);
285 return (flags & HW_Flag_MaybeMemoryLoad) != 0;
288 static bool MaybeMemoryStore(NamedIntrinsic id)
290 HWIntrinsicFlag flags = lookupFlags(id);
291 return (flags & HW_Flag_MaybeMemoryStore) != 0;
294 static bool NoJmpTableImm(NamedIntrinsic id)
296 HWIntrinsicFlag flags = lookupFlags(id);
297 return (flags & HW_Flag_NoJmpTableIMM) != 0;
300 static bool Is64BitOnly(NamedIntrinsic id)
302 HWIntrinsicFlag flags = lookupFlags(id);
303 return (flags & HW_Flag_64BitOnly) != 0;
306 static bool SecondArgMaybe64Bit(NamedIntrinsic id)
308 HWIntrinsicFlag flags = lookupFlags(id);
309 return (flags & HW_Flag_SecondArgMaybe64Bit) != 0;
312 static bool BaseTypeFromSecondArg(NamedIntrinsic id)
314 HWIntrinsicFlag flags = lookupFlags(id);
315 return (flags & HW_Flag_BaseTypeFromSecondArg) != 0;
318 static bool HasSpecialCodegen(NamedIntrinsic id)
320 HWIntrinsicFlag flags = lookupFlags(id);
321 return (flags & HW_Flag_SpecialCodeGen) != 0;
324 static bool HasRMWSemantics(NamedIntrinsic id)
326 HWIntrinsicFlag flags = lookupFlags(id);
327 return (flags & HW_Flag_NoRMWSemantics) == 0;
330 static bool HasSpecialImport(NamedIntrinsic id)
332 HWIntrinsicFlag flags = lookupFlags(id);
333 return (flags & HW_Flag_SpecialImport) != 0;
337 #endif // FEATURE_HW_INTRINSICS
339 #endif // _HW_INTRINSIC_XARCH_H_