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
10enum 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
48enum 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 // NoCodeGen
61 // - should be transformed in the compiler front-end, cannot reach CodeGen
62 HW_Flag_NoCodeGen = 0x8,
63
64 // Unfixed SIMD-size
65 // - overloaded on multiple vector sizes (SIMD size in the table is unreliable)
66 HW_Flag_UnfixedSIMDSize = 0x10,
67
68 // Multi-instruction
69 // - that one intrinsic can generate multiple instructions
70 HW_Flag_MultiIns = 0x20,
71
72 // NoContainment
73 // the intrinsic cannot be handled by comtainment,
74 // all the intrinsic that have explicit memory load/store semantics should have this flag
75 HW_Flag_NoContainment = 0x40,
76
77 // Copy Upper bits
78 // some SIMD scalar intrinsics need the semantics of copying upper bits from the source operand
79 HW_Flag_CopyUpperBits = 0x80,
80
81 // Select base type using the first argument type
82 HW_Flag_BaseTypeFromFirstArg = 0x100,
83
84 // Indicates compFloatingPointUsed does not need to be set.
85 HW_Flag_NoFloatingPointUsed = 0x200,
86
87 // Maybe IMM
88 // the intrinsic has either imm or Vector overloads
89 HW_Flag_MaybeIMM = 0x400,
90
91 // NoJmpTable IMM
92 // the imm intrinsic does not need jumptable fallback when it gets non-const argument
93 HW_Flag_NoJmpTableIMM = 0x800,
94
95 // Select base type using the second argument type
96 HW_Flag_BaseTypeFromSecondArg = 0x1000,
97
98 // Special codegen
99 // the intrinsics need special rules in CodeGen,
100 // but may be table-driven in the front-end
101 HW_Flag_SpecialCodeGen = 0x2000,
102
103 // No Read/Modify/Write Semantics
104 // the intrinsic doesn't have read/modify/write semantics in two/three-operand form.
105 HW_Flag_NoRMWSemantics = 0x4000,
106
107 // Special import
108 // the intrinsics need special rules in importer,
109 // but may be table-driven in the back-end
110 HW_Flag_SpecialImport = 0x8000,
111
112 // Maybe Memory Load/Store
113 // - some intrinsics may have pointer overloads but without HW_Category_MemoryLoad/HW_Category_MemoryStore
114 HW_Flag_MaybeMemoryLoad = 0x10000,
115 HW_Flag_MaybeMemoryStore = 0x20000,
116};
117
118struct HWIntrinsicInfo
119{
120 NamedIntrinsic id;
121 const char* name;
122 InstructionSet isa;
123 int ival;
124 unsigned simdSize;
125 int numArgs;
126 instruction ins[10];
127 HWIntrinsicCategory category;
128 HWIntrinsicFlag flags;
129
130 static const HWIntrinsicInfo& lookup(NamedIntrinsic id);
131
132 static NamedIntrinsic lookupId(const char* className, const char* methodName, const char* enclosingClassName);
133 static InstructionSet lookupIsa(const char* className, const char* enclosingClassName);
134
135 static unsigned lookupSimdSize(Compiler* comp, NamedIntrinsic id, CORINFO_SIG_INFO* sig);
136
137 static int lookupNumArgs(const GenTreeHWIntrinsic* node);
138 static GenTree* lookupLastOp(const GenTreeHWIntrinsic* node);
139 static bool isImmOp(NamedIntrinsic id, const GenTree* op);
140
141 static int lookupImmUpperBound(NamedIntrinsic id);
142 static bool isInImmRange(NamedIntrinsic id, int ival);
143 static bool isAVX2GatherIntrinsic(NamedIntrinsic id);
144
145 static bool isFullyImplementedIsa(InstructionSet isa);
146 static bool isScalarIsa(InstructionSet isa);
147
148 // Member lookup
149
150 static NamedIntrinsic lookupId(NamedIntrinsic id)
151 {
152 return lookup(id).id;
153 }
154
155 static const char* lookupName(NamedIntrinsic id)
156 {
157 return lookup(id).name;
158 }
159
160 static InstructionSet lookupIsa(NamedIntrinsic id)
161 {
162 return lookup(id).isa;
163 }
164
165 static int lookupIval(NamedIntrinsic id)
166 {
167 return lookup(id).ival;
168 }
169
170 static unsigned lookupSimdSize(NamedIntrinsic id)
171 {
172 return lookup(id).simdSize;
173 }
174
175 static int lookupNumArgs(NamedIntrinsic id)
176 {
177 return lookup(id).numArgs;
178 }
179
180 static instruction lookupIns(NamedIntrinsic id, var_types type)
181 {
182 assert((type >= TYP_BYTE) && (type <= TYP_DOUBLE));
183 return lookup(id).ins[type - TYP_BYTE];
184 }
185
186 static HWIntrinsicCategory lookupCategory(NamedIntrinsic id)
187 {
188 return lookup(id).category;
189 }
190
191 static HWIntrinsicFlag lookupFlags(NamedIntrinsic id)
192 {
193 return lookup(id).flags;
194 }
195
196 // Flags lookup
197
198 static bool IsCommutative(NamedIntrinsic id)
199 {
200 HWIntrinsicFlag flags = lookupFlags(id);
201 return (flags & HW_Flag_Commutative) != 0;
202 }
203
204 static bool HasFullRangeImm(NamedIntrinsic id)
205 {
206 HWIntrinsicFlag flags = lookupFlags(id);
207 return (flags & HW_Flag_FullRangeIMM) != 0;
208 }
209
210 static bool RequiresCodegen(NamedIntrinsic id)
211 {
212 HWIntrinsicFlag flags = lookupFlags(id);
213 return (flags & HW_Flag_NoCodeGen) == 0;
214 }
215
216 static bool HasFixedSimdSize(NamedIntrinsic id)
217 {
218 HWIntrinsicFlag flags = lookupFlags(id);
219 return (flags & HW_Flag_UnfixedSIMDSize) == 0;
220 }
221
222 static bool GeneratesMultipleIns(NamedIntrinsic id)
223 {
224 HWIntrinsicFlag flags = lookupFlags(id);
225 return (flags & HW_Flag_MultiIns) != 0;
226 }
227
228 static bool SupportsContainment(NamedIntrinsic id)
229 {
230 HWIntrinsicFlag flags = lookupFlags(id);
231 return (flags & HW_Flag_NoContainment) == 0;
232 }
233
234 static bool CopiesUpperBits(NamedIntrinsic id)
235 {
236 HWIntrinsicFlag flags = lookupFlags(id);
237 return (flags & HW_Flag_CopyUpperBits) != 0;
238 }
239
240 static bool BaseTypeFromFirstArg(NamedIntrinsic id)
241 {
242 HWIntrinsicFlag flags = lookupFlags(id);
243 return (flags & HW_Flag_BaseTypeFromFirstArg) != 0;
244 }
245
246 static bool IsFloatingPointUsed(NamedIntrinsic id)
247 {
248 HWIntrinsicFlag flags = lookupFlags(id);
249 return (flags & HW_Flag_NoFloatingPointUsed) == 0;
250 }
251
252 static bool MaybeImm(NamedIntrinsic id)
253 {
254 HWIntrinsicFlag flags = lookupFlags(id);
255 return (flags & HW_Flag_MaybeIMM) != 0;
256 }
257
258 static bool MaybeMemoryLoad(NamedIntrinsic id)
259 {
260 HWIntrinsicFlag flags = lookupFlags(id);
261 return (flags & HW_Flag_MaybeMemoryLoad) != 0;
262 }
263
264 static bool MaybeMemoryStore(NamedIntrinsic id)
265 {
266 HWIntrinsicFlag flags = lookupFlags(id);
267 return (flags & HW_Flag_MaybeMemoryStore) != 0;
268 }
269
270 static bool NoJmpTableImm(NamedIntrinsic id)
271 {
272 HWIntrinsicFlag flags = lookupFlags(id);
273 return (flags & HW_Flag_NoJmpTableIMM) != 0;
274 }
275
276 static bool BaseTypeFromSecondArg(NamedIntrinsic id)
277 {
278 HWIntrinsicFlag flags = lookupFlags(id);
279 return (flags & HW_Flag_BaseTypeFromSecondArg) != 0;
280 }
281
282 static bool HasSpecialCodegen(NamedIntrinsic id)
283 {
284 HWIntrinsicFlag flags = lookupFlags(id);
285 return (flags & HW_Flag_SpecialCodeGen) != 0;
286 }
287
288 static bool HasRMWSemantics(NamedIntrinsic id)
289 {
290 HWIntrinsicFlag flags = lookupFlags(id);
291 return (flags & HW_Flag_NoRMWSemantics) == 0;
292 }
293
294 static bool HasSpecialImport(NamedIntrinsic id)
295 {
296 HWIntrinsicFlag flags = lookupFlags(id);
297 return (flags & HW_Flag_SpecialImport) != 0;
298 }
299};
300
301#endif // FEATURE_HW_INTRINSICS
302
303#endif // _HW_INTRINSIC_XARCH_H_
304