LLVM 22.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"
23#include "llvm/IR/IntrinsicsSPIRV.h"
24#include "llvm/Support/Debug.h"
26
27using namespace llvm;
28using namespace llvm::LegalizeActions;
29using namespace llvm::LegalityPredicates;
30
31#define DEBUG_TYPE "spirv-legalizer"
32
33LegalityPredicate typeOfExtendedScalars(unsigned TypeIdx, bool IsExtendedInts) {
34 return [IsExtendedInts, TypeIdx](const LegalityQuery &Query) {
35 const LLT Ty = Query.Types[TypeIdx];
36 return IsExtendedInts && Ty.isValid() && Ty.isScalar();
37 };
38}
39
41 using namespace TargetOpcode;
42
43 this->ST = &ST;
44 GR = ST.getSPIRVGlobalRegistry();
45
46 const LLT s1 = LLT::scalar(1);
47 const LLT s8 = LLT::scalar(8);
48 const LLT s16 = LLT::scalar(16);
49 const LLT s32 = LLT::scalar(32);
50 const LLT s64 = LLT::scalar(64);
51 const LLT s128 = LLT::scalar(128);
52
53 const LLT v16s64 = LLT::fixed_vector(16, 64);
54 const LLT v16s32 = LLT::fixed_vector(16, 32);
55 const LLT v16s16 = LLT::fixed_vector(16, 16);
56 const LLT v16s8 = LLT::fixed_vector(16, 8);
57 const LLT v16s1 = LLT::fixed_vector(16, 1);
58
59 const LLT v8s64 = LLT::fixed_vector(8, 64);
60 const LLT v8s32 = LLT::fixed_vector(8, 32);
61 const LLT v8s16 = LLT::fixed_vector(8, 16);
62 const LLT v8s8 = LLT::fixed_vector(8, 8);
63 const LLT v8s1 = LLT::fixed_vector(8, 1);
64
65 const LLT v4s64 = LLT::fixed_vector(4, 64);
66 const LLT v4s32 = LLT::fixed_vector(4, 32);
67 const LLT v4s16 = LLT::fixed_vector(4, 16);
68 const LLT v4s8 = LLT::fixed_vector(4, 8);
69 const LLT v4s1 = LLT::fixed_vector(4, 1);
70
71 const LLT v3s64 = LLT::fixed_vector(3, 64);
72 const LLT v3s32 = LLT::fixed_vector(3, 32);
73 const LLT v3s16 = LLT::fixed_vector(3, 16);
74 const LLT v3s8 = LLT::fixed_vector(3, 8);
75 const LLT v3s1 = LLT::fixed_vector(3, 1);
76
77 const LLT v2s64 = LLT::fixed_vector(2, 64);
78 const LLT v2s32 = LLT::fixed_vector(2, 32);
79 const LLT v2s16 = LLT::fixed_vector(2, 16);
80 const LLT v2s8 = LLT::fixed_vector(2, 8);
81 const LLT v2s1 = LLT::fixed_vector(2, 1);
82
83 const unsigned PSize = ST.getPointerSize();
84 const LLT p0 = LLT::pointer(0, PSize); // Function
85 const LLT p1 = LLT::pointer(1, PSize); // CrossWorkgroup
86 const LLT p2 = LLT::pointer(2, PSize); // UniformConstant
87 const LLT p3 = LLT::pointer(3, PSize); // Workgroup
88 const LLT p4 = LLT::pointer(4, PSize); // Generic
89 const LLT p5 =
90 LLT::pointer(5, PSize); // Input, SPV_INTEL_usm_storage_classes (Device)
91 const LLT p6 = LLT::pointer(6, PSize); // SPV_INTEL_usm_storage_classes (Host)
92 const LLT p7 = LLT::pointer(7, PSize); // Input
93 const LLT p8 = LLT::pointer(8, PSize); // Output
94 const LLT p9 =
95 LLT::pointer(9, PSize); // CodeSectionINTEL, SPV_INTEL_function_pointers
96 const LLT p10 = LLT::pointer(10, PSize); // Private
97 const LLT p11 = LLT::pointer(11, PSize); // StorageBuffer
98 const LLT p12 = LLT::pointer(12, PSize); // Uniform
99
100 // TODO: remove copy-pasting here by using concatenation in some way.
101 auto allPtrsScalarsAndVectors = {
102 p0, p1, p2, p3, p4, p5, p6, p7, p8,
103 p9, p10, p11, p12, s1, s8, s16, s32, s64,
104 v2s1, v2s8, v2s16, v2s32, v2s64, v3s1, v3s8, v3s16, v3s32,
105 v3s64, v4s1, v4s8, v4s16, v4s32, v4s64, v8s1, v8s8, v8s16,
106 v8s32, v8s64, v16s1, v16s8, v16s16, v16s32, v16s64};
107
108 auto allVectors = {v2s1, v2s8, v2s16, v2s32, v2s64, v3s1, v3s8,
109 v3s16, v3s32, v3s64, v4s1, v4s8, v4s16, v4s32,
110 v4s64, v8s1, v8s8, v8s16, v8s32, v8s64, v16s1,
111 v16s8, v16s16, v16s32, v16s64};
112
113 auto allShaderVectors = {v2s1, v2s8, v2s16, v2s32, v2s64,
114 v3s1, v3s8, v3s16, v3s32, v3s64,
115 v4s1, v4s8, v4s16, v4s32, v4s64};
116
117 auto allScalars = {s1, s8, s16, s32, s64};
118
119 auto allScalarsAndVectors = {
120 s1, s8, s16, s32, s64, s128, v2s1, v2s8,
121 v2s16, v2s32, v2s64, v3s1, v3s8, v3s16, v3s32, v3s64,
122 v4s1, v4s8, v4s16, v4s32, v4s64, v8s1, v8s8, v8s16,
123 v8s32, v8s64, v16s1, v16s8, v16s16, v16s32, v16s64};
124
125 auto allIntScalarsAndVectors = {
126 s8, s16, s32, s64, s128, v2s8, v2s16, v2s32, v2s64,
127 v3s8, v3s16, v3s32, v3s64, v4s8, v4s16, v4s32, v4s64, v8s8,
128 v8s16, v8s32, v8s64, v16s8, v16s16, v16s32, v16s64};
129
130 auto allBoolScalarsAndVectors = {s1, v2s1, v3s1, v4s1, v8s1, v16s1};
131
132 auto allIntScalars = {s8, s16, s32, s64, s128};
133
134 auto allFloatScalarsAndF16Vector2AndVector4s = {s16, s32, s64, v2s16, v4s16};
135
136 auto allFloatScalarsAndVectors = {
137 s16, s32, s64, v2s16, v2s32, v2s64, v3s16, v3s32, v3s64,
138 v4s16, v4s32, v4s64, v8s16, v8s32, v8s64, v16s16, v16s32, v16s64};
139
140 auto allFloatAndIntScalarsAndPtrs = {s8, s16, s32, s64, p0, p1, p2, p3, p4,
141 p5, p6, p7, p8, p9, p10, p11, p12};
142
143 auto allPtrs = {p0, p1, p2, p3, p4, p5, p6, p7, p8, p9, p10, p11, p12};
144
145 auto &allowedVectorTypes = ST.isShader() ? allShaderVectors : allVectors;
146
147 bool IsExtendedInts =
148 ST.canUseExtension(
149 SPIRV::Extension::SPV_ALTERA_arbitrary_precision_integers) ||
150 ST.canUseExtension(SPIRV::Extension::SPV_KHR_bit_instructions) ||
151 ST.canUseExtension(SPIRV::Extension::SPV_INTEL_int4);
152 auto extendedScalarsAndVectors =
153 [IsExtendedInts](const LegalityQuery &Query) {
154 const LLT Ty = Query.Types[0];
155 return IsExtendedInts && Ty.isValid() && !Ty.isPointerOrPointerVector();
156 };
157 auto extendedScalarsAndVectorsProduct = [IsExtendedInts](
158 const LegalityQuery &Query) {
159 const LLT Ty1 = Query.Types[0], Ty2 = Query.Types[1];
160 return IsExtendedInts && Ty1.isValid() && Ty2.isValid() &&
161 !Ty1.isPointerOrPointerVector() && !Ty2.isPointerOrPointerVector();
162 };
163 auto extendedPtrsScalarsAndVectors =
164 [IsExtendedInts](const LegalityQuery &Query) {
165 const LLT Ty = Query.Types[0];
166 return IsExtendedInts && Ty.isValid();
167 };
168
169 // The universal validation rules in the SPIR-V specification state that
170 // vector sizes are typically limited to 2, 3, or 4. However, larger vector
171 // sizes (8 and 16) are enabled when the Kernel capability is present. For
172 // shader execution models, vector sizes are strictly limited to 4. In
173 // non-shader contexts, vector sizes of 8 and 16 are also permitted, but
174 // arbitrary sizes (e.g., 6 or 11) are not.
175 uint32_t MaxVectorSize = ST.isShader() ? 4 : 16;
176
177 for (auto Opc : getTypeFoldingSupportedOpcodes()) {
178 switch (Opc) {
179 case G_EXTRACT_VECTOR_ELT:
180 case G_UREM:
181 case G_SREM:
182 case G_UDIV:
183 case G_SDIV:
184 case G_FREM:
185 break;
186 default:
188 .customFor(allScalars)
189 .customFor(allowedVectorTypes)
193 0, ElementCount::getFixed(MaxVectorSize)))
194 .custom();
195 break;
196 }
197 }
198
199 getActionDefinitionsBuilder({G_UREM, G_SREM, G_SDIV, G_UDIV, G_FREM})
200 .customFor(allScalars)
201 .customFor(allowedVectorTypes)
205 0, ElementCount::getFixed(MaxVectorSize)))
206 .custom();
207
208 getActionDefinitionsBuilder({G_FMA, G_STRICT_FMA})
209 .legalFor(allScalars)
210 .legalFor(allowedVectorTypes)
214 0, ElementCount::getFixed(MaxVectorSize)))
215 .alwaysLegal();
216
217 getActionDefinitionsBuilder(G_INTRINSIC_W_SIDE_EFFECTS).custom();
218
219 getActionDefinitionsBuilder(G_SHUFFLE_VECTOR)
220 .legalForCartesianProduct(allowedVectorTypes, allowedVectorTypes)
222 .lowerIf(vectorElementCountIsGreaterThan(0, MaxVectorSize))
224 .lowerIf(vectorElementCountIsGreaterThan(1, MaxVectorSize))
225 .alwaysLegal();
226
227 getActionDefinitionsBuilder(G_EXTRACT_VECTOR_ELT)
231 1, ElementCount::getFixed(MaxVectorSize)))
232 .custom();
233
234 getActionDefinitionsBuilder(G_INSERT_VECTOR_ELT)
238 0, ElementCount::getFixed(MaxVectorSize)))
239 .custom();
240
241 // Illegal G_UNMERGE_VALUES instructions should be handled
242 // during the combine phase.
243 getActionDefinitionsBuilder(G_BUILD_VECTOR)
247 0, ElementCount::getFixed(MaxVectorSize)));
248
249 // When entering the legalizer, there should be no G_BITCAST instructions.
250 // They should all be calls to the `spv_bitcast` intrinsic. The call to
251 // the intrinsic will be converted to a G_BITCAST during legalization if
252 // the vectors are not legal. After using the rules to legalize a G_BITCAST,
253 // we turn it back into a call to the intrinsic with a custom rule to avoid
254 // potential machine verifier failures.
260 0, ElementCount::getFixed(MaxVectorSize)))
261 .lowerIf(vectorElementCountIsGreaterThan(1, MaxVectorSize))
262 .custom();
263
264 // If the result is still illegal, the combiner should be able to remove it.
265 getActionDefinitionsBuilder(G_CONCAT_VECTORS)
266 .legalForCartesianProduct(allowedVectorTypes, allowedVectorTypes)
268
269 getActionDefinitionsBuilder(G_SPLAT_VECTOR)
270 .legalFor(allowedVectorTypes)
274 .alwaysLegal();
275
276 // Vector Reduction Operations
278 {G_VECREDUCE_SMIN, G_VECREDUCE_SMAX, G_VECREDUCE_UMIN, G_VECREDUCE_UMAX,
279 G_VECREDUCE_ADD, G_VECREDUCE_MUL, G_VECREDUCE_FMUL, G_VECREDUCE_FMIN,
280 G_VECREDUCE_FMAX, G_VECREDUCE_FMINIMUM, G_VECREDUCE_FMAXIMUM,
281 G_VECREDUCE_OR, G_VECREDUCE_AND, G_VECREDUCE_XOR})
282 .legalFor(allowedVectorTypes)
283 .scalarize(1)
284 .lower();
285
286 getActionDefinitionsBuilder({G_VECREDUCE_SEQ_FADD, G_VECREDUCE_SEQ_FMUL})
287 .scalarize(2)
288 .lower();
289
290 // Illegal G_UNMERGE_VALUES instructions should be handled
291 // during the combine phase.
292 getActionDefinitionsBuilder(G_UNMERGE_VALUES)
294
295 getActionDefinitionsBuilder({G_MEMCPY, G_MEMMOVE})
296 .unsupportedIf(LegalityPredicates::any(typeIs(0, p9), typeIs(1, p9)))
297 .legalIf(all(typeInSet(0, allPtrs), typeInSet(1, allPtrs)));
298
300 .unsupportedIf(typeIs(0, p9))
301 .legalIf(all(typeInSet(0, allPtrs), typeInSet(1, allIntScalars)));
302
303 getActionDefinitionsBuilder(G_ADDRSPACE_CAST)
306 all(typeIsNot(0, p9), typeIs(1, p9))))
307 .legalForCartesianProduct(allPtrs, allPtrs);
308
309 getActionDefinitionsBuilder({G_LOAD, G_STORE})
310 .unsupportedIf(typeIs(1, p9))
311 .legalIf(typeInSet(1, allPtrs));
312
313 getActionDefinitionsBuilder({G_SMIN, G_SMAX, G_UMIN, G_UMAX, G_ABS,
314 G_BITREVERSE, G_SADDSAT, G_UADDSAT, G_SSUBSAT,
315 G_USUBSAT, G_SCMP, G_UCMP})
316 .legalFor(allIntScalarsAndVectors)
317 .legalIf(extendedScalarsAndVectors);
318
319 getActionDefinitionsBuilder(G_STRICT_FLDEXP)
320 .legalForCartesianProduct(allFloatScalarsAndVectors, allIntScalars);
321
322 getActionDefinitionsBuilder({G_FPTOSI, G_FPTOUI})
323 .legalForCartesianProduct(allIntScalarsAndVectors,
324 allFloatScalarsAndVectors);
325
326 getActionDefinitionsBuilder({G_FPTOSI_SAT, G_FPTOUI_SAT})
327 .legalForCartesianProduct(allIntScalarsAndVectors,
328 allFloatScalarsAndVectors);
329
330 getActionDefinitionsBuilder({G_SITOFP, G_UITOFP})
331 .legalForCartesianProduct(allFloatScalarsAndVectors,
332 allScalarsAndVectors);
333
335 .legalForCartesianProduct(allIntScalarsAndVectors)
336 .legalIf(extendedScalarsAndVectorsProduct);
337
338 // Extensions.
339 getActionDefinitionsBuilder({G_TRUNC, G_ZEXT, G_SEXT, G_ANYEXT})
340 .legalForCartesianProduct(allScalarsAndVectors)
341 .legalIf(extendedScalarsAndVectorsProduct);
342
344 .legalFor(allPtrsScalarsAndVectors)
345 .legalIf(extendedPtrsScalarsAndVectors);
346
348 all(typeInSet(0, allPtrsScalarsAndVectors),
349 typeInSet(1, allPtrsScalarsAndVectors)));
350
351 getActionDefinitionsBuilder({G_IMPLICIT_DEF, G_FREEZE})
352 .legalFor({s1, s128})
353 .legalFor(allFloatAndIntScalarsAndPtrs)
354 .legalFor(allowedVectorTypes)
358 0, ElementCount::getFixed(MaxVectorSize)));
359
360 getActionDefinitionsBuilder({G_STACKSAVE, G_STACKRESTORE}).alwaysLegal();
361
363 .legalForCartesianProduct(allPtrs, allIntScalars)
364 .legalIf(
365 all(typeInSet(0, allPtrs), typeOfExtendedScalars(1, IsExtendedInts)));
367 .legalForCartesianProduct(allIntScalars, allPtrs)
368 .legalIf(
369 all(typeOfExtendedScalars(0, IsExtendedInts), typeInSet(1, allPtrs)));
371 .legalForCartesianProduct(allPtrs, allIntScalars)
372 .legalIf(
373 all(typeInSet(0, allPtrs), typeOfExtendedScalars(1, IsExtendedInts)));
374
375 // ST.canDirectlyComparePointers() for pointer args is supported in
376 // legalizeCustom().
379 all(typeIs(0, p9), typeInSet(1, allPtrs), typeIsNot(1, p9)),
380 all(typeInSet(0, allPtrs), typeIsNot(0, p9), typeIs(1, p9))))
381 .customIf(all(typeInSet(0, allBoolScalarsAndVectors),
382 typeInSet(1, allPtrsScalarsAndVectors)));
383
385 all(typeInSet(0, allBoolScalarsAndVectors),
386 typeInSet(1, allFloatScalarsAndVectors)));
387
388 getActionDefinitionsBuilder({G_ATOMICRMW_OR, G_ATOMICRMW_ADD, G_ATOMICRMW_AND,
389 G_ATOMICRMW_MAX, G_ATOMICRMW_MIN,
390 G_ATOMICRMW_SUB, G_ATOMICRMW_XOR,
391 G_ATOMICRMW_UMAX, G_ATOMICRMW_UMIN})
392 .legalForCartesianProduct(allIntScalars, allPtrs);
393
395 {G_ATOMICRMW_FADD, G_ATOMICRMW_FSUB, G_ATOMICRMW_FMIN, G_ATOMICRMW_FMAX})
396 .legalForCartesianProduct(allFloatScalarsAndF16Vector2AndVector4s,
397 allPtrs);
398
399 getActionDefinitionsBuilder(G_ATOMICRMW_XCHG)
400 .legalForCartesianProduct(allFloatAndIntScalarsAndPtrs, allPtrs);
401
402 getActionDefinitionsBuilder(G_ATOMIC_CMPXCHG_WITH_SUCCESS).lower();
403 // TODO: add proper legalization rules.
404 getActionDefinitionsBuilder(G_ATOMIC_CMPXCHG).alwaysLegal();
405
407 {G_UADDO, G_SADDO, G_USUBO, G_SSUBO, G_UMULO, G_SMULO})
408 .alwaysLegal();
409
410 getActionDefinitionsBuilder({G_LROUND, G_LLROUND})
411 .legalForCartesianProduct(allFloatScalarsAndVectors,
412 allIntScalarsAndVectors);
413
414 // FP conversions.
415 getActionDefinitionsBuilder({G_FPTRUNC, G_FPEXT})
416 .legalForCartesianProduct(allFloatScalarsAndVectors);
417
418 // Pointer-handling.
419 getActionDefinitionsBuilder(G_FRAME_INDEX).legalFor({p0});
420
421 getActionDefinitionsBuilder(G_GLOBAL_VALUE).legalFor(allPtrs);
422
423 // Control-flow. In some cases (e.g. constants) s1 may be promoted to s32.
424 getActionDefinitionsBuilder(G_BRCOND).legalFor({s1, s32});
425
427 allFloatScalarsAndVectors, {s32, v2s32, v3s32, v4s32, v8s32, v16s32});
428
429 // TODO: Review the target OpenCL and GLSL Extended Instruction Set specs to
430 // tighten these requirements. Many of these math functions are only legal on
431 // specific bitwidths, so they are not selectable for
432 // allFloatScalarsAndVectors.
433 getActionDefinitionsBuilder({G_STRICT_FSQRT,
434 G_FPOW,
435 G_FEXP,
436 G_FMODF,
437 G_FEXP2,
438 G_FLOG,
439 G_FLOG2,
440 G_FLOG10,
441 G_FABS,
442 G_FMINNUM,
443 G_FMAXNUM,
444 G_FCEIL,
445 G_FCOS,
446 G_FSIN,
447 G_FTAN,
448 G_FACOS,
449 G_FASIN,
450 G_FATAN,
451 G_FATAN2,
452 G_FCOSH,
453 G_FSINH,
454 G_FTANH,
455 G_FSQRT,
456 G_FFLOOR,
457 G_FRINT,
458 G_FNEARBYINT,
459 G_INTRINSIC_ROUND,
460 G_INTRINSIC_TRUNC,
461 G_FMINIMUM,
462 G_FMAXIMUM,
463 G_INTRINSIC_ROUNDEVEN})
464 .legalFor(allFloatScalarsAndVectors);
465
466 getActionDefinitionsBuilder(G_FCOPYSIGN)
467 .legalForCartesianProduct(allFloatScalarsAndVectors,
468 allFloatScalarsAndVectors);
469
471 allFloatScalarsAndVectors, allIntScalarsAndVectors);
472
473 if (ST.canUseExtInstSet(SPIRV::InstructionSet::OpenCL_std)) {
475 {G_CTTZ, G_CTTZ_ZERO_UNDEF, G_CTLZ, G_CTLZ_ZERO_UNDEF})
476 .legalForCartesianProduct(allIntScalarsAndVectors,
477 allIntScalarsAndVectors);
478
479 // Struct return types become a single scalar, so cannot easily legalize.
480 getActionDefinitionsBuilder({G_SMULH, G_UMULH}).alwaysLegal();
481 }
482
483 getActionDefinitionsBuilder(G_IS_FPCLASS).custom();
484
486 verify(*ST.getInstrInfo());
487}
488
491 MachineIRBuilder &MIRBuilder = Helper.MIRBuilder;
492 Register DstReg = MI.getOperand(0).getReg();
493 Register SrcReg = MI.getOperand(1).getReg();
494 Register IdxReg = MI.getOperand(2).getReg();
495
496 MIRBuilder
497 .buildIntrinsic(Intrinsic::spv_extractelt, ArrayRef<Register>{DstReg})
498 .addUse(SrcReg)
499 .addUse(IdxReg);
500 MI.eraseFromParent();
501 return true;
502}
503
506 MachineIRBuilder &MIRBuilder = Helper.MIRBuilder;
507 Register DstReg = MI.getOperand(0).getReg();
508 Register SrcReg = MI.getOperand(1).getReg();
509 Register ValReg = MI.getOperand(2).getReg();
510 Register IdxReg = MI.getOperand(3).getReg();
511
512 MIRBuilder
513 .buildIntrinsic(Intrinsic::spv_insertelt, ArrayRef<Register>{DstReg})
514 .addUse(SrcReg)
515 .addUse(ValReg)
516 .addUse(IdxReg);
517 MI.eraseFromParent();
518 return true;
519}
520
522 LegalizerHelper &Helper,
525 Register ConvReg = MRI.createGenericVirtualRegister(ConvTy);
526 MRI.setRegClass(ConvReg, GR->getRegClass(SpvType));
527 GR->assignSPIRVTypeToVReg(SpvType, ConvReg, Helper.MIRBuilder.getMF());
528 Helper.MIRBuilder.buildInstr(TargetOpcode::G_PTRTOINT)
529 .addDef(ConvReg)
530 .addUse(Reg);
531 return ConvReg;
532}
533
536 LostDebugLocObserver &LocObserver) const {
537 MachineRegisterInfo &MRI = MI.getMF()->getRegInfo();
538 switch (MI.getOpcode()) {
539 default:
540 // TODO: implement legalization for other opcodes.
541 return true;
542 case TargetOpcode::G_BITCAST:
543 return legalizeBitcast(Helper, MI);
544 case TargetOpcode::G_EXTRACT_VECTOR_ELT:
545 return legalizeExtractVectorElt(Helper, MI, GR);
546 case TargetOpcode::G_INSERT_VECTOR_ELT:
547 return legalizeInsertVectorElt(Helper, MI, GR);
548 case TargetOpcode::G_INTRINSIC:
549 case TargetOpcode::G_INTRINSIC_W_SIDE_EFFECTS:
550 return legalizeIntrinsic(Helper, MI);
551 case TargetOpcode::G_IS_FPCLASS:
552 return legalizeIsFPClass(Helper, MI, LocObserver);
553 case TargetOpcode::G_ICMP: {
554 assert(GR->getSPIRVTypeForVReg(MI.getOperand(0).getReg()));
555 auto &Op0 = MI.getOperand(2);
556 auto &Op1 = MI.getOperand(3);
557 Register Reg0 = Op0.getReg();
558 Register Reg1 = Op1.getReg();
560 static_cast<CmpInst::Predicate>(MI.getOperand(1).getPredicate());
561 if ((!ST->canDirectlyComparePointers() ||
563 MRI.getType(Reg0).isPointer() && MRI.getType(Reg1).isPointer()) {
564 LLT ConvT = LLT::scalar(ST->getPointerSize());
565 Type *LLVMTy = IntegerType::get(MI.getMF()->getFunction().getContext(),
566 ST->getPointerSize());
567 SPIRVType *SpirvTy = GR->getOrCreateSPIRVType(
568 LLVMTy, Helper.MIRBuilder, SPIRV::AccessQualifier::ReadWrite, true);
569 Op0.setReg(convertPtrToInt(Reg0, ConvT, SpirvTy, Helper, MRI, GR));
570 Op1.setReg(convertPtrToInt(Reg1, ConvT, SpirvTy, Helper, MRI, GR));
571 }
572 return true;
573 }
574 }
575}
576
577static bool needsVectorLegalization(const LLT &Ty, const SPIRVSubtarget &ST) {
578 if (!Ty.isVector())
579 return false;
580 unsigned NumElements = Ty.getNumElements();
581 unsigned MaxVectorSize = ST.isShader() ? 4 : 16;
582 return (NumElements > 4 && !isPowerOf2_32(NumElements)) ||
583 NumElements > MaxVectorSize;
584}
585
587 MachineInstr &MI) const {
588 LLVM_DEBUG(dbgs() << "legalizeIntrinsic: " << MI);
589
590 MachineIRBuilder &MIRBuilder = Helper.MIRBuilder;
591 MachineRegisterInfo &MRI = *MIRBuilder.getMRI();
592 const SPIRVSubtarget &ST = MI.getMF()->getSubtarget<SPIRVSubtarget>();
593
594 auto IntrinsicID = cast<GIntrinsic>(MI).getIntrinsicID();
595 if (IntrinsicID == Intrinsic::spv_bitcast) {
596 LLVM_DEBUG(dbgs() << "Found a bitcast instruction\n");
597 Register DstReg = MI.getOperand(0).getReg();
598 Register SrcReg = MI.getOperand(2).getReg();
599 LLT DstTy = MRI.getType(DstReg);
600 LLT SrcTy = MRI.getType(SrcReg);
601
602 // If an spv_bitcast needs to be legalized, we convert it to G_BITCAST to
603 // allow using the generic legalization rules.
604 if (needsVectorLegalization(DstTy, ST) ||
605 needsVectorLegalization(SrcTy, ST)) {
606 LLVM_DEBUG(dbgs() << "Replacing with a G_BITCAST\n");
607 MIRBuilder.buildBitcast(DstReg, SrcReg);
608 MI.eraseFromParent();
609 }
610 return true;
611 } else if (IntrinsicID == Intrinsic::spv_insertelt) {
612 Register DstReg = MI.getOperand(0).getReg();
613 LLT DstTy = MRI.getType(DstReg);
614
615 if (needsVectorLegalization(DstTy, ST)) {
616 Register SrcReg = MI.getOperand(2).getReg();
617 Register ValReg = MI.getOperand(3).getReg();
618 Register IdxReg = MI.getOperand(4).getReg();
619 MIRBuilder.buildInsertVectorElement(DstReg, SrcReg, ValReg, IdxReg);
620 MI.eraseFromParent();
621 }
622 return true;
623 } else if (IntrinsicID == Intrinsic::spv_extractelt) {
624 Register SrcReg = MI.getOperand(2).getReg();
625 LLT SrcTy = MRI.getType(SrcReg);
626
627 if (needsVectorLegalization(SrcTy, ST)) {
628 Register DstReg = MI.getOperand(0).getReg();
629 Register IdxReg = MI.getOperand(3).getReg();
630 MIRBuilder.buildExtractVectorElement(DstReg, SrcReg, IdxReg);
631 MI.eraseFromParent();
632 }
633 return true;
634 }
635 return true;
636}
637
638bool SPIRVLegalizerInfo::legalizeBitcast(LegalizerHelper &Helper,
639 MachineInstr &MI) const {
640 // Once the G_BITCAST is using vectors that are allowed, we turn it back into
641 // an spv_bitcast to avoid verifier problems when the register types are the
642 // same for the source and the result. Note that the SPIR-V types associated
643 // with the bitcast can be different even if the register types are the same.
644 MachineIRBuilder &MIRBuilder = Helper.MIRBuilder;
645 Register DstReg = MI.getOperand(0).getReg();
646 Register SrcReg = MI.getOperand(1).getReg();
647 SmallVector<Register, 1> DstRegs = {DstReg};
648 MIRBuilder.buildIntrinsic(Intrinsic::spv_bitcast, DstRegs).addUse(SrcReg);
649 MI.eraseFromParent();
650 return true;
651}
652
653// Note this code was copied from LegalizerHelper::lowerISFPCLASS and adjusted
654// to ensure that all instructions created during the lowering have SPIR-V types
655// assigned to them.
656bool SPIRVLegalizerInfo::legalizeIsFPClass(
658 LostDebugLocObserver &LocObserver) const {
659 auto [DstReg, DstTy, SrcReg, SrcTy] = MI.getFirst2RegLLTs();
660 FPClassTest Mask = static_cast<FPClassTest>(MI.getOperand(2).getImm());
661
662 auto &MIRBuilder = Helper.MIRBuilder;
663 auto &MF = MIRBuilder.getMF();
664 MachineRegisterInfo &MRI = MF.getRegInfo();
665
666 Type *LLVMDstTy =
667 IntegerType::get(MIRBuilder.getContext(), DstTy.getScalarSizeInBits());
668 if (DstTy.isVector())
669 LLVMDstTy = VectorType::get(LLVMDstTy, DstTy.getElementCount());
670 SPIRVType *SPIRVDstTy = GR->getOrCreateSPIRVType(
671 LLVMDstTy, MIRBuilder, SPIRV::AccessQualifier::ReadWrite,
672 /*EmitIR*/ true);
673
674 unsigned BitSize = SrcTy.getScalarSizeInBits();
675 const fltSemantics &Semantics = getFltSemanticForLLT(SrcTy.getScalarType());
676
677 LLT IntTy = LLT::scalar(BitSize);
678 Type *LLVMIntTy = IntegerType::get(MIRBuilder.getContext(), BitSize);
679 if (SrcTy.isVector()) {
680 IntTy = LLT::vector(SrcTy.getElementCount(), IntTy);
681 LLVMIntTy = VectorType::get(LLVMIntTy, SrcTy.getElementCount());
682 }
683 SPIRVType *SPIRVIntTy = GR->getOrCreateSPIRVType(
684 LLVMIntTy, MIRBuilder, SPIRV::AccessQualifier::ReadWrite,
685 /*EmitIR*/ true);
686
687 // Clang doesn't support capture of structured bindings:
688 LLT DstTyCopy = DstTy;
689 const auto assignSPIRVTy = [&](MachineInstrBuilder &&MI) {
690 // Assign this MI's (assumed only) destination to one of the two types we
691 // expect: either the G_IS_FPCLASS's destination type, or the integer type
692 // bitcast from the source type.
693 LLT MITy = MRI.getType(MI.getReg(0));
694 assert((MITy == IntTy || MITy == DstTyCopy) &&
695 "Unexpected LLT type while lowering G_IS_FPCLASS");
696 auto *SPVTy = MITy == IntTy ? SPIRVIntTy : SPIRVDstTy;
697 GR->assignSPIRVTypeToVReg(SPVTy, MI.getReg(0), MF);
698 return MI;
699 };
700
701 // Helper to build and assign a constant in one go
702 const auto buildSPIRVConstant = [&](LLT Ty, auto &&C) -> MachineInstrBuilder {
703 if (!Ty.isFixedVector())
704 return assignSPIRVTy(MIRBuilder.buildConstant(Ty, C));
705 auto ScalarC = MIRBuilder.buildConstant(Ty.getScalarType(), C);
706 assert((Ty == IntTy || Ty == DstTyCopy) &&
707 "Unexpected LLT type while lowering constant for G_IS_FPCLASS");
708 SPIRVType *VecEltTy = GR->getOrCreateSPIRVType(
709 (Ty == IntTy ? LLVMIntTy : LLVMDstTy)->getScalarType(), MIRBuilder,
710 SPIRV::AccessQualifier::ReadWrite,
711 /*EmitIR*/ true);
712 GR->assignSPIRVTypeToVReg(VecEltTy, ScalarC.getReg(0), MF);
713 return assignSPIRVTy(MIRBuilder.buildSplatBuildVector(Ty, ScalarC));
714 };
715
716 if (Mask == fcNone) {
717 MIRBuilder.buildCopy(DstReg, buildSPIRVConstant(DstTy, 0));
718 MI.eraseFromParent();
719 return true;
720 }
721 if (Mask == fcAllFlags) {
722 MIRBuilder.buildCopy(DstReg, buildSPIRVConstant(DstTy, 1));
723 MI.eraseFromParent();
724 return true;
725 }
726
727 // Note that rather than creating a COPY here (between a floating-point and
728 // integer type of the same size) we create a SPIR-V bitcast immediately. We
729 // can't create a G_BITCAST because the LLTs are the same, and we can't seem
730 // to correctly lower COPYs to SPIR-V bitcasts at this moment.
731 Register ResVReg = MRI.createGenericVirtualRegister(IntTy);
732 MRI.setRegClass(ResVReg, GR->getRegClass(SPIRVIntTy));
733 GR->assignSPIRVTypeToVReg(SPIRVIntTy, ResVReg, Helper.MIRBuilder.getMF());
734 auto AsInt = MIRBuilder.buildInstr(SPIRV::OpBitcast)
735 .addDef(ResVReg)
736 .addUse(GR->getSPIRVTypeID(SPIRVIntTy))
737 .addUse(SrcReg);
738 AsInt = assignSPIRVTy(std::move(AsInt));
739
740 // Various masks.
741 APInt SignBit = APInt::getSignMask(BitSize);
742 APInt ValueMask = APInt::getSignedMaxValue(BitSize); // All bits but sign.
743 APInt Inf = APFloat::getInf(Semantics).bitcastToAPInt(); // Exp and int bit.
744 APInt ExpMask = Inf;
745 APInt AllOneMantissa = APFloat::getLargest(Semantics).bitcastToAPInt() & ~Inf;
746 APInt QNaNBitMask =
747 APInt::getOneBitSet(BitSize, AllOneMantissa.getActiveBits() - 1);
748 APInt InversionMask = APInt::getAllOnes(DstTy.getScalarSizeInBits());
749
750 auto SignBitC = buildSPIRVConstant(IntTy, SignBit);
751 auto ValueMaskC = buildSPIRVConstant(IntTy, ValueMask);
752 auto InfC = buildSPIRVConstant(IntTy, Inf);
753 auto ExpMaskC = buildSPIRVConstant(IntTy, ExpMask);
754 auto ZeroC = buildSPIRVConstant(IntTy, 0);
755
756 auto Abs = assignSPIRVTy(MIRBuilder.buildAnd(IntTy, AsInt, ValueMaskC));
757 auto Sign = assignSPIRVTy(
758 MIRBuilder.buildICmp(CmpInst::Predicate::ICMP_NE, DstTy, AsInt, Abs));
759
760 auto Res = buildSPIRVConstant(DstTy, 0);
761
762 const auto appendToRes = [&](MachineInstrBuilder &&ToAppend) {
763 Res = assignSPIRVTy(
764 MIRBuilder.buildOr(DstTyCopy, Res, assignSPIRVTy(std::move(ToAppend))));
765 };
766
767 // Tests that involve more than one class should be processed first.
768 if ((Mask & fcFinite) == fcFinite) {
769 // finite(V) ==> abs(V) u< exp_mask
770 appendToRes(MIRBuilder.buildICmp(CmpInst::Predicate::ICMP_ULT, DstTy, Abs,
771 ExpMaskC));
772 Mask &= ~fcFinite;
773 } else if ((Mask & fcFinite) == fcPosFinite) {
774 // finite(V) && V > 0 ==> V u< exp_mask
775 appendToRes(MIRBuilder.buildICmp(CmpInst::Predicate::ICMP_ULT, DstTy, AsInt,
776 ExpMaskC));
777 Mask &= ~fcPosFinite;
778 } else if ((Mask & fcFinite) == fcNegFinite) {
779 // finite(V) && V < 0 ==> abs(V) u< exp_mask && signbit == 1
780 auto Cmp = assignSPIRVTy(MIRBuilder.buildICmp(CmpInst::Predicate::ICMP_ULT,
781 DstTy, Abs, ExpMaskC));
782 appendToRes(MIRBuilder.buildAnd(DstTy, Cmp, Sign));
783 Mask &= ~fcNegFinite;
784 }
785
786 if (FPClassTest PartialCheck = Mask & (fcZero | fcSubnormal)) {
787 // fcZero | fcSubnormal => test all exponent bits are 0
788 // TODO: Handle sign bit specific cases
789 // TODO: Handle inverted case
790 if (PartialCheck == (fcZero | fcSubnormal)) {
791 auto ExpBits = assignSPIRVTy(MIRBuilder.buildAnd(IntTy, AsInt, ExpMaskC));
792 appendToRes(MIRBuilder.buildICmp(CmpInst::Predicate::ICMP_EQ, DstTy,
793 ExpBits, ZeroC));
794 Mask &= ~PartialCheck;
795 }
796 }
797
798 // Check for individual classes.
799 if (FPClassTest PartialCheck = Mask & fcZero) {
800 if (PartialCheck == fcPosZero)
801 appendToRes(MIRBuilder.buildICmp(CmpInst::Predicate::ICMP_EQ, DstTy,
802 AsInt, ZeroC));
803 else if (PartialCheck == fcZero)
804 appendToRes(
805 MIRBuilder.buildICmp(CmpInst::Predicate::ICMP_EQ, DstTy, Abs, ZeroC));
806 else // fcNegZero
807 appendToRes(MIRBuilder.buildICmp(CmpInst::Predicate::ICMP_EQ, DstTy,
808 AsInt, SignBitC));
809 }
810
811 if (FPClassTest PartialCheck = Mask & fcSubnormal) {
812 // issubnormal(V) ==> unsigned(abs(V) - 1) u< (all mantissa bits set)
813 // issubnormal(V) && V>0 ==> unsigned(V - 1) u< (all mantissa bits set)
814 auto V = (PartialCheck == fcPosSubnormal) ? AsInt : Abs;
815 auto OneC = buildSPIRVConstant(IntTy, 1);
816 auto VMinusOne = MIRBuilder.buildSub(IntTy, V, OneC);
817 auto SubnormalRes = assignSPIRVTy(
818 MIRBuilder.buildICmp(CmpInst::Predicate::ICMP_ULT, DstTy, VMinusOne,
819 buildSPIRVConstant(IntTy, AllOneMantissa)));
820 if (PartialCheck == fcNegSubnormal)
821 SubnormalRes = MIRBuilder.buildAnd(DstTy, SubnormalRes, Sign);
822 appendToRes(std::move(SubnormalRes));
823 }
824
825 if (FPClassTest PartialCheck = Mask & fcInf) {
826 if (PartialCheck == fcPosInf)
827 appendToRes(MIRBuilder.buildICmp(CmpInst::Predicate::ICMP_EQ, DstTy,
828 AsInt, InfC));
829 else if (PartialCheck == fcInf)
830 appendToRes(
831 MIRBuilder.buildICmp(CmpInst::Predicate::ICMP_EQ, DstTy, Abs, InfC));
832 else { // fcNegInf
833 APInt NegInf = APFloat::getInf(Semantics, true).bitcastToAPInt();
834 auto NegInfC = buildSPIRVConstant(IntTy, NegInf);
835 appendToRes(MIRBuilder.buildICmp(CmpInst::Predicate::ICMP_EQ, DstTy,
836 AsInt, NegInfC));
837 }
838 }
839
840 if (FPClassTest PartialCheck = Mask & fcNan) {
841 auto InfWithQnanBitC =
842 buildSPIRVConstant(IntTy, std::move(Inf) | QNaNBitMask);
843 if (PartialCheck == fcNan) {
844 // isnan(V) ==> abs(V) u> int(inf)
845 appendToRes(
846 MIRBuilder.buildICmp(CmpInst::Predicate::ICMP_UGT, DstTy, Abs, InfC));
847 } else if (PartialCheck == fcQNan) {
848 // isquiet(V) ==> abs(V) u>= (unsigned(Inf) | quiet_bit)
849 appendToRes(MIRBuilder.buildICmp(CmpInst::Predicate::ICMP_UGE, DstTy, Abs,
850 InfWithQnanBitC));
851 } else { // fcSNan
852 // issignaling(V) ==> abs(V) u> unsigned(Inf) &&
853 // abs(V) u< (unsigned(Inf) | quiet_bit)
854 auto IsNan = assignSPIRVTy(
855 MIRBuilder.buildICmp(CmpInst::Predicate::ICMP_UGT, DstTy, Abs, InfC));
856 auto IsNotQnan = assignSPIRVTy(MIRBuilder.buildICmp(
857 CmpInst::Predicate::ICMP_ULT, DstTy, Abs, InfWithQnanBitC));
858 appendToRes(MIRBuilder.buildAnd(DstTy, IsNan, IsNotQnan));
859 }
860 }
861
862 if (FPClassTest PartialCheck = Mask & fcNormal) {
863 // isnormal(V) ==> (0 u< exp u< max_exp) ==> (unsigned(exp-1) u<
864 // (max_exp-1))
865 APInt ExpLSB = ExpMask & ~(ExpMask.shl(1));
866 auto ExpMinusOne = assignSPIRVTy(
867 MIRBuilder.buildSub(IntTy, Abs, buildSPIRVConstant(IntTy, ExpLSB)));
868 APInt MaxExpMinusOne = std::move(ExpMask) - ExpLSB;
869 auto NormalRes = assignSPIRVTy(
870 MIRBuilder.buildICmp(CmpInst::Predicate::ICMP_ULT, DstTy, ExpMinusOne,
871 buildSPIRVConstant(IntTy, MaxExpMinusOne)));
872 if (PartialCheck == fcNegNormal)
873 NormalRes = MIRBuilder.buildAnd(DstTy, NormalRes, Sign);
874 else if (PartialCheck == fcPosNormal) {
875 auto PosSign = assignSPIRVTy(MIRBuilder.buildXor(
876 DstTy, Sign, buildSPIRVConstant(DstTy, InversionMask)));
877 NormalRes = MIRBuilder.buildAnd(DstTy, NormalRes, PosSign);
878 }
879 appendToRes(std::move(NormalRes));
880 }
881
882 MIRBuilder.buildCopy(DstReg, Res);
883 MI.eraseFromParent();
884 return true;
885}
unsigned const MachineRegisterInfo * MRI
assert(UImm &&(UImm !=~static_cast< T >(0)) &&"Invalid immediate!")
static void scalarize(Instruction *I, SmallVectorImpl< Instruction * > &Worklist)
Definition ExpandFp.cpp:947
Declares convenience wrapper classes for interpreting MachineInstr instances as specific generic oper...
IRTranslator LLVM IR MI
This file declares the MachineIRBuilder class.
Register Reg
Promote Memory to Register
Definition Mem2Reg.cpp:110
ppc ctr loops verify
const SmallVectorImpl< MachineOperand > & Cond
static bool needsVectorLegalization(const LLT &Ty, const SPIRVSubtarget &ST)
static Register convertPtrToInt(Register Reg, LLT ConvTy, SPIRVType *SpvType, LegalizerHelper &Helper, MachineRegisterInfo &MRI, SPIRVGlobalRegistry *GR)
LegalityPredicate typeOfExtendedScalars(unsigned TypeIdx, bool IsExtendedInts)
static bool legalizeExtractVectorElt(LegalizerHelper &Helper, MachineInstr &MI, SPIRVGlobalRegistry *GR)
static bool legalizeInsertVectorElt(LegalizerHelper &Helper, MachineInstr &MI, SPIRVGlobalRegistry *GR)
#define LLVM_DEBUG(...)
Definition Debug.h:114
APInt bitcastToAPInt() const
Definition APFloat.h:1335
static APFloat getLargest(const fltSemantics &Sem, bool Negative=false)
Returns the largest finite number in the given semantics.
Definition APFloat.h:1120
static APFloat getInf(const fltSemantics &Sem, bool Negative=false)
Factory for Positive and Negative Infinity.
Definition APFloat.h:1080
static APInt getAllOnes(unsigned numBits)
Return an APInt of a specified width with all bits set.
Definition APInt.h:235
static APInt getSignMask(unsigned BitWidth)
Get the SignMask for a specific bit width.
Definition APInt.h:230
unsigned getActiveBits() const
Compute the number of active bits in the value.
Definition APInt.h:1513
static APInt getSignedMaxValue(unsigned numBits)
Gets maximum signed value of APInt for a specific bit width.
Definition APInt.h:210
APInt shl(unsigned shiftAmt) const
Left-shift function.
Definition APInt.h:874
static APInt getOneBitSet(unsigned numBits, unsigned BitNo)
Return an APInt with exactly one bit set in the result.
Definition APInt.h:240
ArrayRef - Represent a constant reference to an array (0 or more elements consecutively in memory),...
Definition ArrayRef.h:40
Predicate
This enumeration lists the possible predicates for CmpInst subclasses.
Definition InstrTypes.h:676
@ ICMP_UGE
unsigned greater or equal
Definition InstrTypes.h:700
@ ICMP_UGT
unsigned greater than
Definition InstrTypes.h:699
@ ICMP_ULT
unsigned less than
Definition InstrTypes.h:701
@ ICMP_NE
not equal
Definition InstrTypes.h:698
static constexpr ElementCount getFixed(ScalarTy MinVal)
Definition TypeSize.h:309
static LLVM_ABI IntegerType * get(LLVMContext &C, unsigned NumBits)
This static method is the primary way of constructing an IntegerType.
Definition Type.cpp:318
static constexpr LLT vector(ElementCount EC, unsigned ScalarSizeInBits)
Get a low-level vector of some number of elements and element width.
static constexpr LLT scalar(unsigned SizeInBits)
Get a low-level scalar or aggregate "bag of bits".
constexpr bool isValid() const
static constexpr LLT pointer(unsigned AddressSpace, unsigned SizeInBits)
Get a low-level pointer in the given address space.
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 LLT getScalarType() const
LLVM_ABI void computeTables()
Compute any ancillary tables needed to quickly decide how an operation should be handled.
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 & 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)
MachineIRBuilder & MIRBuilder
Expose MIRBuilder so clients can set their own RecordInsertInstruction functions.
LegalizeRuleSet & getActionDefinitionsBuilder(unsigned Opcode)
Get the action definition builder for the given opcode.
const LegacyLegalizerInfo & getLegacyLegalizerInfo() const
Helper class to build MachineInstr.
LLVMContext & getContext() const
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 buildExtractVectorElement(const DstOp &Res, const SrcOp &Val, const SrcOp &Idx)
Build and insert Res = G_EXTRACT_VECTOR_ELT Val, Idx.
MachineInstrBuilder buildInstr(unsigned Opcode)
Build and insert <empty> = Opcode <empty>.
MachineFunction & getMF()
Getter for the function we currently build.
MachineInstrBuilder buildInsertVectorElement(const DstOp &Res, const SrcOp &Val, const SrcOp &Elt, const SrcOp &Idx)
Build and insert Res = G_INSERT_VECTOR_ELT Val, Elt, Idx.
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, unsigned Flags=0, unsigned SubReg=0) const
Add a virtual register use operand.
const MachineInstrBuilder & addDef(Register RegNo, unsigned Flags=0, unsigned SubReg=0) const
Add a virtual register definition operand.
Representation of each machine instruction.
MachineRegisterInfo - Keep track of information for virtual and physical registers,...
Wrapper class representing virtual and physical registers.
Definition Register.h:20
void assignSPIRVTypeToVReg(SPIRVType *Type, Register VReg, const MachineFunction &MF)
const TargetRegisterClass * getRegClass(SPIRVType *SpvType) 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
This is a 'vector' (really, a variable-sized array), optimized for the case when the array is small.
The instances of the Type class are immutable: once they are created, they are never changed.
Definition Type.h:45
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.
@ C
The default llvm calling convention, compatible with C.
Definition CallingConv.h:34
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.
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.
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:279
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:207
const MachineInstr SPIRVType
const std::set< unsigned > & getTypeFoldingSupportedOpcodes()
decltype(auto) cast(const From &Val)
cast<X> - Return the argument parameter cast to the specified type.
Definition Casting.h:559
The LegalityQuery object bundles together all the information that's needed to decide whether a given...