LLVM 24.0.0git
SPIRVLegalizerInfo.cpp
Go to the documentation of this file.
1//===- SPIRVLegalizerInfo.cpp --- SPIR-V Legalization Rules ------*- C++ -*-==//
2//
3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4// See https://llvm.org/LICENSE.txt for license information.
5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6//
7//===----------------------------------------------------------------------===//
8//
9// This file implements the targeting of the Machinelegalizer class for SPIR-V.
10//
11//===----------------------------------------------------------------------===//
12
13#include "SPIRVLegalizerInfo.h"
14#include "SPIRV.h"
15#include "SPIRVGlobalRegistry.h"
16#include "SPIRVSubtarget.h"
17#include "SPIRVUtils.h"
24#include "llvm/IR/IntrinsicsSPIRV.h"
25#include "llvm/Support/Debug.h"
28
29using namespace llvm;
30using namespace llvm::LegalizeActions;
31using namespace llvm::LegalityPredicates;
32
33#define DEBUG_TYPE "spirv-legalizer"
34
35LegalityPredicate typeOfExtendedScalars(unsigned TypeIdx, bool IsExtendedInts) {
36 return [IsExtendedInts, TypeIdx](const LegalityQuery &Query) {
37 const LLT Ty = Query.Types[TypeIdx];
38 return IsExtendedInts && Ty.isValid() && Ty.isScalar();
39 };
40}
41
42LegalityPredicate typeOfLongVectors(unsigned TypeIdx, bool IsLongVecs) {
43 return [TypeIdx, IsLongVecs](const LegalityQuery &Query) {
44 const LLT Ty = Query.Types[TypeIdx];
45 return IsLongVecs && Ty.isValid() && Ty.isVector();
46 };
47}
48
50 using namespace TargetOpcode;
51
52 this->ST = &ST;
53 GR = ST.getSPIRVGlobalRegistry();
54
55 const LLT s1 = LLT::scalar(1);
56 const LLT s8 = LLT::scalar(8);
57 const LLT s16 = LLT::scalar(16);
58 const LLT s32 = LLT::scalar(32);
59 const LLT s64 = LLT::scalar(64);
60 const LLT s128 = LLT::scalar(128);
61
62 const LLT v16s64 = LLT::fixed_vector(16, 64);
63 const LLT v16s32 = LLT::fixed_vector(16, 32);
64 const LLT v16s16 = LLT::fixed_vector(16, 16);
65 const LLT v16s8 = LLT::fixed_vector(16, 8);
66 const LLT v16s1 = LLT::fixed_vector(16, 1);
67
68 const LLT v8s64 = LLT::fixed_vector(8, 64);
69 const LLT v8s32 = LLT::fixed_vector(8, 32);
70 const LLT v8s16 = LLT::fixed_vector(8, 16);
71 const LLT v8s8 = LLT::fixed_vector(8, 8);
72 const LLT v8s1 = LLT::fixed_vector(8, 1);
73
74 const LLT v4s64 = LLT::fixed_vector(4, 64);
75 const LLT v4s32 = LLT::fixed_vector(4, 32);
76 const LLT v4s16 = LLT::fixed_vector(4, 16);
77 const LLT v4s8 = LLT::fixed_vector(4, 8);
78 const LLT v4s1 = LLT::fixed_vector(4, 1);
79
80 const LLT v3s64 = LLT::fixed_vector(3, 64);
81 const LLT v3s32 = LLT::fixed_vector(3, 32);
82 const LLT v3s16 = LLT::fixed_vector(3, 16);
83 const LLT v3s8 = LLT::fixed_vector(3, 8);
84 const LLT v3s1 = LLT::fixed_vector(3, 1);
85
86 const LLT v2s64 = LLT::fixed_vector(2, 64);
87 const LLT v2s32 = LLT::fixed_vector(2, 32);
88 const LLT v2s16 = LLT::fixed_vector(2, 16);
89 const LLT v2s8 = LLT::fixed_vector(2, 8);
90 const LLT v2s1 = LLT::fixed_vector(2, 1);
91
92 const unsigned PSize = ST.getPointerSize();
93 const LLT p0 = LLT::pointer(SPIRVAS::Function, PSize);
94 const LLT p1 = LLT::pointer(SPIRVAS::CrossWorkgroup, PSize);
95 const LLT p2 = LLT::pointer(SPIRVAS::UniformConstant, PSize);
96 const LLT p3 = LLT::pointer(SPIRVAS::Workgroup, PSize);
97 const LLT p4 = LLT::pointer(SPIRVAS::Generic, PSize);
98 const LLT p5 = LLT::pointer(SPIRVAS::DeviceOnlyINTEL, PSize);
99 const LLT p6 = LLT::pointer(SPIRVAS::HostOnlyINTEL, PSize);
100 const LLT p7 = LLT::pointer(SPIRVAS::Input, PSize);
101 const LLT p8 = LLT::pointer(SPIRVAS::Output, PSize);
102 const LLT p9 = LLT::pointer(SPIRVAS::CodeSectionINTEL, PSize);
103 const LLT p10 = LLT::pointer(SPIRVAS::Private, PSize);
104 const LLT p11 = LLT::pointer(SPIRVAS::StorageBuffer, PSize);
105 const LLT p12 = LLT::pointer(SPIRVAS::Uniform, PSize);
106 const LLT p13 = LLT::pointer(SPIRVAS::PushConstant, PSize);
107
108 // TODO: remove copy-pasting here by using concatenation in some way.
109 auto allPtrsScalarsAndVectors = {
110 p0, p1, p2, p3, p4, p5, p6, p7, p8,
111 p9, p10, p11, p12, p13, s1, s8, s16, s32,
112 s64, s128, v2s1, v2s8, v2s16, v2s32, v2s64, v3s1, v3s8,
113 v3s16, v3s32, v3s64, v4s1, v4s8, v4s16, v4s32, v4s64, v8s1,
114 v8s8, v8s16, v8s32, v8s64, v16s1, v16s8, v16s16, v16s32, v16s64};
115
116 auto allVectors = {v2s1, v2s8, v2s16, v2s32, v2s64, v3s1, v3s8,
117 v3s16, v3s32, v3s64, v4s1, v4s8, v4s16, v4s32,
118 v4s64, v8s1, v8s8, v8s16, v8s32, v8s64, v16s1,
119 v16s8, v16s16, v16s32, v16s64};
120
121 auto allShaderVectors = {v2s1, v2s8, v2s16, v2s32, v2s64,
122 v3s1, v3s8, v3s16, v3s32, v3s64,
123 v4s1, v4s8, v4s16, v4s32, v4s64};
124
125 auto allScalars = {s1, s8, s16, s32, s64};
126
127 auto allScalarsAndVectors = {
128 s1, s8, s16, s32, s64, s128, v2s1, v2s8,
129 v2s16, v2s32, v2s64, v3s1, v3s8, v3s16, v3s32, v3s64,
130 v4s1, v4s8, v4s16, v4s32, v4s64, v8s1, v8s8, v8s16,
131 v8s32, v8s64, v16s1, v16s8, v16s16, v16s32, v16s64};
132
133 auto allShaderScalarsAndVectors = {
134 s1, s8, s16, s32, s64, s128, v2s1, v2s8, v2s16, v2s32, v2s64,
135 v3s1, v3s8, v3s16, v3s32, v3s64, v4s1, v4s8, v4s16, v4s32, v4s64};
136
137 auto &allowedScalarsAndVectors =
138 ST.isShader() ? allShaderScalarsAndVectors : allScalarsAndVectors;
139
140 auto allIntScalarsAndVectors = {
141 s8, s16, s32, s64, s128, v2s8, v2s16, v2s32, v2s64,
142 v3s8, v3s16, v3s32, v3s64, v4s8, v4s16, v4s32, v4s64, v8s8,
143 v8s16, v8s32, v8s64, v16s8, v16s16, v16s32, v16s64};
144
145 auto allBoolScalarsAndVectors = {s1, v2s1, v3s1, v4s1, v8s1, v16s1};
146 auto allBoolVectors = {v2s1, v3s1, v4s1, v8s1, v16s1};
147
148 auto allIntScalars = {s8, s16, s32, s64, s128};
149
150 auto allShaderIntVectors = {v2s8, v2s16, v2s32, v2s64, v3s8, v3s16,
151 v3s32, v3s64, v4s8, v4s16, v4s32, v4s64};
152
153 auto allIntVectors = {v2s8, v2s16, v2s32, v2s64, v3s8, v3s16, v3s32,
154 v3s64, v4s8, v4s16, v4s32, v4s64, v8s8, v8s16,
155 v8s32, v8s64, v16s8, v16s16, v16s32, v16s64};
156
157 auto &allowedIntVectorTypes =
158 ST.isShader() ? allShaderIntVectors : allIntVectors;
159
160 auto allFloatScalarsAndF16Vector2AndVector4s = {s16, s32, s64, v2s16, v4s16};
161
162 auto allFloatScalars = {s16, s32, s64};
163
164 auto allFloatScalarsAndVectors = {
165 s16, s32, s64, v2s16, v2s32, v2s64, v3s16, v3s32, v3s64,
166 v4s16, v4s32, v4s64, v8s16, v8s32, v8s64, v16s16, v16s32, v16s64};
167
168 auto allShaderFloatVectors = {v2s16, v2s32, v2s64, v3s16, v3s32,
169 v3s64, v4s16, v4s32, v4s64};
170
171 auto allFloatVectors = {v2s16, v2s32, v2s64, v3s16, v3s32,
172 v3s64, v4s16, v4s32, v4s64, v8s16,
173 v8s32, v8s64, v16s16, v16s32, v16s64};
174
175 auto &allowedFloatVectorTypes =
176 ST.isShader() ? allShaderFloatVectors : allFloatVectors;
177
178 auto allFloatAndIntScalarsAndPtrs = {s8, s16, s32, s64, p0, p1,
179 p2, p3, p4, p5, p6, p7,
180 p8, p9, p10, p11, p12, p13};
181
182 auto allPtrs = {p0, p1, p2, p3, p4, p5, p6, p7, p8, p9, p10, p11, p12, p13};
183
184 auto &allowedVectorTypes = ST.isShader() ? allShaderVectors : allVectors;
185
186 bool HasArbitraryPrecisionInts = ST.canUseExtension(
187 SPIRV::Extension::SPV_ALTERA_arbitrary_precision_integers);
188 bool IsExtendedInts =
189 HasArbitraryPrecisionInts ||
190 ST.canUseExtension(SPIRV::Extension::SPV_KHR_bit_instructions) ||
191 ST.canUseExtension(SPIRV::Extension::SPV_INTEL_int4);
192 bool IsLongVecs = ST.canUseExtension(SPIRV::Extension::SPV_EXT_long_vector);
193 auto ExtendedIntScalarsAndVectors =
194 [IsExtendedInts](const LegalityQuery &Query) {
195 const LLT Ty = Query.Types[0];
196 return IsExtendedInts && Ty.isValid() &&
197 !Ty.isPointerOrPointerVector() && Ty.getScalarSizeInBits() > 1;
198 };
199 auto ExtendedScalarsAndVectorsProduct = [IsExtendedInts](
200 const LegalityQuery &Query) {
201 const LLT Ty1 = Query.Types[0], Ty2 = Query.Types[1];
202 return IsExtendedInts && Ty1.isValid() && Ty2.isValid() &&
203 !Ty1.isPointerOrPointerVector() && !Ty2.isPointerOrPointerVector();
204 };
205 auto ExtendedPtrsScalarsAndVectors =
206 [IsExtendedInts](const LegalityQuery &Query) {
207 const LLT Ty = Query.Types[0];
208 return IsExtendedInts && Ty.isValid();
209 };
210
211 // The universal validation rules in the SPIR-V specification state that
212 // vector sizes are typically limited to 2, 3, or 4. However, larger vector
213 // sizes (8 and 16) are enabled when the Kernel capability is present. For
214 // shader execution models, vector sizes are strictly limited to 4. In
215 // non-shader contexts, vector sizes of 8 and 16 are also permitted, but
216 // arbitrary sizes (e.g., 6 or 11) are not.
217 uint32_t MaxVectorSize = ST.isShader() ? 4 : 16;
218 LLVM_DEBUG(dbgs() << "MaxVectorSize: " << MaxVectorSize << "\n");
219
220 for (auto Opc : getTypeFoldingSupportedOpcodes()) {
221 switch (Opc) {
222 case G_EXTRACT_VECTOR_ELT:
223 case G_UREM:
224 case G_SREM:
225 case G_UDIV:
226 case G_SDIV:
227 case G_FREM:
228 case G_SELECT:
229 break;
230 default:
232 .customFor(allScalars)
233 .customFor(allowedVectorTypes)
234 .customIf(typeOfLongVectors(0, IsLongVecs))
238 0, ElementCount::getFixed(MaxVectorSize)))
239 .custom();
240 break;
241 }
242 }
243
244 getActionDefinitionsBuilder({G_UREM, G_SREM, G_SDIV, G_UDIV, G_FREM})
245 .customFor(allScalars)
246 .customFor(allowedVectorTypes)
247 .customIf(typeOfLongVectors(0, IsLongVecs))
251 0, ElementCount::getFixed(MaxVectorSize)))
252 .custom();
253
255 .customFor(allScalars)
256 .customFor(allowedVectorTypes)
257 .customIf(typeOfLongVectors(0, IsLongVecs))
260 0, ElementCount::getFixed(MaxVectorSize)))
261 .custom();
262
263 getActionDefinitionsBuilder({G_FMA, G_STRICT_FMA})
264 .legalFor(allScalars)
265 .legalFor(allowedVectorTypes)
266 .legalIf(typeOfLongVectors(0, IsLongVecs))
270 0, ElementCount::getFixed(MaxVectorSize)))
271 .alwaysLegal();
272
273 getActionDefinitionsBuilder(G_INTRINSIC_W_SIDE_EFFECTS).custom();
274
275 getActionDefinitionsBuilder(G_SHUFFLE_VECTOR)
276 .legalForCartesianProduct(allowedVectorTypes, allowedVectorTypes)
277 .legalIf(typeOfLongVectors(0, IsLongVecs))
278 .legalIf(typeOfLongVectors(1, IsLongVecs))
280 .lowerIf(vectorElementCountIsGreaterThan(0, MaxVectorSize))
282 .lowerIf(vectorElementCountIsGreaterThan(1, MaxVectorSize));
283
284 getActionDefinitionsBuilder(G_EXTRACT_VECTOR_ELT)
285 .customIf(typeOfLongVectors(1, IsLongVecs))
289 1, ElementCount::getFixed(MaxVectorSize)))
290 .custom();
291
292 getActionDefinitionsBuilder(G_INSERT_VECTOR_ELT)
293 .customIf(typeOfLongVectors(0, IsLongVecs))
297 0, ElementCount::getFixed(MaxVectorSize)))
298 .custom();
299
300 // Illegal G_UNMERGE_VALUES instructions should be handled
301 // during the combine phase.
302 getActionDefinitionsBuilder(G_BUILD_VECTOR)
303 .legalIf(typeOfLongVectors(0, IsLongVecs))
307 0, ElementCount::getFixed(MaxVectorSize)));
308
309 // When entering the legalizer, there should be no G_BITCAST instructions.
310 // They should all be calls to the `spv_bitcast` intrinsic. The call to
311 // the intrinsic will be converted to a G_BITCAST during legalization if
312 // the vectors are not legal. After using the rules to legalize a G_BITCAST,
313 // we turn it back into a call to the intrinsic with a custom rule to avoid
314 // potential machine verifier failures.
316 .customIf(typeOfLongVectors(0, IsLongVecs))
321 0, ElementCount::getFixed(MaxVectorSize)))
322 .lowerIf(vectorElementCountIsGreaterThan(1, MaxVectorSize))
323 .custom();
324
325 // If the result is still illegal, the combiner should be able to remove it.
326 getActionDefinitionsBuilder(G_CONCAT_VECTORS)
327 .legalForCartesianProduct(allowedVectorTypes, allowedVectorTypes)
329 typeOfLongVectors(1, IsLongVecs)));
330
331 getActionDefinitionsBuilder(G_SPLAT_VECTOR)
332 .legalFor(allowedVectorTypes)
333 .legalIf(typeOfLongVectors(0, IsLongVecs))
337 .alwaysLegal();
338
339 // Vector Reduction Operations
341 {G_VECREDUCE_SMIN, G_VECREDUCE_SMAX, G_VECREDUCE_UMIN, G_VECREDUCE_UMAX,
342 G_VECREDUCE_ADD, G_VECREDUCE_MUL, G_VECREDUCE_FMUL, G_VECREDUCE_FMIN,
343 G_VECREDUCE_FMAX, G_VECREDUCE_FMINIMUM, G_VECREDUCE_FMAXIMUM,
344 G_VECREDUCE_OR, G_VECREDUCE_AND, G_VECREDUCE_XOR})
345 .legalFor(allowedVectorTypes)
346 .legalIf(typeOfLongVectors(0, IsLongVecs))
347 .scalarize(1)
348 .lower();
349
350 getActionDefinitionsBuilder({G_VECREDUCE_SEQ_FADD, G_VECREDUCE_SEQ_FMUL})
351 .scalarize(2)
352 .lower();
353
354 // Illegal G_UNMERGE_VALUES instructions should be handled
355 // during the combine phase.
356 getActionDefinitionsBuilder(G_UNMERGE_VALUES)
358 typeOfLongVectors(1, IsLongVecs)))
360
361 getActionDefinitionsBuilder({G_MEMCPY, G_MEMCPY_INLINE, G_MEMMOVE})
362 .unsupportedIf(LegalityPredicates::any(typeIs(0, p9), typeIs(1, p9)))
363 .legalIf(all(typeInSet(0, allPtrs), typeInSet(1, allPtrs)));
364
365 getActionDefinitionsBuilder({G_MEMSET, G_MEMSET_INLINE})
366 .unsupportedIf(typeIs(0, p9))
367 .legalIf(all(typeInSet(0, allPtrs), typeInSet(1, allIntScalars)));
368
369 getActionDefinitionsBuilder(G_ADDRSPACE_CAST)
370 .legalForCartesianProduct(allPtrs, allPtrs);
371
372 // Should we be legalizing bad scalar sizes like s5 here instead
373 // of handling them in the instruction selector?
374 getActionDefinitionsBuilder({G_LOAD, G_STORE})
375 .unsupportedIf(typeIs(1, p9))
376 .legalForCartesianProduct(allowedVectorTypes, allPtrs)
377 .legalForCartesianProduct(allPtrs, allPtrs)
378 .legalIf(isScalar(0))
379 .legalIf(typeOfLongVectors(0, IsLongVecs))
380 .custom();
381
382 getActionDefinitionsBuilder({G_SMIN, G_SMAX, G_UMIN, G_UMAX, G_ABS,
383 G_BITREVERSE, G_SADDSAT, G_UADDSAT, G_SSUBSAT,
384 G_USUBSAT, G_SCMP, G_UCMP})
385 .legalFor(allIntScalars)
386 .legalFor(allowedIntVectorTypes)
387 .legalIf(ExtendedIntScalarsAndVectors)
388 // LLVM i1 maps to OpTypeBool, not OpTypeInt.
389 .scalarizeIf(typeInSet(0, allBoolVectors), 0)
390 .minScalar(0, s32)
393 0, ElementCount::getFixed(MaxVectorSize)))
395
396 getActionDefinitionsBuilder({G_SSHLSAT, G_USHLSAT}).lower();
397
398 getActionDefinitionsBuilder({G_FLDEXP, G_STRICT_FLDEXP})
399 .legalForCartesianProduct(allFloatScalarsAndVectors, allIntScalars);
400
401 getActionDefinitionsBuilder({G_FPTOSI, G_FPTOUI})
402 .legalForCartesianProduct(allIntScalarsAndVectors,
403 allFloatScalarsAndVectors);
404
405 getActionDefinitionsBuilder({G_FPTOSI_SAT, G_FPTOUI_SAT})
406 .legalForCartesianProduct(allIntScalarsAndVectors,
407 allFloatScalarsAndVectors);
408
409 getActionDefinitionsBuilder({G_SITOFP, G_UITOFP})
410 .legalForCartesianProduct(allFloatScalarsAndVectors,
411 allScalarsAndVectors);
412
414 .legalForCartesianProduct(allIntScalarsAndVectors)
415 .legalIf(ExtendedScalarsAndVectorsProduct)
416 .legalIf(typeOfLongVectors(0, IsLongVecs));
417
418 getActionDefinitionsBuilder({G_TRUNC, G_ZEXT, G_SEXT, G_ANYEXT})
419 .legalForCartesianProduct(allowedScalarsAndVectors)
420 .legalIf(ExtendedScalarsAndVectorsProduct)
421 .legalIf(typeOfLongVectors(0, IsLongVecs))
425 0, ElementCount::getFixed(MaxVectorSize)));
426
427 getActionDefinitionsBuilder(G_SEXT_INREG)
428 .lowerIf(typeOfLongVectors(0, IsLongVecs))
432 0, ElementCount::getFixed(MaxVectorSize)))
433 .lower();
434
436 .legalIf(typeOfLongVectors(0, IsLongVecs))
439 0, ElementCount::getFixed(MaxVectorSize)))
440 .legalFor(allPtrsScalarsAndVectors)
441 .legalIf(ExtendedPtrsScalarsAndVectors)
443
445 all(typeInSet(0, allPtrsScalarsAndVectors),
446 typeInSet(1, allPtrsScalarsAndVectors)));
447
448 getActionDefinitionsBuilder({G_IMPLICIT_DEF, G_FREEZE})
449 .legalFor({s1, s128})
450 .legalFor(allFloatAndIntScalarsAndPtrs)
451 .legalFor(allowedVectorTypes)
452 .legalIf([](const LegalityQuery &Query) {
453 return Query.Types[0].isPointerVector();
454 })
455 .legalIf(typeOfLongVectors(0, IsLongVecs))
459 0, ElementCount::getFixed(MaxVectorSize)));
460
461 getActionDefinitionsBuilder({G_STACKSAVE, G_STACKRESTORE}).alwaysLegal();
462
464 .legalForCartesianProduct(allPtrs, allIntScalars)
465 .legalIf(
466 all(typeInSet(0, allPtrs), typeOfExtendedScalars(1, IsExtendedInts)))
467 .legalIf([](const LegalityQuery &Query) {
468 const LLT DstTy = Query.Types[0];
469 const LLT SrcTy = Query.Types[1];
470 return DstTy.isPointerVector() && SrcTy.isVector() &&
471 !SrcTy.isPointer() &&
472 DstTy.getNumElements() == SrcTy.getNumElements();
473 });
475 .legalForCartesianProduct(allIntScalars, allPtrs)
476 .legalIf(
477 all(typeOfExtendedScalars(0, IsExtendedInts), typeInSet(1, allPtrs)))
478 .legalIf([](const LegalityQuery &Query) {
479 const LLT DstTy = Query.Types[0];
480 const LLT SrcTy = Query.Types[1];
481 return SrcTy.isPointerVector() && DstTy.isVector() &&
482 !DstTy.isPointer() &&
483 DstTy.getNumElements() == SrcTy.getNumElements();
484 });
486 .legalForCartesianProduct(allPtrs, allIntScalars)
487 .legalIf(
488 all(typeInSet(0, allPtrs), typeOfExtendedScalars(1, IsExtendedInts)));
489
491 .legalForCartesianProduct(allPtrs, allIntScalars)
492 .legalIf(
493 all(typeInSet(0, allPtrs), typeOfExtendedScalars(1, IsExtendedInts)))
494 .legalIf([](const LegalityQuery &Query) {
495 const LLT PtrTy = Query.Types[0];
496 const LLT MaskTy = Query.Types[1];
497 return PtrTy.isPointerVector() && MaskTy.isVector() &&
498 !MaskTy.isPointer() &&
499 PtrTy.getNumElements() == MaskTy.getNumElements();
500 });
501
502 // ST.canDirectlyComparePointers() for pointer args is supported in
503 // legalizeCustom().
506 all(typeIs(0, p9), typeInSet(1, allPtrs), typeIsNot(1, p9)),
507 all(typeInSet(0, allPtrs), typeIsNot(0, p9), typeIs(1, p9))))
510 1, ElementCount::getFixed(MaxVectorSize)))
511 .legalIf([IsExtendedInts](const LegalityQuery &Query) {
512 const LLT Ty = Query.Types[1];
513 return IsExtendedInts && Ty.isValid() && !Ty.isPointerOrPointerVector();
514 })
515 .customIf(all(typeInSet(0, allBoolScalarsAndVectors),
516 typeInSet(1, allPtrsScalarsAndVectors)));
517
521 1, ElementCount::getFixed(MaxVectorSize)))
522 .legalIf(all(typeInSet(0, allBoolScalarsAndVectors),
523 typeInSet(1, allFloatScalarsAndVectors)))
525
526 getActionDefinitionsBuilder({G_ATOMICRMW_OR, G_ATOMICRMW_ADD, G_ATOMICRMW_AND,
527 G_ATOMICRMW_MAX, G_ATOMICRMW_MIN,
528 G_ATOMICRMW_SUB, G_ATOMICRMW_XOR,
529 G_ATOMICRMW_UMAX, G_ATOMICRMW_UMIN})
530 .legalForCartesianProduct(allIntScalars, allPtrs);
531
533 {G_ATOMICRMW_FADD, G_ATOMICRMW_FSUB, G_ATOMICRMW_FMIN, G_ATOMICRMW_FMAX})
534 .legalForCartesianProduct(allFloatScalarsAndF16Vector2AndVector4s,
535 allPtrs);
536
537 getActionDefinitionsBuilder(G_ATOMICRMW_XCHG)
538 .legalForCartesianProduct(allFloatAndIntScalarsAndPtrs, allPtrs);
539
540 getActionDefinitionsBuilder(G_ATOMIC_CMPXCHG_WITH_SUCCESS).lower();
541 // TODO: add proper legalization rules.
542 getActionDefinitionsBuilder(G_ATOMIC_CMPXCHG).alwaysLegal();
544
545 getActionDefinitionsBuilder({G_UADDO, G_USUBO, G_UMULO, G_SMULO})
546 .alwaysLegal();
547
548 getActionDefinitionsBuilder({G_SADDO, G_SSUBO}).lower();
549
550 // Lowering widens s64 to s128, which needs
551 // SPV_ALTERA_arbitrary_precision_integers. Mark s64 unsupported otherwise.
552 auto &MulFix = getActionDefinitionsBuilder({G_SMULFIX, G_UMULFIX});
553 if (!HasArbitraryPrecisionInts)
554 MulFix.unsupportedFor({s64});
555 MulFix.lower();
556
557 getActionDefinitionsBuilder({G_LROUND, G_LLROUND})
558 .legalForCartesianProduct(allIntScalarsAndVectors,
559 allFloatScalarsAndVectors);
560
561 // FP conversions.
562 getActionDefinitionsBuilder({G_FPTRUNC, G_FPEXT})
563 .legalForCartesianProduct(allFloatScalarsAndVectors);
564
565 // Pointer-handling.
566 getActionDefinitionsBuilder(G_FRAME_INDEX).legalFor({p0});
567
568 getActionDefinitionsBuilder(G_GLOBAL_VALUE).legalFor(allPtrs);
569
570 // Control-flow. In some cases (e.g. constants) s1 may be promoted to s32.
572 getActionDefinitionsBuilder(G_BRCOND).legalFor({s1, s32});
573
575 allFloatScalarsAndVectors, {s32, v2s32, v3s32, v4s32, v8s32, v16s32});
576
577 // TODO: Review the target OpenCL and GLSL Extended Instruction Set specs to
578 // tighten these requirements. Many of these math functions are only legal on
579 // specific bitwidths, so they are not selectable for
580 // allFloatScalarsAndVectors.
581 // clang-format off
582 getActionDefinitionsBuilder({G_STRICT_FSQRT,
583 G_FPOW,
584 G_FEXP,
585 G_FMODF,
586 G_FSINCOS,
587 G_FEXP2,
588 G_FEXP10,
589 G_FLOG,
590 G_FLOG2,
591 G_FLOG10,
592 G_FABS,
593 G_FMINNUM,
594 G_FMAXNUM,
595 G_FCEIL,
596 G_FCOS,
597 G_FSIN,
598 G_FTAN,
599 G_FACOS,
600 G_FASIN,
601 G_FATAN,
602 G_FATAN2,
603 G_FCOSH,
604 G_FSINH,
605 G_FTANH,
606 G_FSQRT,
607 G_FFLOOR,
608 G_FRINT,
609 G_FNEARBYINT,
610 G_INTRINSIC_ROUND,
611 G_INTRINSIC_TRUNC,
612 G_INTRINSIC_ROUNDEVEN})
613 .legalFor(allFloatScalars)
614 .legalFor(allowedFloatVectorTypes)
617 0, ElementCount::getFixed(MaxVectorSize)))
619 // clang-format on
620
621 getActionDefinitionsBuilder(G_FCOPYSIGN)
622 .legalForCartesianProduct(allFloatScalarsAndVectors,
623 allFloatScalarsAndVectors)
626 0, ElementCount::getFixed(MaxVectorSize)))
628
630 allFloatScalarsAndVectors, allIntScalarsAndVectors);
631
632 if (ST.canUseExtInstSet(SPIRV::InstructionSet::OpenCL_std)) {
634 {G_CTTZ, G_CTTZ_ZERO_POISON, G_CTLZ, G_CTLZ_ZERO_POISON})
635 .legalForCartesianProduct(allIntScalarsAndVectors,
636 allIntScalarsAndVectors);
637
638 // Struct return types become a single scalar, so cannot easily legalize.
639 getActionDefinitionsBuilder({G_SMULH, G_UMULH}).alwaysLegal();
640 }
641
642 getActionDefinitionsBuilder(G_IS_FPCLASS).custom();
643
644 getActionDefinitionsBuilder({G_INTRINSIC, G_INTRINSIC_CONVERGENT,
645 G_INTRINSIC_CONVERGENT_W_SIDE_EFFECTS})
646 .alwaysLegal();
648 getActionDefinitionsBuilder({G_TRAP, G_DEBUGTRAP, G_UBSANTRAP}).alwaysLegal();
649
650 verify(*ST.getInstrInfo());
651}
652
654 MachineInstr &MI) {
655 MachineIRBuilder &MIRBuilder = Helper.MIRBuilder;
656 Register DstReg = MI.getOperand(0).getReg();
657 Register SrcReg = MI.getOperand(1).getReg();
658 Register IdxReg = MI.getOperand(2).getReg();
659
660 MIRBuilder
661 .buildIntrinsic(Intrinsic::spv_extractelt, ArrayRef<Register>{DstReg})
662 .addUse(SrcReg)
663 .addUse(IdxReg);
664 MI.eraseFromParent();
665 return true;
666}
667
669 MachineIRBuilder &MIRBuilder = Helper.MIRBuilder;
670 Register DstReg = MI.getOperand(0).getReg();
671 Register SrcReg = MI.getOperand(1).getReg();
672 Register ValReg = MI.getOperand(2).getReg();
673 Register IdxReg = MI.getOperand(3).getReg();
674
675 MIRBuilder
676 .buildIntrinsic(Intrinsic::spv_insertelt, ArrayRef<Register>{DstReg})
677 .addUse(SrcReg)
678 .addUse(ValReg)
679 .addUse(IdxReg);
680 MI.eraseFromParent();
681 return true;
682}
683
685 LegalizerHelper &Helper,
688 Register ConvReg = MRI.createGenericVirtualRegister(ConvTy);
689 MRI.setRegClass(ConvReg, GR->getRegClass(SpvType));
690 GR->assignSPIRVTypeToVReg(SpvType, ConvReg, Helper.MIRBuilder.getMF());
691 Helper.MIRBuilder.buildInstr(TargetOpcode::G_PTRTOINT)
692 .addDef(ConvReg)
693 .addUse(Reg);
694 return ConvReg;
695}
696
697static bool needsVectorLegalization(const LLT &Ty, const SPIRVSubtarget &ST) {
698 if (!Ty.isVector() ||
699 ST.canUseExtension(SPIRV::Extension::SPV_EXT_long_vector))
700 return false;
701 unsigned NumElements = Ty.getNumElements();
702 unsigned MaxVectorSize = ST.isShader() ? 4 : 16;
703 return (NumElements > 4 && !isPowerOf2_32(NumElements)) ||
704 NumElements > MaxVectorSize;
705}
706
709 MachineRegisterInfo &MRI = MI.getMF()->getRegInfo();
710 MachineIRBuilder &MIRBuilder = Helper.MIRBuilder;
711 Register DstReg = MI.getOperand(0).getReg();
712 Register PtrReg = MI.getOperand(1).getReg();
713 LLT DstTy = MRI.getType(DstReg);
714
715 if (!DstTy.isVector())
716 return true;
717
718 const SPIRVSubtarget &ST = MI.getMF()->getSubtarget<SPIRVSubtarget>();
719 if (!needsVectorLegalization(DstTy, ST))
720 return true;
721
722 SmallVector<Register, 8> SplitRegs;
723 LLT EltTy = DstTy.getElementType();
724 unsigned NumElts = DstTy.getNumElements();
725
726 LLT PtrTy = MRI.getType(PtrReg);
727 auto Zero = MIRBuilder.buildConstant(LLT::scalar(32), 0);
728
729 for (unsigned i = 0; i < NumElts; ++i) {
730 auto Idx = MIRBuilder.buildConstant(LLT::scalar(32), i);
731 Register EltPtr = MRI.createGenericVirtualRegister(PtrTy);
732
733 MIRBuilder.buildIntrinsic(Intrinsic::spv_gep, ArrayRef<Register>{EltPtr})
734 .addImm(1) // InBounds
735 .addUse(PtrReg)
736 .addUse(Zero.getReg(0))
737 .addUse(Idx.getReg(0));
738
739 MachinePointerInfo EltPtrInfo;
740 Align EltAlign = Align(1);
741 if (!MI.memoperands_empty()) {
742 MachineMemOperand *MMO = *MI.memoperands_begin();
743 EltPtrInfo =
744 MMO->getPointerInfo().getWithOffset(i * EltTy.getSizeInBytes());
745 EltAlign = commonAlignment(MMO->getAlign(), i * EltTy.getSizeInBytes());
746 }
747
748 Register EltReg = MRI.createGenericVirtualRegister(EltTy);
749 MIRBuilder.buildLoad(EltReg, EltPtr, EltPtrInfo, EltAlign);
750 SplitRegs.push_back(EltReg);
751 }
752
753 MIRBuilder.buildBuildVector(DstReg, SplitRegs);
754 MI.eraseFromParent();
755 return true;
756}
757
760 MachineRegisterInfo &MRI = MI.getMF()->getRegInfo();
761 MachineIRBuilder &MIRBuilder = Helper.MIRBuilder;
762 Register ValReg = MI.getOperand(0).getReg();
763 Register PtrReg = MI.getOperand(1).getReg();
764 LLT ValTy = MRI.getType(ValReg);
765
766 assert(ValTy.isVector() && "Expected vector store");
767
768 SmallVector<Register, 8> SplitRegs;
769 LLT EltTy = ValTy.getElementType();
770 unsigned NumElts = ValTy.getNumElements();
771
772 for (unsigned i = 0; i < NumElts; ++i)
773 SplitRegs.push_back(MRI.createGenericVirtualRegister(EltTy));
774
775 MIRBuilder.buildUnmerge(SplitRegs, ValReg);
776
777 LLT PtrTy = MRI.getType(PtrReg);
778 auto Zero = MIRBuilder.buildConstant(LLT::scalar(32), 0);
779
780 for (unsigned i = 0; i < NumElts; ++i) {
781 auto Idx = MIRBuilder.buildConstant(LLT::scalar(32), i);
782 Register EltPtr = MRI.createGenericVirtualRegister(PtrTy);
783
784 MIRBuilder.buildIntrinsic(Intrinsic::spv_gep, ArrayRef<Register>{EltPtr})
785 .addImm(1) // InBounds
786 .addUse(PtrReg)
787 .addUse(Zero.getReg(0))
788 .addUse(Idx.getReg(0));
789
790 MachinePointerInfo EltPtrInfo;
791 Align EltAlign = Align(1);
792 if (!MI.memoperands_empty()) {
793 MachineMemOperand *MMO = *MI.memoperands_begin();
794 EltPtrInfo =
795 MMO->getPointerInfo().getWithOffset(i * EltTy.getSizeInBytes());
796 EltAlign = commonAlignment(MMO->getAlign(), i * EltTy.getSizeInBytes());
797 }
798
799 MIRBuilder.buildStore(SplitRegs[i], EltPtr, EltPtrInfo, EltAlign);
800 }
801
802 MI.eraseFromParent();
803 return true;
804}
805
808 LostDebugLocObserver &LocObserver) const {
809 MachineRegisterInfo &MRI = MI.getMF()->getRegInfo();
810 switch (MI.getOpcode()) {
811 default:
812 // TODO: implement legalization for other opcodes.
813 return true;
814 case TargetOpcode::G_BITCAST:
815 return legalizeBitcast(Helper, MI);
816 case TargetOpcode::G_EXTRACT_VECTOR_ELT:
817 return legalizeExtractVectorElt(Helper, MI);
818 case TargetOpcode::G_INSERT_VECTOR_ELT:
819 return legalizeInsertVectorElt(Helper, MI);
820 case TargetOpcode::G_INTRINSIC:
821 case TargetOpcode::G_INTRINSIC_W_SIDE_EFFECTS:
822 return legalizeIntrinsic(Helper, MI);
823 case TargetOpcode::G_IS_FPCLASS:
824 return legalizeIsFPClass(Helper, MI, LocObserver);
825 case TargetOpcode::G_ICMP: {
826 auto &Op0 = MI.getOperand(2);
827 auto &Op1 = MI.getOperand(3);
828 Register Reg0 = Op0.getReg();
829 Register Reg1 = Op1.getReg();
831 static_cast<CmpInst::Predicate>(MI.getOperand(1).getPredicate());
832 if ((!ST->canDirectlyComparePointers() ||
834 MRI.getType(Reg0).isPointer() && MRI.getType(Reg1).isPointer()) {
835 LLT ConvT = LLT::scalar(ST->getPointerSize());
836 Type *LLVMTy = IntegerType::get(MI.getMF()->getFunction().getContext(),
837 ST->getPointerSize());
838 SPIRVTypeInst SpirvTy = GR->getOrCreateSPIRVType(
839 LLVMTy, Helper.MIRBuilder, SPIRV::AccessQualifier::ReadWrite, true);
840 Op0.setReg(convertPtrToInt(Reg0, ConvT, SpirvTy, Helper, MRI, GR));
841 Op1.setReg(convertPtrToInt(Reg1, ConvT, SpirvTy, Helper, MRI, GR));
842 }
843 return true;
844 }
845 case TargetOpcode::G_LOAD:
846 return legalizeLoad(Helper, MI, GR);
847 case TargetOpcode::G_STORE:
848 return legalizeStore(Helper, MI, GR);
849 }
850}
851
854 Register SrcReg, LLT SrcTy,
855 MachinePointerInfo &PtrInfo, Align &VecAlign) {
856 MachineIRBuilder &MIRBuilder = Helper.MIRBuilder;
857 MachineRegisterInfo &MRI = *MIRBuilder.getMRI();
858
859 VecAlign = Helper.getStackTemporaryAlignment(SrcTy);
860 auto StackTemp = Helper.createStackTemporary(
861 TypeSize::getFixed(SrcTy.getSizeInBytes()), VecAlign, PtrInfo);
862
863 // Set the type of StackTemp to a pointer to an array of the element type.
864 SPIRVTypeInst SpvSrcTy = GR->getSPIRVTypeForVReg(SrcReg);
865 SPIRVTypeInst EltSpvTy = GR->getScalarOrVectorComponentType(SpvSrcTy);
866 const Type *LLVMEltTy = GR->getTypeForSPIRVType(EltSpvTy);
867 const Type *LLVMArrTy =
868 ArrayType::get(const_cast<Type *>(LLVMEltTy), SrcTy.getNumElements());
869 SPIRVTypeInst ArrSpvTy = GR->getOrCreateSPIRVType(
870 LLVMArrTy, MIRBuilder, SPIRV::AccessQualifier::ReadWrite, true);
871 SPIRVTypeInst PtrToArrSpvTy = GR->getOrCreateSPIRVPointerType(
872 ArrSpvTy, MIRBuilder, SPIRV::StorageClass::Function);
873
874 Register StackReg = StackTemp.getReg(0);
875 MRI.setRegClass(StackReg, GR->getRegClass(PtrToArrSpvTy));
876 GR->assignSPIRVTypeToVReg(PtrToArrSpvTy, StackReg, MIRBuilder.getMF());
877
878 return StackTemp;
879}
880
883 LLVM_DEBUG(dbgs() << "Found a bitcast instruction\n");
884 MachineIRBuilder &MIRBuilder = Helper.MIRBuilder;
885 MachineRegisterInfo &MRI = *MIRBuilder.getMRI();
886 const SPIRVSubtarget &ST = MI.getMF()->getSubtarget<SPIRVSubtarget>();
887
888 Register DstReg = MI.getOperand(0).getReg();
889 Register SrcReg = MI.getOperand(2).getReg();
890 LLT DstTy = MRI.getType(DstReg);
891 LLT SrcTy = MRI.getType(SrcReg);
892
893 // If an spv_bitcast needs to be legalized, we convert it to G_BITCAST to
894 // allow using the generic legalization rules.
895 if (needsVectorLegalization(DstTy, ST) ||
896 needsVectorLegalization(SrcTy, ST)) {
897 LLVM_DEBUG(dbgs() << "Replacing with a G_BITCAST\n");
898 MIRBuilder.buildBitcast(DstReg, SrcReg);
899 MI.eraseFromParent();
900 }
901 return true;
902}
903
906 MachineIRBuilder &MIRBuilder = Helper.MIRBuilder;
907 MachineRegisterInfo &MRI = *MIRBuilder.getMRI();
908 const SPIRVSubtarget &ST = MI.getMF()->getSubtarget<SPIRVSubtarget>();
909
910 Register DstReg = MI.getOperand(0).getReg();
911 LLT DstTy = MRI.getType(DstReg);
912
913 if (needsVectorLegalization(DstTy, ST)) {
914 Register SrcReg = MI.getOperand(2).getReg();
915 Register ValReg = MI.getOperand(3).getReg();
916 LLT SrcTy = MRI.getType(SrcReg);
917 MachineOperand &IdxOperand = MI.getOperand(4);
918
919 if (getImm(IdxOperand, &MRI)) {
920 uint64_t IdxVal = foldImm(IdxOperand, &MRI);
921 if (IdxVal < SrcTy.getNumElements()) {
923 SPIRVTypeInst ElementType =
925 LLT ElementLLTTy = GR->getRegType(ElementType);
926 for (unsigned I = 0, E = SrcTy.getNumElements(); I < E; ++I) {
927 Register Reg = MRI.createGenericVirtualRegister(ElementLLTTy);
928 MRI.setRegClass(Reg, GR->getRegClass(ElementType));
929 GR->assignSPIRVTypeToVReg(ElementType, Reg, *MI.getMF());
930 Regs.push_back(Reg);
931 }
932 MIRBuilder.buildUnmerge(Regs, SrcReg);
933 Regs[IdxVal] = ValReg;
934 MIRBuilder.buildBuildVector(DstReg, Regs);
935 MI.eraseFromParent();
936 return true;
937 }
938 }
939
940 LLT EltTy = SrcTy.getElementType();
941 Align VecAlign;
942 MachinePointerInfo PtrInfo;
943 auto StackTemp = createStackTemporaryForVector(Helper, GR, SrcReg, SrcTy,
944 PtrInfo, VecAlign);
945
946 MIRBuilder.buildStore(SrcReg, StackTemp, PtrInfo, VecAlign);
947
948 Register IdxReg = IdxOperand.getReg();
949 LLT PtrTy = MRI.getType(StackTemp.getReg(0));
950 Register EltPtr = MRI.createGenericVirtualRegister(PtrTy);
951 auto Zero = MIRBuilder.buildConstant(LLT::scalar(32), 0);
952
953 MIRBuilder.buildIntrinsic(Intrinsic::spv_gep, ArrayRef<Register>{EltPtr})
954 .addImm(1) // InBounds
955 .addUse(StackTemp.getReg(0))
956 .addUse(Zero.getReg(0))
957 .addUse(IdxReg);
958
960 Align EltAlign = Helper.getStackTemporaryAlignment(EltTy);
961 MIRBuilder.buildStore(ValReg, EltPtr, EltPtrInfo, EltAlign);
962
963 MIRBuilder.buildLoad(DstReg, StackTemp, PtrInfo, VecAlign);
964 MI.eraseFromParent();
965 return true;
966 }
967 return true;
968}
969
972 MachineIRBuilder &MIRBuilder = Helper.MIRBuilder;
973 MachineRegisterInfo &MRI = *MIRBuilder.getMRI();
974 const SPIRVSubtarget &ST = MI.getMF()->getSubtarget<SPIRVSubtarget>();
975
976 Register SrcReg = MI.getOperand(2).getReg();
977 LLT SrcTy = MRI.getType(SrcReg);
978
979 if (needsVectorLegalization(SrcTy, ST)) {
980 Register DstReg = MI.getOperand(0).getReg();
981 MachineOperand &IdxOperand = MI.getOperand(3);
982
983 if (getImm(IdxOperand, &MRI)) {
984 uint64_t IdxVal = foldImm(IdxOperand, &MRI);
985 if (IdxVal < SrcTy.getNumElements()) {
986 LLT DstTy = MRI.getType(DstReg);
988 SPIRVTypeInst DstSpvTy = GR->getSPIRVTypeForVReg(DstReg);
989 for (unsigned I = 0, E = SrcTy.getNumElements(); I < E; ++I) {
990 if (I == IdxVal) {
991 Regs.push_back(DstReg);
992 } else {
993 Register Reg = MRI.createGenericVirtualRegister(DstTy);
994 MRI.setRegClass(Reg, GR->getRegClass(DstSpvTy));
995 GR->assignSPIRVTypeToVReg(DstSpvTy, Reg, *MI.getMF());
996 Regs.push_back(Reg);
997 }
998 }
999 MIRBuilder.buildUnmerge(Regs, SrcReg);
1000 MI.eraseFromParent();
1001 return true;
1002 }
1003 }
1004
1005 LLT EltTy = SrcTy.getElementType();
1006 Align VecAlign;
1007 MachinePointerInfo PtrInfo;
1008 auto StackTemp = createStackTemporaryForVector(Helper, GR, SrcReg, SrcTy,
1009 PtrInfo, VecAlign);
1010
1011 MIRBuilder.buildStore(SrcReg, StackTemp, PtrInfo, VecAlign);
1012
1013 Register IdxReg = IdxOperand.getReg();
1014 LLT PtrTy = MRI.getType(StackTemp.getReg(0));
1015 Register EltPtr = MRI.createGenericVirtualRegister(PtrTy);
1016 auto Zero = MIRBuilder.buildConstant(LLT::scalar(32), 0);
1017
1018 MIRBuilder.buildIntrinsic(Intrinsic::spv_gep, ArrayRef<Register>{EltPtr})
1019 .addImm(1) // InBounds
1020 .addUse(StackTemp.getReg(0))
1021 .addUse(Zero.getReg(0))
1022 .addUse(IdxReg);
1023
1025 Align EltAlign = Helper.getStackTemporaryAlignment(EltTy);
1026 MIRBuilder.buildLoad(DstReg, EltPtr, EltPtrInfo, EltAlign);
1027
1028 MI.eraseFromParent();
1029 return true;
1030 }
1031 return true;
1032}
1033
1035 SPIRVGlobalRegistry *GR) {
1036 MachineIRBuilder &MIRBuilder = Helper.MIRBuilder;
1037 MachineRegisterInfo &MRI = *MIRBuilder.getMRI();
1038 const SPIRVSubtarget &ST = MI.getMF()->getSubtarget<SPIRVSubtarget>();
1039
1040 Register DstReg = MI.getOperand(0).getReg();
1041 LLT DstTy = MRI.getType(DstReg);
1042
1043 if (!needsVectorLegalization(DstTy, ST))
1044 return true;
1045
1047 if (MI.getNumOperands() == 2) {
1048 // The "null" case: no values are attached.
1049 LLT EltTy = DstTy.getElementType();
1050 auto Zero = MIRBuilder.buildConstant(EltTy, 0);
1051 SPIRVTypeInst SpvDstTy = GR->getSPIRVTypeForVReg(DstReg);
1052 SPIRVTypeInst SpvEltTy = GR->getScalarOrVectorComponentType(SpvDstTy);
1053 GR->assignSPIRVTypeToVReg(SpvEltTy, Zero.getReg(0), MIRBuilder.getMF());
1054 for (unsigned i = 0; i < DstTy.getNumElements(); ++i)
1055 SrcRegs.push_back(Zero.getReg(0));
1056 } else {
1057 for (unsigned i = 2; i < MI.getNumOperands(); ++i) {
1058 SrcRegs.push_back(MI.getOperand(i).getReg());
1059 }
1060 }
1061 MIRBuilder.buildBuildVector(DstReg, SrcRegs);
1062 MI.eraseFromParent();
1063 return true;
1064}
1065
1067 MachineIRBuilder &MIRBuilder,
1068 SPIRVGlobalRegistry *GR) {
1069 LLT Ty = MIRBuilder.getMRI()->getType(Reg);
1070 if (!Ty.isVector())
1071 return {Reg};
1072 SPIRVTypeInst EltSpvTy =
1074 unsigned NumElts = Ty.getNumElements();
1076 for (unsigned I = 0; I < NumElts; ++I)
1077 Elts.push_back(createVirtualRegister(EltSpvTy, GR, MIRBuilder));
1078 MIRBuilder.buildUnmerge(Elts, Reg);
1079 return Elts;
1080}
1081
1083 MachineIRBuilder &MIRBuilder,
1084 SPIRVGlobalRegistry *GR) {
1085 if (Elts.size() == 1)
1086 return Elts[0];
1087 SPIRVTypeInst PartSpvTy =
1089 Elts.size(), MIRBuilder, /*EmitIR=*/true);
1090 Register Part = createVirtualRegister(PartSpvTy, GR, MIRBuilder);
1091 MIRBuilder.buildBuildVector(Part, Elts);
1092 return Part;
1093}
1094
1095// Split an elementwise intrinsic with an illegal vector width into intrinsics
1096// on legal vector widths.
1098 GIntrinsic &MI,
1099 SPIRVGlobalRegistry *GR) {
1100 MachineIRBuilder &MIRBuilder = Helper.MIRBuilder;
1101 MachineRegisterInfo &MRI = *MIRBuilder.getMRI();
1102 const SPIRVSubtarget &ST = MI.getMF()->getSubtarget<SPIRVSubtarget>();
1103
1104 if (!Intrinsic::isTriviallyScalarizable(MI.getIntrinsicID()))
1105 return true;
1106 Register DstReg = MI.getReg(0);
1107 LLT DstTy = MRI.getType(DstReg);
1108 if (!needsVectorLegalization(DstTy, ST))
1109 return true;
1110
1111 unsigned NumElts = DstTy.getNumElements();
1112 unsigned MaxVectorSize = ST.isShader() ? 4 : 16;
1113 unsigned PartSize = NumElts > MaxVectorSize ? MaxVectorSize : 4;
1114
1116 for (const MachineOperand &MO : drop_begin(MI.explicit_uses())) {
1117 if (!MO.isReg() || !MRI.getType(MO.getReg()).isVector())
1118 continue;
1119 auto [It, Inserted] = OpElts.try_emplace(MO.getReg());
1120 if (Inserted)
1121 It->second = unmergeToScalars(MO.getReg(), MIRBuilder, GR);
1122 }
1123
1124 SPIRVTypeInst DstEltSpvTy =
1127 for (unsigned Offset = 0; Offset < NumElts; Offset += PartSize) {
1128 unsigned Size = std::min(PartSize, NumElts - Offset);
1129 SPIRVTypeInst PartSpvTy =
1130 Size == 1 ? DstEltSpvTy
1131 : GR->getOrCreateSPIRVVectorType(DstEltSpvTy, Size,
1132 MIRBuilder, /*EmitIR=*/true);
1135 for (const MachineOperand &MO : drop_begin(MI.explicit_uses())) {
1136 auto EltsIt = MO.isReg() ? OpElts.find(MO.getReg()) : OpElts.end();
1137 if (EltsIt == OpElts.end()) {
1138 PartOps.push_back(MO);
1139 continue;
1140 }
1141 auto [It, Inserted] = PartRegs.try_emplace(MO.getReg());
1142 if (Inserted)
1143 It->second = buildVectorPart(
1144 ArrayRef(EltsIt->second).slice(Offset, Size), MIRBuilder, GR);
1145 PartOps.push_back(MachineOperand::CreateReg(It->second, /*isDef=*/false));
1146 }
1147 Register PartDst = createVirtualRegister(PartSpvTy, GR, MIRBuilder);
1148 auto Part = MIRBuilder.buildIntrinsic(
1149 MI.getIntrinsicID(), ArrayRef<Register>{PartDst}, MI.hasSideEffects(),
1150 MI.isConvergent());
1151 for (const MachineOperand &MO : PartOps)
1152 Part.add(MO);
1153 Part->setFlags(MI.getFlags());
1154 append_range(DstElts, unmergeToScalars(PartDst, MIRBuilder, GR));
1155 }
1156
1157 MIRBuilder.buildBuildVector(DstReg, DstElts);
1158 MI.eraseFromParent();
1159 return true;
1160}
1161
1163 MachineInstr &MI) const {
1164 LLVM_DEBUG(dbgs() << "legalizeIntrinsic: " << MI);
1165 auto IntrinsicID = cast<GIntrinsic>(MI).getIntrinsicID();
1166 switch (IntrinsicID) {
1167 case Intrinsic::spv_bitcast:
1168 return legalizeSpvBitcast(Helper, MI, GR);
1169 case Intrinsic::spv_insertelt:
1170 return legalizeSpvInsertElt(Helper, MI, GR);
1171 case Intrinsic::spv_extractelt:
1172 return legalizeSpvExtractElt(Helper, MI, GR);
1173 case Intrinsic::spv_const_composite:
1174 return legalizeSpvConstComposite(Helper, MI, GR);
1175 }
1177}
1178
1179bool SPIRVLegalizerInfo::legalizeBitcast(LegalizerHelper &Helper,
1180 MachineInstr &MI) const {
1181 // Once the G_BITCAST is using vectors that are allowed, we turn it back into
1182 // an spv_bitcast to avoid verifier problems when the register types are the
1183 // same for the source and the result. Note that the SPIR-V types associated
1184 // with the bitcast can be different even if the register types are the same.
1185 MachineIRBuilder &MIRBuilder = Helper.MIRBuilder;
1186 Register DstReg = MI.getOperand(0).getReg();
1187 Register SrcReg = MI.getOperand(1).getReg();
1188 SmallVector<Register, 1> DstRegs = {DstReg};
1189 MIRBuilder.buildIntrinsic(Intrinsic::spv_bitcast, DstRegs).addUse(SrcReg);
1190 MI.eraseFromParent();
1191 return true;
1192}
1193
1194// Note this code was copied from LegalizerHelper::lowerISFPCLASS and adjusted
1195// to ensure that all instructions created during the lowering have SPIR-V types
1196// assigned to them.
1197bool SPIRVLegalizerInfo::legalizeIsFPClass(
1199 LostDebugLocObserver &LocObserver) const {
1200 auto [DstReg, DstTy, SrcReg, SrcTy] = MI.getFirst2RegLLTs();
1201 FPClassTest Mask = static_cast<FPClassTest>(MI.getOperand(2).getImm());
1202
1203 auto &MIRBuilder = Helper.MIRBuilder;
1204 auto &MF = MIRBuilder.getMF();
1205 MachineRegisterInfo &MRI = MF.getRegInfo();
1206
1207 Type *LLVMDstTy =
1208 IntegerType::get(MIRBuilder.getContext(), DstTy.getScalarSizeInBits());
1209 if (DstTy.isVector())
1210 LLVMDstTy = VectorType::get(LLVMDstTy, DstTy.getElementCount());
1211 SPIRVTypeInst SPIRVDstTy = GR->getOrCreateSPIRVType(
1212 LLVMDstTy, MIRBuilder, SPIRV::AccessQualifier::ReadWrite,
1213 /*EmitIR*/ true);
1214
1215 unsigned BitSize = SrcTy.getScalarSizeInBits();
1216 const fltSemantics &Semantics = getFltSemanticForLLT(SrcTy.getScalarType());
1217
1218 LLT IntTy = LLT::scalar(BitSize);
1219 Type *LLVMIntTy = IntegerType::get(MIRBuilder.getContext(), BitSize);
1220 if (SrcTy.isVector()) {
1221 IntTy = LLT::vector(SrcTy.getElementCount(), IntTy);
1222 LLVMIntTy = VectorType::get(LLVMIntTy, SrcTy.getElementCount());
1223 }
1224 SPIRVTypeInst SPIRVIntTy = GR->getOrCreateSPIRVType(
1225 LLVMIntTy, MIRBuilder, SPIRV::AccessQualifier::ReadWrite,
1226 /*EmitIR*/ true);
1227
1228 // Clang doesn't support capture of structured bindings:
1229 LLT DstTyCopy = DstTy;
1230 const auto assignSPIRVTy = [&](MachineInstrBuilder &&MI) {
1231 // Assign this MI's (assumed only) destination to one of the two types we
1232 // expect: either the G_IS_FPCLASS's destination type, or the integer type
1233 // bitcast from the source type.
1234 LLT MITy = MRI.getType(MI.getReg(0));
1235 assert((MITy == IntTy || MITy == DstTyCopy) &&
1236 "Unexpected LLT type while lowering G_IS_FPCLASS");
1237 SPIRVTypeInst SPVTy = MITy == IntTy ? SPIRVIntTy : SPIRVDstTy;
1238 GR->assignSPIRVTypeToVReg(SPVTy, MI.getReg(0), MF);
1239 return MI;
1240 };
1241
1242 // Helper to build and assign a constant in one go
1243 const auto buildSPIRVConstant = [&](LLT Ty, auto &&C) -> MachineInstrBuilder {
1244 if (!Ty.isFixedVector())
1245 return assignSPIRVTy(MIRBuilder.buildConstant(Ty, C));
1246 auto ScalarC = MIRBuilder.buildConstant(Ty.getScalarType(), C);
1247 assert((Ty == IntTy || Ty == DstTyCopy) &&
1248 "Unexpected LLT type while lowering constant for G_IS_FPCLASS");
1249 SPIRVTypeInst VecEltTy = GR->getOrCreateSPIRVType(
1250 (Ty == IntTy ? LLVMIntTy : LLVMDstTy)->getScalarType(), MIRBuilder,
1251 SPIRV::AccessQualifier::ReadWrite,
1252 /*EmitIR*/ true);
1253 GR->assignSPIRVTypeToVReg(VecEltTy, ScalarC.getReg(0), MF);
1254 return assignSPIRVTy(MIRBuilder.buildSplatBuildVector(Ty, ScalarC));
1255 };
1256
1257 if (Mask == fcNone) {
1258 MIRBuilder.buildCopy(DstReg, buildSPIRVConstant(DstTy, 0));
1259 MI.eraseFromParent();
1260 return true;
1261 }
1262 if (Mask == fcAllFlags) {
1263 MIRBuilder.buildCopy(DstReg, buildSPIRVConstant(DstTy, 1));
1264 MI.eraseFromParent();
1265 return true;
1266 }
1267
1268 // Note that rather than creating a COPY here (between a floating-point and
1269 // integer type of the same size) we create a SPIR-V bitcast immediately. We
1270 // can't create a G_BITCAST because the LLTs are the same, and we can't seem
1271 // to correctly lower COPYs to SPIR-V bitcasts at this moment.
1272 Register ResVReg = MRI.createGenericVirtualRegister(IntTy);
1273 MRI.setRegClass(ResVReg, GR->getRegClass(SPIRVIntTy));
1274 GR->assignSPIRVTypeToVReg(SPIRVIntTy, ResVReg, Helper.MIRBuilder.getMF());
1275 auto AsInt = MIRBuilder.buildInstr(SPIRV::OpBitcast)
1276 .addDef(ResVReg)
1277 .addUse(GR->getSPIRVTypeID(SPIRVIntTy))
1278 .addUse(SrcReg);
1279 AsInt = assignSPIRVTy(std::move(AsInt));
1280
1281 // Various masks.
1282 APInt SignBit = APInt::getSignMask(BitSize);
1283 APInt ValueMask = APInt::getSignedMaxValue(BitSize); // All bits but sign.
1284 APInt Inf = APFloat::getInf(Semantics).bitcastToAPInt(); // Exp and int bit.
1285 APInt ExpMask = Inf;
1286 APInt AllOneMantissa = APFloat::getLargest(Semantics).bitcastToAPInt() & ~Inf;
1287 APInt QNaNBitMask =
1288 APInt::getOneBitSet(BitSize, AllOneMantissa.getActiveBits() - 1);
1289 APInt InversionMask = APInt::getAllOnes(DstTy.getScalarSizeInBits());
1290
1291 auto SignBitC = buildSPIRVConstant(IntTy, SignBit);
1292 auto ValueMaskC = buildSPIRVConstant(IntTy, ValueMask);
1293 auto InfC = buildSPIRVConstant(IntTy, Inf);
1294 auto ExpMaskC = buildSPIRVConstant(IntTy, ExpMask);
1295 auto ZeroC = buildSPIRVConstant(IntTy, 0);
1296
1297 auto Abs = assignSPIRVTy(MIRBuilder.buildAnd(IntTy, AsInt, ValueMaskC));
1298 auto Sign = assignSPIRVTy(
1299 MIRBuilder.buildICmp(CmpInst::Predicate::ICMP_NE, DstTy, AsInt, Abs));
1300
1301 MachineInstrBuilder Res;
1302
1303 const auto appendToRes = [&](MachineInstrBuilder &&ToAppend) {
1304 auto Appended = assignSPIRVTy(std::move(ToAppend));
1305 Res = Res.getInstr()
1306 ? assignSPIRVTy(MIRBuilder.buildOr(DstTyCopy, Res, Appended))
1307 : Appended;
1308 };
1309
1310 // Tests that involve more than one class should be processed first.
1311 if ((Mask & fcFinite) == fcFinite) {
1312 // finite(V) ==> abs(V) u< exp_mask
1313 appendToRes(MIRBuilder.buildICmp(CmpInst::Predicate::ICMP_ULT, DstTy, Abs,
1314 ExpMaskC));
1315 Mask &= ~fcFinite;
1316 } else if ((Mask & fcFinite) == fcPosFinite) {
1317 // finite(V) && V > 0 ==> V u< exp_mask
1318 appendToRes(MIRBuilder.buildICmp(CmpInst::Predicate::ICMP_ULT, DstTy, AsInt,
1319 ExpMaskC));
1320 Mask &= ~fcPosFinite;
1321 } else if ((Mask & fcFinite) == fcNegFinite) {
1322 // finite(V) && V < 0 ==> abs(V) u< exp_mask && signbit == 1
1323 auto Cmp = assignSPIRVTy(MIRBuilder.buildICmp(CmpInst::Predicate::ICMP_ULT,
1324 DstTy, Abs, ExpMaskC));
1325 appendToRes(MIRBuilder.buildAnd(DstTy, Cmp, Sign));
1326 Mask &= ~fcNegFinite;
1327 }
1328
1329 if (FPClassTest PartialCheck = Mask & (fcZero | fcSubnormal)) {
1330 // fcZero | fcSubnormal => test all exponent bits are 0
1331 // TODO: Handle sign bit specific cases
1332 // TODO: Handle inverted case
1333 if (PartialCheck == (fcZero | fcSubnormal)) {
1334 auto ExpBits = assignSPIRVTy(MIRBuilder.buildAnd(IntTy, AsInt, ExpMaskC));
1335 appendToRes(MIRBuilder.buildICmp(CmpInst::Predicate::ICMP_EQ, DstTy,
1336 ExpBits, ZeroC));
1337 Mask &= ~PartialCheck;
1338 }
1339 }
1340
1341 // Check for individual classes.
1342 if (FPClassTest PartialCheck = Mask & fcZero) {
1343 if (PartialCheck == fcPosZero)
1344 appendToRes(MIRBuilder.buildICmp(CmpInst::Predicate::ICMP_EQ, DstTy,
1345 AsInt, ZeroC));
1346 else if (PartialCheck == fcZero)
1347 appendToRes(
1348 MIRBuilder.buildICmp(CmpInst::Predicate::ICMP_EQ, DstTy, Abs, ZeroC));
1349 else // fcNegZero
1350 appendToRes(MIRBuilder.buildICmp(CmpInst::Predicate::ICMP_EQ, DstTy,
1351 AsInt, SignBitC));
1352 }
1353
1354 if (FPClassTest PartialCheck = Mask & fcSubnormal) {
1355 // issubnormal(V) ==> unsigned(abs(V) - 1) u< (all mantissa bits set)
1356 // issubnormal(V) && V>0 ==> unsigned(V - 1) u< (all mantissa bits set)
1357 auto V = (PartialCheck == fcPosSubnormal) ? AsInt : Abs;
1358 auto OneC = buildSPIRVConstant(IntTy, 1);
1359 auto VMinusOne = MIRBuilder.buildSub(IntTy, V, OneC);
1360 auto SubnormalRes = assignSPIRVTy(
1361 MIRBuilder.buildICmp(CmpInst::Predicate::ICMP_ULT, DstTy, VMinusOne,
1362 buildSPIRVConstant(IntTy, AllOneMantissa)));
1363 if (PartialCheck == fcNegSubnormal)
1364 SubnormalRes = MIRBuilder.buildAnd(DstTy, SubnormalRes, Sign);
1365 appendToRes(std::move(SubnormalRes));
1366 }
1367
1368 if (FPClassTest PartialCheck = Mask & fcInf) {
1369 if (PartialCheck == fcPosInf)
1370 appendToRes(MIRBuilder.buildICmp(CmpInst::Predicate::ICMP_EQ, DstTy,
1371 AsInt, InfC));
1372 else if (PartialCheck == fcInf)
1373 appendToRes(
1374 MIRBuilder.buildICmp(CmpInst::Predicate::ICMP_EQ, DstTy, Abs, InfC));
1375 else { // fcNegInf
1376 APInt NegInf = APFloat::getInf(Semantics, true).bitcastToAPInt();
1377 auto NegInfC = buildSPIRVConstant(IntTy, NegInf);
1378 appendToRes(MIRBuilder.buildICmp(CmpInst::Predicate::ICMP_EQ, DstTy,
1379 AsInt, NegInfC));
1380 }
1381 }
1382
1383 if (FPClassTest PartialCheck = Mask & fcNan) {
1384 auto InfWithQnanBitC =
1385 buildSPIRVConstant(IntTy, std::move(Inf) | QNaNBitMask);
1386 if (PartialCheck == fcNan) {
1387 // isnan(V) ==> abs(V) u> int(inf)
1388 appendToRes(
1389 MIRBuilder.buildICmp(CmpInst::Predicate::ICMP_UGT, DstTy, Abs, InfC));
1390 } else if (PartialCheck == fcQNan) {
1391 // isquiet(V) ==> abs(V) u>= (unsigned(Inf) | quiet_bit)
1392 appendToRes(MIRBuilder.buildICmp(CmpInst::Predicate::ICMP_UGE, DstTy, Abs,
1393 InfWithQnanBitC));
1394 } else { // fcSNan
1395 // issignaling(V) ==> abs(V) u> unsigned(Inf) &&
1396 // abs(V) u< (unsigned(Inf) | quiet_bit)
1397 auto IsNan = assignSPIRVTy(
1398 MIRBuilder.buildICmp(CmpInst::Predicate::ICMP_UGT, DstTy, Abs, InfC));
1399 auto IsNotQnan = assignSPIRVTy(MIRBuilder.buildICmp(
1400 CmpInst::Predicate::ICMP_ULT, DstTy, Abs, InfWithQnanBitC));
1401 appendToRes(MIRBuilder.buildAnd(DstTy, IsNan, IsNotQnan));
1402 }
1403 }
1404
1405 if (FPClassTest PartialCheck = Mask & fcNormal) {
1406 // isnormal(V) ==> (0 u< exp u< max_exp) ==> (unsigned(exp-1) u<
1407 // (max_exp-1))
1408 APInt ExpLSB = ExpMask & ~(ExpMask.shl(1));
1409 auto ExpMinusOne = assignSPIRVTy(
1410 MIRBuilder.buildSub(IntTy, Abs, buildSPIRVConstant(IntTy, ExpLSB)));
1411 APInt MaxExpMinusOne = std::move(ExpMask) - ExpLSB;
1412 auto NormalRes = assignSPIRVTy(
1413 MIRBuilder.buildICmp(CmpInst::Predicate::ICMP_ULT, DstTy, ExpMinusOne,
1414 buildSPIRVConstant(IntTy, MaxExpMinusOne)));
1415 if (PartialCheck == fcNegNormal)
1416 NormalRes = MIRBuilder.buildAnd(DstTy, NormalRes, Sign);
1417 else if (PartialCheck == fcPosNormal) {
1418 auto PosSign = assignSPIRVTy(MIRBuilder.buildXor(
1419 DstTy, Sign, buildSPIRVConstant(DstTy, InversionMask)));
1420 NormalRes = MIRBuilder.buildAnd(DstTy, NormalRes, PosSign);
1421 }
1422 appendToRes(std::move(NormalRes));
1423 }
1424
1425 MIRBuilder.buildCopy(DstReg, Res);
1426 MI.eraseFromParent();
1427 return true;
1428}
assert(UImm &&(UImm !=~static_cast< T >(0)) &&"Invalid immediate!")
uint64_t uint64_t
static GCRegistry::Add< ShadowStackGC > C("shadow-stack", "Very portable GC for uncooperative code generators")
static GCRegistry::Add< CoreCLRGC > E("coreclr", "CoreCLR-compatible GC")
static void scalarize(Instruction *I, SmallVectorImpl< Instruction * > &Worklist)
Declares convenience wrapper classes for interpreting MachineInstr instances as specific generic oper...
IRTranslator LLVM IR MI
#define I(x, y, z)
Definition MD5.cpp:57
This file declares the MachineIRBuilder class.
Register Reg
Promote Memory to Register
Definition Mem2Reg.cpp:110
ppc ctr loops verify
SmallVector< MachineOperand, 4 > Cond
MachineRegisterInfo & MRI
SPIR-V address space definition.
static bool legalizeSpvInsertElt(LegalizerHelper &Helper, MachineInstr &MI, SPIRVGlobalRegistry *GR)
static bool needsVectorLegalization(const LLT &Ty, const SPIRVSubtarget &ST)
static SmallVector< Register, 16 > unmergeToScalars(Register Reg, MachineIRBuilder &MIRBuilder, SPIRVGlobalRegistry *GR)
static bool legalizeInsertVectorElt(LegalizerHelper &Helper, MachineInstr &MI)
static MachineInstrBuilder createStackTemporaryForVector(LegalizerHelper &Helper, SPIRVGlobalRegistry *GR, Register SrcReg, LLT SrcTy, MachinePointerInfo &PtrInfo, Align &VecAlign)
static Register convertPtrToInt(Register Reg, LLT ConvTy, SPIRVTypeInst SpvType, LegalizerHelper &Helper, MachineRegisterInfo &MRI, SPIRVGlobalRegistry *GR)
LegalityPredicate typeOfExtendedScalars(unsigned TypeIdx, bool IsExtendedInts)
static bool legalizeStore(LegalizerHelper &Helper, MachineInstr &MI, SPIRVGlobalRegistry *GR)
static Register buildVectorPart(ArrayRef< Register > Elts, MachineIRBuilder &MIRBuilder, SPIRVGlobalRegistry *GR)
static bool legalizeExtractVectorElt(LegalizerHelper &Helper, MachineInstr &MI)
static bool legalizeSpvExtractElt(LegalizerHelper &Helper, MachineInstr &MI, SPIRVGlobalRegistry *GR)
LegalityPredicate typeOfLongVectors(unsigned TypeIdx, bool IsLongVecs)
static bool legalizeSpvBitcast(LegalizerHelper &Helper, MachineInstr &MI, SPIRVGlobalRegistry *GR)
static bool legalizeElementwiseIntrinsic(LegalizerHelper &Helper, GIntrinsic &MI, SPIRVGlobalRegistry *GR)
static bool legalizeSpvConstComposite(LegalizerHelper &Helper, MachineInstr &MI, SPIRVGlobalRegistry *GR)
static bool legalizeLoad(LegalizerHelper &Helper, MachineInstr &MI, SPIRVGlobalRegistry *GR)
#define LLVM_DEBUG(...)
Definition Debug.h:119
APInt bitcastToAPInt() const
Definition APFloat.h:1475
static APFloat getLargest(const fltSemantics &Sem, bool Negative=false)
Returns the largest finite number in the given semantics.
Definition APFloat.h:1242
static APFloat getInf(const fltSemantics &Sem, bool Negative=false)
Factory for Positive and Negative Infinity.
Definition APFloat.h:1202
static APInt getAllOnes(unsigned numBits)
Return an APInt of a specified width with all bits set.
Definition APInt.h:230
static APInt getSignMask(unsigned BitWidth)
Get the SignMask for a specific bit width.
Definition APInt.h:225
unsigned getActiveBits() const
Compute the number of active bits in the value.
Definition APInt.h:1532
static APInt getSignedMaxValue(unsigned numBits)
Gets maximum signed value of APInt for a specific bit width.
Definition APInt.h:205
APInt shl(unsigned shiftAmt) const
Left-shift function.
Definition APInt.h:875
static APInt getOneBitSet(unsigned numBits, unsigned BitNo)
Return an APInt with exactly one bit set in the result.
Definition APInt.h:235
Represent a constant reference to an array (0 or more elements consecutively in memory),...
Definition ArrayRef.h:40
size_t size() const
Get the array size.
Definition ArrayRef.h:141
static LLVM_ABI ArrayType * get(Type *ElementType, uint64_t NumElements)
This static method is the primary way to construct an ArrayType.
Predicate
This enumeration lists the possible predicates for CmpInst subclasses.
Definition InstrTypes.h:740
@ ICMP_UGE
unsigned greater or equal
Definition InstrTypes.h:764
@ ICMP_UGT
unsigned greater than
Definition InstrTypes.h:763
@ ICMP_ULT
unsigned less than
Definition InstrTypes.h:765
@ ICMP_NE
not equal
Definition InstrTypes.h:762
iterator find(const_arg_type_t< KeyT > Val)
Definition DenseMap.h:766
iterator end()
Definition DenseMap.h:686
std::pair< iterator, bool > try_emplace(KeyT &&Key, Ts &&...Args)
Definition DenseMap.h:856
static constexpr ElementCount getFixed(ScalarTy MinVal)
Definition TypeSize.h:306
Represents a call to an intrinsic.
static LLVM_ABI IntegerType * get(LLVMContext &C, unsigned NumBits)
This static method is the primary way of constructing an IntegerType.
Definition Type.cpp:338
static constexpr LLT vector(ElementCount EC, unsigned ScalarSizeInBits)
Get a low-level vector of some number of elements and element width.
LLT getScalarType() const
constexpr bool isPointerVector() const
static constexpr LLT scalar(unsigned SizeInBits)
Get a low-level scalar or aggregate "bag of bits".
constexpr bool isValid() const
constexpr uint16_t getNumElements() const
Returns the number of elements in a vector LLT.
constexpr bool isVector() const
static constexpr LLT pointer(unsigned AddressSpace, unsigned SizeInBits)
Get a low-level pointer in the given address space.
constexpr bool isPointer() const
constexpr unsigned getAddressSpace() const
static constexpr LLT fixed_vector(unsigned NumElements, unsigned ScalarSizeInBits)
Get a low-level fixed-width vector of some number of elements and element width.
constexpr bool isPointerOrPointerVector() const
constexpr bool isFixedVector() const
Returns true if the LLT is a fixed vector.
constexpr TypeSize getSizeInBytes() const
Returns the total size of the type in bytes, i.e.
LLT getElementType() const
Returns the vector's element type. Only valid for vector types.
LegalizeRuleSet & minScalar(unsigned TypeIdx, const LLT Ty)
Ensure the scalar is at least as wide as Ty.
LegalizeRuleSet & legalFor(std::initializer_list< LLT > Types)
The instruction is legal when type index 0 is any type in the given list.
LegalizeRuleSet & fewerElementsIf(LegalityPredicate Predicate, LegalizeMutation Mutation)
Remove elements to reach the type selected by the mutation if the predicate is true.
LegalizeRuleSet & unsupportedFor(std::initializer_list< LLT > Types)
LegalizeRuleSet & moreElementsToNextPow2(unsigned TypeIdx)
Add more elements to the vector to reach the next power of two.
LegalizeRuleSet & lower()
The instruction is lowered.
LegalizeRuleSet & scalarizeIf(LegalityPredicate Predicate, unsigned TypeIdx)
LegalizeRuleSet & lowerIf(LegalityPredicate Predicate)
The instruction is lowered if predicate is true.
LegalizeRuleSet & custom()
Unconditionally custom lower.
LegalizeRuleSet & unsupportedIf(LegalityPredicate Predicate)
LegalizeRuleSet & alwaysLegal()
LegalizeRuleSet & customIf(LegalityPredicate Predicate)
LegalizeRuleSet & scalarize(unsigned TypeIdx)
LegalizeRuleSet & legalForCartesianProduct(std::initializer_list< LLT > Types)
The instruction is legal when type indexes 0 and 1 are both in the given list.
LegalizeRuleSet & legalIf(LegalityPredicate Predicate)
The instruction is legal if predicate is true.
LegalizeRuleSet & customFor(std::initializer_list< LLT > Types)
LLVM_ABI MachineInstrBuilder createStackTemporary(TypeSize Bytes, Align Alignment, MachinePointerInfo &PtrInfo)
Create a stack temporary based on the size in bytes and the alignment.
MachineIRBuilder & MIRBuilder
Expose MIRBuilder so clients can set their own RecordInsertInstruction functions.
LLVM_ABI Align getStackTemporaryAlignment(LLT Type, Align MinAlign=Align()) const
Return the alignment to use for a stack temporary object with the given type.
LegalizeRuleSet & getActionDefinitionsBuilder(unsigned Opcode)
Get the action definition builder for the given opcode.
Helper class to build MachineInstr.
LLVMContext & getContext() const
MachineInstrBuilder buildUnmerge(ArrayRef< LLT > Res, const SrcOp &Op)
Build and insert Res0, ... = G_UNMERGE_VALUES Op.
MachineInstrBuilder buildAnd(const DstOp &Dst, const SrcOp &Src0, const SrcOp &Src1)
Build and insert Res = G_AND Op0, Op1.
MachineInstrBuilder buildICmp(CmpInst::Predicate Pred, const DstOp &Res, const SrcOp &Op0, const SrcOp &Op1, std::optional< unsigned > Flags=std::nullopt)
Build and insert a Res = G_ICMP Pred, Op0, Op1.
MachineInstrBuilder buildSub(const DstOp &Dst, const SrcOp &Src0, const SrcOp &Src1, std::optional< unsigned > Flags=std::nullopt)
Build and insert Res = G_SUB Op0, Op1.
MachineInstrBuilder buildIntrinsic(Intrinsic::ID ID, ArrayRef< Register > Res, bool HasSideEffects, bool isConvergent)
Build and insert a G_INTRINSIC instruction.
MachineInstrBuilder buildSplatBuildVector(const DstOp &Res, const SrcOp &Src)
Build and insert Res = G_BUILD_VECTOR with Src replicated to fill the number of elements.
MachineInstrBuilder buildBuildVector(const DstOp &Res, ArrayRef< Register > Ops)
Build and insert Res = G_BUILD_VECTOR Op0, ...
MachineInstrBuilder buildLoad(const DstOp &Res, const SrcOp &Addr, MachineMemOperand &MMO)
Build and insert Res = G_LOAD Addr, MMO.
MachineInstrBuilder buildStore(const SrcOp &Val, const SrcOp &Addr, MachineMemOperand &MMO)
Build and insert G_STORE Val, Addr, MMO.
MachineInstrBuilder buildInstr(unsigned Opcode)
Build and insert <empty> = Opcode <empty>.
MachineFunction & getMF()
Getter for the function we currently build.
MachineInstrBuilder buildBitcast(const DstOp &Dst, const SrcOp &Src)
Build and insert Dst = G_BITCAST Src.
MachineRegisterInfo * getMRI()
Getter for MRI.
MachineInstrBuilder buildOr(const DstOp &Dst, const SrcOp &Src0, const SrcOp &Src1, std::optional< unsigned > Flags=std::nullopt)
Build and insert Res = G_OR Op0, Op1.
MachineInstrBuilder buildCopy(const DstOp &Res, const SrcOp &Op)
Build and insert Res = COPY Op.
MachineInstrBuilder buildXor(const DstOp &Dst, const SrcOp &Src0, const SrcOp &Src1)
Build and insert Res = G_XOR Op0, Op1.
virtual MachineInstrBuilder buildConstant(const DstOp &Res, const ConstantInt &Val)
Build and insert Res = G_CONSTANT Val.
const MachineInstrBuilder & addUse(Register RegNo, RegState Flags={}, unsigned SubReg=0) const
Add a virtual register use operand.
const MachineInstrBuilder & add(const MachineOperand &MO) const
const MachineInstrBuilder & addDef(Register RegNo, RegState Flags={}, unsigned SubReg=0) const
Add a virtual register definition operand.
MachineInstr * getInstr() const
If conversion operators fail, use this method to get the MachineInstr explicitly.
Representation of each machine instruction.
void setFlags(unsigned flags)
A description of a memory reference used in the backend.
const MachinePointerInfo & getPointerInfo() const
LLVM_ABI Align getAlign() const
Return the minimum known alignment in bytes of the actual memory reference.
MachineOperand class - Representation of each machine instruction operand.
Register getReg() const
getReg - Returns the register number.
static MachineOperand CreateReg(Register Reg, bool isDef, bool isImp=false, bool isKill=false, bool isDead=false, bool isUndef=false, bool isEarlyClobber=false, unsigned SubReg=0, bool isDebug=false, bool isInternalRead=false, bool isRenamable=false)
MachineRegisterInfo - Keep track of information for virtual and physical registers,...
LLT getType(Register Reg) const
Get the low-level type of Reg or LLT{} if Reg is not a generic (target independent) virtual register.
LLVM_ABI void setRegClass(Register Reg, const TargetRegisterClass *RC)
setRegClass - Set the register class of the specified virtual register.
LLVM_ABI Register createGenericVirtualRegister(LLT Ty, StringRef Name="")
Create and return a new generic virtual register with low-level type Ty.
Wrapper class representing virtual and physical registers.
Definition Register.h:20
void assignSPIRVTypeToVReg(SPIRVTypeInst Type, Register VReg, const MachineFunction &MF)
SPIRVTypeInst getOrCreateSPIRVPointerType(const Type *BaseType, MachineIRBuilder &MIRBuilder, SPIRV::StorageClass::StorageClass SC, bool ForceTyped=false)
const TargetRegisterClass * getRegClass(SPIRVTypeInst SpvType) const
SPIRVTypeInst getOrCreateSPIRVVectorType(SPIRVTypeInst BaseType, unsigned NumElements, MachineIRBuilder &MIRBuilder, bool EmitIR)
const Type * getTypeForSPIRVType(SPIRVTypeInst Ty) const
LLT getRegType(SPIRVTypeInst SpvType) const
SPIRVTypeInst getScalarOrVectorComponentType(SPIRVTypeInst Type) const
SPIRVTypeInst getOrCreateSPIRVType(const Type *Type, MachineInstr &I, SPIRV::AccessQualifier::AccessQualifier AQ, bool EmitIR)
SPIRVTypeInst getSPIRVTypeForVReg(Register VReg, const MachineFunction *MF=nullptr) const
SPIRVLegalizerInfo(const SPIRVSubtarget &ST)
bool legalizeCustom(LegalizerHelper &Helper, MachineInstr &MI, LostDebugLocObserver &LocObserver) const override
Called for instructions with the Custom LegalizationAction.
bool legalizeIntrinsic(LegalizerHelper &Helper, MachineInstr &MI) const override
SPIRVGlobalRegistry * getSPIRVGlobalRegistry() const
void push_back(const T &Elt)
This is a 'vector' (really, a variable-sized array), optimized for the case when the array is small.
static constexpr TypeSize getFixed(ScalarTy ExactSize)
Definition TypeSize.h:352
The instances of the Type class are immutable: once they are created, they are never changed.
Definition Type.h:46
static LLVM_ABI VectorType * get(Type *ElementType, ElementCount EC)
This static method is the primary way to construct an VectorType.
constexpr std::underlying_type_t< E > Mask()
Get a bitmask with 1s in all places up to the high-order bit of E's largest value.
LLVM_ABI bool isTriviallyScalarizable(ID id)
Returns true if the intrinsic is trivially scalarizable.
LLVM_ABI LegalityPredicate isScalar(unsigned TypeIdx)
True iff the specified type index is a scalar.
LLVM_ABI LegalityPredicate numElementsNotPow2(unsigned TypeIdx)
True iff the specified type index is a vector whose element count is not a power of 2.
LLVM_ABI LegalityPredicate vectorElementCountIsLessThanOrEqualTo(unsigned TypeIdx, unsigned Size)
True iff the specified type index is a vector with a number of elements that's less than or equal to ...
LLVM_ABI LegalityPredicate typeInSet(unsigned TypeIdx, std::initializer_list< LLT > TypesInit)
True iff the given type index is one of the specified types.
LLVM_ABI LegalityPredicate vectorElementCountIsGreaterThan(unsigned TypeIdx, unsigned Size)
True iff the specified type index is a vector with a number of elements that's greater than the given...
Predicate any(Predicate P0, Predicate P1)
True iff P0 or P1 are true.
LegalityPredicate typeIsNot(unsigned TypeIdx, LLT Type)
True iff the given type index is not the specified type.
Predicate all(Predicate P0, Predicate P1)
True iff P0 and P1 are true.
LLVM_ABI LegalityPredicate typeIs(unsigned TypeIdx, LLT TypesInit)
True iff the given type index is the specified type.
LLVM_ABI LegalizeMutation changeElementCountTo(unsigned TypeIdx, unsigned FromTypeIdx)
Keep the same scalar or element type as TypeIdx, but take the number of elements from FromTypeIdx.
LLVM_ABI LegalizeMutation changeElementSizeTo(unsigned TypeIdx, unsigned FromTypeIdx)
Change the scalar size or element size to have the same scalar size as type index FromIndex.
Invariant opcodes: All instruction sets have these as their low opcodes.
This is an optimization pass for GlobalISel generic memory operations.
auto drop_begin(T &&RangeOrContainer, size_t N=1)
Return a range covering RangeOrContainer with the first N elements excluded.
Definition STLExtras.h:316
@ Offset
Definition DWP.cpp:577
LLVM_ABI const llvm::fltSemantics & getFltSemanticForLLT(LLT Ty)
Get the appropriate floating point arithmetic semantic based on the bit size of the given scalar LLT.
Register createVirtualRegister(SPIRVTypeInst SpvType, SPIRVGlobalRegistry *GR, MachineRegisterInfo *MRI, const MachineFunction &MF)
void append_range(Container &C, Range &&R)
Wrapper function to append range R to container C.
Definition STLExtras.h:2224
std::function< bool(const LegalityQuery &)> LegalityPredicate
MachineInstr * getImm(const MachineOperand &MO, const MachineRegisterInfo *MRI)
constexpr bool isPowerOf2_32(uint32_t Value)
Return true if the argument is a power of two > 0.
Definition MathExtras.h:280
FPClassTest
Floating-point class tests, supported by 'is_fpclass' intrinsic.
LLVM_ABI raw_ostream & dbgs()
dbgs() - This returns a reference to a raw_ostream for debugging messages.
Definition Debug.cpp:209
const std::set< unsigned > & getTypeFoldingSupportedOpcodes()
int64_t foldImm(const MachineOperand &MO, const MachineRegisterInfo *MRI)
ArrayRef(const T &OneElt) -> ArrayRef< T >
decltype(auto) cast(const From &Val)
cast<X> - Return the argument parameter cast to the specified type.
Definition Casting.h:559
Align commonAlignment(Align A, uint64_t Offset)
Returns the alignment that satisfies both alignments.
Definition Alignment.h:206
This struct is a compact representation of a valid (non-zero power of two) alignment.
Definition Alignment.h:39
The LegalityQuery object bundles together all the information that's needed to decide whether a given...
ArrayRef< LLT > Types
This class contains a discriminated union of information about pointers in memory operands,...
MachinePointerInfo getWithOffset(int64_t O) const