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 const LLT p13 = LLT::pointer(13, PSize); // PushConstant
100
101 // TODO: remove copy-pasting here by using concatenation in some way.
102 auto allPtrsScalarsAndVectors = {
103 p0, p1, p2, p3, p4, p5, p6, p7, p8,
104 p9, p10, p11, p12, p13, s1, s8, s16, s32,
105 s64, v2s1, v2s8, v2s16, v2s32, v2s64, v3s1, v3s8, v3s16,
106 v3s32, v3s64, v4s1, v4s8, v4s16, v4s32, v4s64, v8s1, v8s8,
107 v8s16, v8s32, v8s64, v16s1, v16s8, v16s16, v16s32, v16s64};
108
109 auto allVectors = {v2s1, v2s8, v2s16, v2s32, v2s64, v3s1, v3s8,
110 v3s16, v3s32, v3s64, v4s1, v4s8, v4s16, v4s32,
111 v4s64, v8s1, v8s8, v8s16, v8s32, v8s64, v16s1,
112 v16s8, v16s16, v16s32, v16s64};
113
114 auto allShaderVectors = {v2s1, v2s8, v2s16, v2s32, v2s64,
115 v3s1, v3s8, v3s16, v3s32, v3s64,
116 v4s1, v4s8, v4s16, v4s32, v4s64};
117
118 auto allScalars = {s1, s8, s16, s32, s64};
119
120 auto allScalarsAndVectors = {
121 s1, s8, s16, s32, s64, s128, v2s1, v2s8,
122 v2s16, v2s32, v2s64, v3s1, v3s8, v3s16, v3s32, v3s64,
123 v4s1, v4s8, v4s16, v4s32, v4s64, v8s1, v8s8, v8s16,
124 v8s32, v8s64, v16s1, v16s8, v16s16, v16s32, v16s64};
125
126 auto allIntScalarsAndVectors = {
127 s8, s16, s32, s64, s128, v2s8, v2s16, v2s32, v2s64,
128 v3s8, v3s16, v3s32, v3s64, v4s8, v4s16, v4s32, v4s64, v8s8,
129 v8s16, v8s32, v8s64, v16s8, v16s16, v16s32, v16s64};
130
131 auto allBoolScalarsAndVectors = {s1, v2s1, v3s1, v4s1, v8s1, v16s1};
132
133 auto allIntScalars = {s8, s16, s32, s64, s128};
134
135 auto allFloatScalarsAndF16Vector2AndVector4s = {s16, s32, s64, v2s16, v4s16};
136
137 auto allFloatScalarsAndVectors = {
138 s16, s32, s64, v2s16, v2s32, v2s64, v3s16, v3s32, v3s64,
139 v4s16, v4s32, v4s64, v8s16, v8s32, v8s64, v16s16, v16s32, v16s64};
140
141 auto allFloatAndIntScalarsAndPtrs = {s8, s16, s32, s64, p0, p1,
142 p2, p3, p4, p5, p6, p7,
143 p8, p9, p10, p11, p12, p13};
144
145 auto allPtrs = {p0, p1, p2, p3, p4, p5, p6, p7, p8, p9, p10, p11, p12, p13};
146
147 auto &allowedVectorTypes = ST.isShader() ? allShaderVectors : allVectors;
148
149 bool IsExtendedInts =
150 ST.canUseExtension(
151 SPIRV::Extension::SPV_ALTERA_arbitrary_precision_integers) ||
152 ST.canUseExtension(SPIRV::Extension::SPV_KHR_bit_instructions) ||
153 ST.canUseExtension(SPIRV::Extension::SPV_INTEL_int4);
154 auto extendedScalarsAndVectors =
155 [IsExtendedInts](const LegalityQuery &Query) {
156 const LLT Ty = Query.Types[0];
157 return IsExtendedInts && Ty.isValid() && !Ty.isPointerOrPointerVector();
158 };
159 auto extendedScalarsAndVectorsProduct = [IsExtendedInts](
160 const LegalityQuery &Query) {
161 const LLT Ty1 = Query.Types[0], Ty2 = Query.Types[1];
162 return IsExtendedInts && Ty1.isValid() && Ty2.isValid() &&
163 !Ty1.isPointerOrPointerVector() && !Ty2.isPointerOrPointerVector();
164 };
165 auto extendedPtrsScalarsAndVectors =
166 [IsExtendedInts](const LegalityQuery &Query) {
167 const LLT Ty = Query.Types[0];
168 return IsExtendedInts && Ty.isValid();
169 };
170
171 // The universal validation rules in the SPIR-V specification state that
172 // vector sizes are typically limited to 2, 3, or 4. However, larger vector
173 // sizes (8 and 16) are enabled when the Kernel capability is present. For
174 // shader execution models, vector sizes are strictly limited to 4. In
175 // non-shader contexts, vector sizes of 8 and 16 are also permitted, but
176 // arbitrary sizes (e.g., 6 or 11) are not.
177 uint32_t MaxVectorSize = ST.isShader() ? 4 : 16;
178 LLVM_DEBUG(dbgs() << "MaxVectorSize: " << MaxVectorSize << "\n");
179
180 for (auto Opc : getTypeFoldingSupportedOpcodes()) {
181 switch (Opc) {
182 case G_EXTRACT_VECTOR_ELT:
183 case G_UREM:
184 case G_SREM:
185 case G_UDIV:
186 case G_SDIV:
187 case G_FREM:
188 break;
189 default:
191 .customFor(allScalars)
192 .customFor(allowedVectorTypes)
196 0, ElementCount::getFixed(MaxVectorSize)))
197 .custom();
198 break;
199 }
200 }
201
202 getActionDefinitionsBuilder({G_UREM, G_SREM, G_SDIV, G_UDIV, G_FREM})
203 .customFor(allScalars)
204 .customFor(allowedVectorTypes)
208 0, ElementCount::getFixed(MaxVectorSize)))
209 .custom();
210
211 getActionDefinitionsBuilder({G_FMA, G_STRICT_FMA})
212 .legalFor(allScalars)
213 .legalFor(allowedVectorTypes)
217 0, ElementCount::getFixed(MaxVectorSize)))
218 .alwaysLegal();
219
220 getActionDefinitionsBuilder(G_INTRINSIC_W_SIDE_EFFECTS).custom();
221
222 getActionDefinitionsBuilder(G_SHUFFLE_VECTOR)
223 .legalForCartesianProduct(allowedVectorTypes, allowedVectorTypes)
225 .lowerIf(vectorElementCountIsGreaterThan(0, MaxVectorSize))
227 .lowerIf(vectorElementCountIsGreaterThan(1, MaxVectorSize));
228
229 getActionDefinitionsBuilder(G_EXTRACT_VECTOR_ELT)
233 1, ElementCount::getFixed(MaxVectorSize)))
234 .custom();
235
236 getActionDefinitionsBuilder(G_INSERT_VECTOR_ELT)
240 0, ElementCount::getFixed(MaxVectorSize)))
241 .custom();
242
243 // Illegal G_UNMERGE_VALUES instructions should be handled
244 // during the combine phase.
245 getActionDefinitionsBuilder(G_BUILD_VECTOR)
249 0, ElementCount::getFixed(MaxVectorSize)));
250
251 // When entering the legalizer, there should be no G_BITCAST instructions.
252 // They should all be calls to the `spv_bitcast` intrinsic. The call to
253 // the intrinsic will be converted to a G_BITCAST during legalization if
254 // the vectors are not legal. After using the rules to legalize a G_BITCAST,
255 // we turn it back into a call to the intrinsic with a custom rule to avoid
256 // potential machine verifier failures.
262 0, ElementCount::getFixed(MaxVectorSize)))
263 .lowerIf(vectorElementCountIsGreaterThan(1, MaxVectorSize))
264 .custom();
265
266 // If the result is still illegal, the combiner should be able to remove it.
267 getActionDefinitionsBuilder(G_CONCAT_VECTORS)
268 .legalForCartesianProduct(allowedVectorTypes, allowedVectorTypes);
269
270 getActionDefinitionsBuilder(G_SPLAT_VECTOR)
271 .legalFor(allowedVectorTypes)
275 .alwaysLegal();
276
277 // Vector Reduction Operations
279 {G_VECREDUCE_SMIN, G_VECREDUCE_SMAX, G_VECREDUCE_UMIN, G_VECREDUCE_UMAX,
280 G_VECREDUCE_ADD, G_VECREDUCE_MUL, G_VECREDUCE_FMUL, G_VECREDUCE_FMIN,
281 G_VECREDUCE_FMAX, G_VECREDUCE_FMINIMUM, G_VECREDUCE_FMAXIMUM,
282 G_VECREDUCE_OR, G_VECREDUCE_AND, G_VECREDUCE_XOR})
283 .legalFor(allowedVectorTypes)
284 .scalarize(1)
285 .lower();
286
287 getActionDefinitionsBuilder({G_VECREDUCE_SEQ_FADD, G_VECREDUCE_SEQ_FMUL})
288 .scalarize(2)
289 .lower();
290
291 // Illegal G_UNMERGE_VALUES instructions should be handled
292 // during the combine phase.
293 getActionDefinitionsBuilder(G_UNMERGE_VALUES)
295
296 getActionDefinitionsBuilder({G_MEMCPY, G_MEMMOVE})
297 .unsupportedIf(LegalityPredicates::any(typeIs(0, p9), typeIs(1, p9)))
298 .legalIf(all(typeInSet(0, allPtrs), typeInSet(1, allPtrs)));
299
301 .unsupportedIf(typeIs(0, p9))
302 .legalIf(all(typeInSet(0, allPtrs), typeInSet(1, allIntScalars)));
303
304 getActionDefinitionsBuilder(G_ADDRSPACE_CAST)
307 all(typeIsNot(0, p9), typeIs(1, p9))))
308 .legalForCartesianProduct(allPtrs, allPtrs);
309
310 getActionDefinitionsBuilder({G_LOAD, G_STORE})
311 .unsupportedIf(typeIs(1, p9))
312 .legalIf(typeInSet(1, allPtrs));
313
314 getActionDefinitionsBuilder({G_SMIN, G_SMAX, G_UMIN, G_UMAX, G_ABS,
315 G_BITREVERSE, G_SADDSAT, G_UADDSAT, G_SSUBSAT,
316 G_USUBSAT, G_SCMP, G_UCMP})
317 .legalFor(allIntScalarsAndVectors)
318 .legalIf(extendedScalarsAndVectors);
319
320 getActionDefinitionsBuilder(G_STRICT_FLDEXP)
321 .legalForCartesianProduct(allFloatScalarsAndVectors, allIntScalars);
322
323 getActionDefinitionsBuilder({G_FPTOSI, G_FPTOUI})
324 .legalForCartesianProduct(allIntScalarsAndVectors,
325 allFloatScalarsAndVectors);
326
327 getActionDefinitionsBuilder({G_FPTOSI_SAT, G_FPTOUI_SAT})
328 .legalForCartesianProduct(allIntScalarsAndVectors,
329 allFloatScalarsAndVectors);
330
331 getActionDefinitionsBuilder({G_SITOFP, G_UITOFP})
332 .legalForCartesianProduct(allFloatScalarsAndVectors,
333 allScalarsAndVectors);
334
336 .legalForCartesianProduct(allIntScalarsAndVectors)
337 .legalIf(extendedScalarsAndVectorsProduct);
338
339 // Extensions.
340 getActionDefinitionsBuilder({G_TRUNC, G_ZEXT, G_SEXT, G_ANYEXT})
341 .legalForCartesianProduct(allScalarsAndVectors)
342 .legalIf(extendedScalarsAndVectorsProduct);
343
345 .legalFor(allPtrsScalarsAndVectors)
346 .legalIf(extendedPtrsScalarsAndVectors);
347
349 all(typeInSet(0, allPtrsScalarsAndVectors),
350 typeInSet(1, allPtrsScalarsAndVectors)));
351
352 getActionDefinitionsBuilder({G_IMPLICIT_DEF, G_FREEZE})
353 .legalFor({s1, s128})
354 .legalFor(allFloatAndIntScalarsAndPtrs)
355 .legalFor(allowedVectorTypes)
359 0, ElementCount::getFixed(MaxVectorSize)));
360
361 getActionDefinitionsBuilder({G_STACKSAVE, G_STACKRESTORE}).alwaysLegal();
362
364 .legalForCartesianProduct(allPtrs, allIntScalars)
365 .legalIf(
366 all(typeInSet(0, allPtrs), typeOfExtendedScalars(1, IsExtendedInts)));
368 .legalForCartesianProduct(allIntScalars, allPtrs)
369 .legalIf(
370 all(typeOfExtendedScalars(0, IsExtendedInts), typeInSet(1, allPtrs)));
372 .legalForCartesianProduct(allPtrs, allIntScalars)
373 .legalIf(
374 all(typeInSet(0, allPtrs), typeOfExtendedScalars(1, IsExtendedInts)));
375
376 // ST.canDirectlyComparePointers() for pointer args is supported in
377 // legalizeCustom().
380 all(typeIs(0, p9), typeInSet(1, allPtrs), typeIsNot(1, p9)),
381 all(typeInSet(0, allPtrs), typeIsNot(0, p9), typeIs(1, p9))))
382 .customIf(all(typeInSet(0, allBoolScalarsAndVectors),
383 typeInSet(1, allPtrsScalarsAndVectors)));
384
386 all(typeInSet(0, allBoolScalarsAndVectors),
387 typeInSet(1, allFloatScalarsAndVectors)));
388
389 getActionDefinitionsBuilder({G_ATOMICRMW_OR, G_ATOMICRMW_ADD, G_ATOMICRMW_AND,
390 G_ATOMICRMW_MAX, G_ATOMICRMW_MIN,
391 G_ATOMICRMW_SUB, G_ATOMICRMW_XOR,
392 G_ATOMICRMW_UMAX, G_ATOMICRMW_UMIN})
393 .legalForCartesianProduct(allIntScalars, allPtrs);
394
396 {G_ATOMICRMW_FADD, G_ATOMICRMW_FSUB, G_ATOMICRMW_FMIN, G_ATOMICRMW_FMAX})
397 .legalForCartesianProduct(allFloatScalarsAndF16Vector2AndVector4s,
398 allPtrs);
399
400 getActionDefinitionsBuilder(G_ATOMICRMW_XCHG)
401 .legalForCartesianProduct(allFloatAndIntScalarsAndPtrs, allPtrs);
402
403 getActionDefinitionsBuilder(G_ATOMIC_CMPXCHG_WITH_SUCCESS).lower();
404 // TODO: add proper legalization rules.
405 getActionDefinitionsBuilder(G_ATOMIC_CMPXCHG).alwaysLegal();
406
408 {G_UADDO, G_SADDO, G_USUBO, G_SSUBO, G_UMULO, G_SMULO})
409 .alwaysLegal();
410
411 getActionDefinitionsBuilder({G_LROUND, G_LLROUND})
412 .legalForCartesianProduct(allFloatScalarsAndVectors,
413 allIntScalarsAndVectors);
414
415 // FP conversions.
416 getActionDefinitionsBuilder({G_FPTRUNC, G_FPEXT})
417 .legalForCartesianProduct(allFloatScalarsAndVectors);
418
419 // Pointer-handling.
420 getActionDefinitionsBuilder(G_FRAME_INDEX).legalFor({p0});
421
422 getActionDefinitionsBuilder(G_GLOBAL_VALUE).legalFor(allPtrs);
423
424 // Control-flow. In some cases (e.g. constants) s1 may be promoted to s32.
425 getActionDefinitionsBuilder(G_BRCOND).legalFor({s1, s32});
426
428 allFloatScalarsAndVectors, {s32, v2s32, v3s32, v4s32, v8s32, v16s32});
429
430 // TODO: Review the target OpenCL and GLSL Extended Instruction Set specs to
431 // tighten these requirements. Many of these math functions are only legal on
432 // specific bitwidths, so they are not selectable for
433 // allFloatScalarsAndVectors.
434 getActionDefinitionsBuilder({G_STRICT_FSQRT,
435 G_FPOW,
436 G_FEXP,
437 G_FMODF,
438 G_FEXP2,
439 G_FLOG,
440 G_FLOG2,
441 G_FLOG10,
442 G_FABS,
443 G_FMINNUM,
444 G_FMAXNUM,
445 G_FCEIL,
446 G_FCOS,
447 G_FSIN,
448 G_FTAN,
449 G_FACOS,
450 G_FASIN,
451 G_FATAN,
452 G_FATAN2,
453 G_FCOSH,
454 G_FSINH,
455 G_FTANH,
456 G_FSQRT,
457 G_FFLOOR,
458 G_FRINT,
459 G_FNEARBYINT,
460 G_INTRINSIC_ROUND,
461 G_INTRINSIC_TRUNC,
462 G_FMINIMUM,
463 G_FMAXIMUM,
464 G_INTRINSIC_ROUNDEVEN})
465 .legalFor(allFloatScalarsAndVectors);
466
467 getActionDefinitionsBuilder(G_FCOPYSIGN)
468 .legalForCartesianProduct(allFloatScalarsAndVectors,
469 allFloatScalarsAndVectors);
470
472 allFloatScalarsAndVectors, allIntScalarsAndVectors);
473
474 if (ST.canUseExtInstSet(SPIRV::InstructionSet::OpenCL_std)) {
476 {G_CTTZ, G_CTTZ_ZERO_UNDEF, G_CTLZ, G_CTLZ_ZERO_UNDEF})
477 .legalForCartesianProduct(allIntScalarsAndVectors,
478 allIntScalarsAndVectors);
479
480 // Struct return types become a single scalar, so cannot easily legalize.
481 getActionDefinitionsBuilder({G_SMULH, G_UMULH}).alwaysLegal();
482 }
483
484 getActionDefinitionsBuilder(G_IS_FPCLASS).custom();
485
487 verify(*ST.getInstrInfo());
488}
489
492 MachineIRBuilder &MIRBuilder = Helper.MIRBuilder;
493 Register DstReg = MI.getOperand(0).getReg();
494 Register SrcReg = MI.getOperand(1).getReg();
495 Register IdxReg = MI.getOperand(2).getReg();
496
497 MIRBuilder
498 .buildIntrinsic(Intrinsic::spv_extractelt, ArrayRef<Register>{DstReg})
499 .addUse(SrcReg)
500 .addUse(IdxReg);
501 MI.eraseFromParent();
502 return true;
503}
504
507 MachineIRBuilder &MIRBuilder = Helper.MIRBuilder;
508 Register DstReg = MI.getOperand(0).getReg();
509 Register SrcReg = MI.getOperand(1).getReg();
510 Register ValReg = MI.getOperand(2).getReg();
511 Register IdxReg = MI.getOperand(3).getReg();
512
513 MIRBuilder
514 .buildIntrinsic(Intrinsic::spv_insertelt, ArrayRef<Register>{DstReg})
515 .addUse(SrcReg)
516 .addUse(ValReg)
517 .addUse(IdxReg);
518 MI.eraseFromParent();
519 return true;
520}
521
523 LegalizerHelper &Helper,
526 Register ConvReg = MRI.createGenericVirtualRegister(ConvTy);
527 MRI.setRegClass(ConvReg, GR->getRegClass(SpvType));
528 GR->assignSPIRVTypeToVReg(SpvType, ConvReg, Helper.MIRBuilder.getMF());
529 Helper.MIRBuilder.buildInstr(TargetOpcode::G_PTRTOINT)
530 .addDef(ConvReg)
531 .addUse(Reg);
532 return ConvReg;
533}
534
537 LostDebugLocObserver &LocObserver) const {
538 MachineRegisterInfo &MRI = MI.getMF()->getRegInfo();
539 switch (MI.getOpcode()) {
540 default:
541 // TODO: implement legalization for other opcodes.
542 return true;
543 case TargetOpcode::G_BITCAST:
544 return legalizeBitcast(Helper, MI);
545 case TargetOpcode::G_EXTRACT_VECTOR_ELT:
546 return legalizeExtractVectorElt(Helper, MI, GR);
547 case TargetOpcode::G_INSERT_VECTOR_ELT:
548 return legalizeInsertVectorElt(Helper, MI, GR);
549 case TargetOpcode::G_INTRINSIC:
550 case TargetOpcode::G_INTRINSIC_W_SIDE_EFFECTS:
551 return legalizeIntrinsic(Helper, MI);
552 case TargetOpcode::G_IS_FPCLASS:
553 return legalizeIsFPClass(Helper, MI, LocObserver);
554 case TargetOpcode::G_ICMP: {
555 assert(GR->getSPIRVTypeForVReg(MI.getOperand(0).getReg()));
556 auto &Op0 = MI.getOperand(2);
557 auto &Op1 = MI.getOperand(3);
558 Register Reg0 = Op0.getReg();
559 Register Reg1 = Op1.getReg();
561 static_cast<CmpInst::Predicate>(MI.getOperand(1).getPredicate());
562 if ((!ST->canDirectlyComparePointers() ||
564 MRI.getType(Reg0).isPointer() && MRI.getType(Reg1).isPointer()) {
565 LLT ConvT = LLT::scalar(ST->getPointerSize());
566 Type *LLVMTy = IntegerType::get(MI.getMF()->getFunction().getContext(),
567 ST->getPointerSize());
568 SPIRVType *SpirvTy = GR->getOrCreateSPIRVType(
569 LLVMTy, Helper.MIRBuilder, SPIRV::AccessQualifier::ReadWrite, true);
570 Op0.setReg(convertPtrToInt(Reg0, ConvT, SpirvTy, Helper, MRI, GR));
571 Op1.setReg(convertPtrToInt(Reg1, ConvT, SpirvTy, Helper, MRI, GR));
572 }
573 return true;
574 }
575 }
576}
577
578static bool needsVectorLegalization(const LLT &Ty, const SPIRVSubtarget &ST) {
579 if (!Ty.isVector())
580 return false;
581 unsigned NumElements = Ty.getNumElements();
582 unsigned MaxVectorSize = ST.isShader() ? 4 : 16;
583 return (NumElements > 4 && !isPowerOf2_32(NumElements)) ||
584 NumElements > MaxVectorSize;
585}
586
588 MachineInstr &MI) const {
589 LLVM_DEBUG(dbgs() << "legalizeIntrinsic: " << MI);
590
591 MachineIRBuilder &MIRBuilder = Helper.MIRBuilder;
592 MachineRegisterInfo &MRI = *MIRBuilder.getMRI();
593 const SPIRVSubtarget &ST = MI.getMF()->getSubtarget<SPIRVSubtarget>();
594
595 auto IntrinsicID = cast<GIntrinsic>(MI).getIntrinsicID();
596 if (IntrinsicID == Intrinsic::spv_bitcast) {
597 LLVM_DEBUG(dbgs() << "Found a bitcast instruction\n");
598 Register DstReg = MI.getOperand(0).getReg();
599 Register SrcReg = MI.getOperand(2).getReg();
600 LLT DstTy = MRI.getType(DstReg);
601 LLT SrcTy = MRI.getType(SrcReg);
602
603 // If an spv_bitcast needs to be legalized, we convert it to G_BITCAST to
604 // allow using the generic legalization rules.
605 if (needsVectorLegalization(DstTy, ST) ||
606 needsVectorLegalization(SrcTy, ST)) {
607 LLVM_DEBUG(dbgs() << "Replacing with a G_BITCAST\n");
608 MIRBuilder.buildBitcast(DstReg, SrcReg);
609 MI.eraseFromParent();
610 }
611 return true;
612 } else if (IntrinsicID == Intrinsic::spv_insertelt) {
613 Register DstReg = MI.getOperand(0).getReg();
614 LLT DstTy = MRI.getType(DstReg);
615
616 if (needsVectorLegalization(DstTy, ST)) {
617 Register SrcReg = MI.getOperand(2).getReg();
618 Register ValReg = MI.getOperand(3).getReg();
619 Register IdxReg = MI.getOperand(4).getReg();
620 MIRBuilder.buildInsertVectorElement(DstReg, SrcReg, ValReg, IdxReg);
621 MI.eraseFromParent();
622 }
623 return true;
624 } else if (IntrinsicID == Intrinsic::spv_extractelt) {
625 Register SrcReg = MI.getOperand(2).getReg();
626 LLT SrcTy = MRI.getType(SrcReg);
627
628 if (needsVectorLegalization(SrcTy, ST)) {
629 Register DstReg = MI.getOperand(0).getReg();
630 Register IdxReg = MI.getOperand(3).getReg();
631 MIRBuilder.buildExtractVectorElement(DstReg, SrcReg, IdxReg);
632 MI.eraseFromParent();
633 }
634 return true;
635 }
636 return true;
637}
638
639bool SPIRVLegalizerInfo::legalizeBitcast(LegalizerHelper &Helper,
640 MachineInstr &MI) const {
641 // Once the G_BITCAST is using vectors that are allowed, we turn it back into
642 // an spv_bitcast to avoid verifier problems when the register types are the
643 // same for the source and the result. Note that the SPIR-V types associated
644 // with the bitcast can be different even if the register types are the same.
645 MachineIRBuilder &MIRBuilder = Helper.MIRBuilder;
646 Register DstReg = MI.getOperand(0).getReg();
647 Register SrcReg = MI.getOperand(1).getReg();
648 SmallVector<Register, 1> DstRegs = {DstReg};
649 MIRBuilder.buildIntrinsic(Intrinsic::spv_bitcast, DstRegs).addUse(SrcReg);
650 MI.eraseFromParent();
651 return true;
652}
653
654// Note this code was copied from LegalizerHelper::lowerISFPCLASS and adjusted
655// to ensure that all instructions created during the lowering have SPIR-V types
656// assigned to them.
657bool SPIRVLegalizerInfo::legalizeIsFPClass(
659 LostDebugLocObserver &LocObserver) const {
660 auto [DstReg, DstTy, SrcReg, SrcTy] = MI.getFirst2RegLLTs();
661 FPClassTest Mask = static_cast<FPClassTest>(MI.getOperand(2).getImm());
662
663 auto &MIRBuilder = Helper.MIRBuilder;
664 auto &MF = MIRBuilder.getMF();
665 MachineRegisterInfo &MRI = MF.getRegInfo();
666
667 Type *LLVMDstTy =
668 IntegerType::get(MIRBuilder.getContext(), DstTy.getScalarSizeInBits());
669 if (DstTy.isVector())
670 LLVMDstTy = VectorType::get(LLVMDstTy, DstTy.getElementCount());
671 SPIRVType *SPIRVDstTy = GR->getOrCreateSPIRVType(
672 LLVMDstTy, MIRBuilder, SPIRV::AccessQualifier::ReadWrite,
673 /*EmitIR*/ true);
674
675 unsigned BitSize = SrcTy.getScalarSizeInBits();
676 const fltSemantics &Semantics = getFltSemanticForLLT(SrcTy.getScalarType());
677
678 LLT IntTy = LLT::scalar(BitSize);
679 Type *LLVMIntTy = IntegerType::get(MIRBuilder.getContext(), BitSize);
680 if (SrcTy.isVector()) {
681 IntTy = LLT::vector(SrcTy.getElementCount(), IntTy);
682 LLVMIntTy = VectorType::get(LLVMIntTy, SrcTy.getElementCount());
683 }
684 SPIRVType *SPIRVIntTy = GR->getOrCreateSPIRVType(
685 LLVMIntTy, MIRBuilder, SPIRV::AccessQualifier::ReadWrite,
686 /*EmitIR*/ true);
687
688 // Clang doesn't support capture of structured bindings:
689 LLT DstTyCopy = DstTy;
690 const auto assignSPIRVTy = [&](MachineInstrBuilder &&MI) {
691 // Assign this MI's (assumed only) destination to one of the two types we
692 // expect: either the G_IS_FPCLASS's destination type, or the integer type
693 // bitcast from the source type.
694 LLT MITy = MRI.getType(MI.getReg(0));
695 assert((MITy == IntTy || MITy == DstTyCopy) &&
696 "Unexpected LLT type while lowering G_IS_FPCLASS");
697 auto *SPVTy = MITy == IntTy ? SPIRVIntTy : SPIRVDstTy;
698 GR->assignSPIRVTypeToVReg(SPVTy, MI.getReg(0), MF);
699 return MI;
700 };
701
702 // Helper to build and assign a constant in one go
703 const auto buildSPIRVConstant = [&](LLT Ty, auto &&C) -> MachineInstrBuilder {
704 if (!Ty.isFixedVector())
705 return assignSPIRVTy(MIRBuilder.buildConstant(Ty, C));
706 auto ScalarC = MIRBuilder.buildConstant(Ty.getScalarType(), C);
707 assert((Ty == IntTy || Ty == DstTyCopy) &&
708 "Unexpected LLT type while lowering constant for G_IS_FPCLASS");
709 SPIRVType *VecEltTy = GR->getOrCreateSPIRVType(
710 (Ty == IntTy ? LLVMIntTy : LLVMDstTy)->getScalarType(), MIRBuilder,
711 SPIRV::AccessQualifier::ReadWrite,
712 /*EmitIR*/ true);
713 GR->assignSPIRVTypeToVReg(VecEltTy, ScalarC.getReg(0), MF);
714 return assignSPIRVTy(MIRBuilder.buildSplatBuildVector(Ty, ScalarC));
715 };
716
717 if (Mask == fcNone) {
718 MIRBuilder.buildCopy(DstReg, buildSPIRVConstant(DstTy, 0));
719 MI.eraseFromParent();
720 return true;
721 }
722 if (Mask == fcAllFlags) {
723 MIRBuilder.buildCopy(DstReg, buildSPIRVConstant(DstTy, 1));
724 MI.eraseFromParent();
725 return true;
726 }
727
728 // Note that rather than creating a COPY here (between a floating-point and
729 // integer type of the same size) we create a SPIR-V bitcast immediately. We
730 // can't create a G_BITCAST because the LLTs are the same, and we can't seem
731 // to correctly lower COPYs to SPIR-V bitcasts at this moment.
732 Register ResVReg = MRI.createGenericVirtualRegister(IntTy);
733 MRI.setRegClass(ResVReg, GR->getRegClass(SPIRVIntTy));
734 GR->assignSPIRVTypeToVReg(SPIRVIntTy, ResVReg, Helper.MIRBuilder.getMF());
735 auto AsInt = MIRBuilder.buildInstr(SPIRV::OpBitcast)
736 .addDef(ResVReg)
737 .addUse(GR->getSPIRVTypeID(SPIRVIntTy))
738 .addUse(SrcReg);
739 AsInt = assignSPIRVTy(std::move(AsInt));
740
741 // Various masks.
742 APInt SignBit = APInt::getSignMask(BitSize);
743 APInt ValueMask = APInt::getSignedMaxValue(BitSize); // All bits but sign.
744 APInt Inf = APFloat::getInf(Semantics).bitcastToAPInt(); // Exp and int bit.
745 APInt ExpMask = Inf;
746 APInt AllOneMantissa = APFloat::getLargest(Semantics).bitcastToAPInt() & ~Inf;
747 APInt QNaNBitMask =
748 APInt::getOneBitSet(BitSize, AllOneMantissa.getActiveBits() - 1);
749 APInt InversionMask = APInt::getAllOnes(DstTy.getScalarSizeInBits());
750
751 auto SignBitC = buildSPIRVConstant(IntTy, SignBit);
752 auto ValueMaskC = buildSPIRVConstant(IntTy, ValueMask);
753 auto InfC = buildSPIRVConstant(IntTy, Inf);
754 auto ExpMaskC = buildSPIRVConstant(IntTy, ExpMask);
755 auto ZeroC = buildSPIRVConstant(IntTy, 0);
756
757 auto Abs = assignSPIRVTy(MIRBuilder.buildAnd(IntTy, AsInt, ValueMaskC));
758 auto Sign = assignSPIRVTy(
759 MIRBuilder.buildICmp(CmpInst::Predicate::ICMP_NE, DstTy, AsInt, Abs));
760
761 auto Res = buildSPIRVConstant(DstTy, 0);
762
763 const auto appendToRes = [&](MachineInstrBuilder &&ToAppend) {
764 Res = assignSPIRVTy(
765 MIRBuilder.buildOr(DstTyCopy, Res, assignSPIRVTy(std::move(ToAppend))));
766 };
767
768 // Tests that involve more than one class should be processed first.
769 if ((Mask & fcFinite) == fcFinite) {
770 // finite(V) ==> abs(V) u< exp_mask
771 appendToRes(MIRBuilder.buildICmp(CmpInst::Predicate::ICMP_ULT, DstTy, Abs,
772 ExpMaskC));
773 Mask &= ~fcFinite;
774 } else if ((Mask & fcFinite) == fcPosFinite) {
775 // finite(V) && V > 0 ==> V u< exp_mask
776 appendToRes(MIRBuilder.buildICmp(CmpInst::Predicate::ICMP_ULT, DstTy, AsInt,
777 ExpMaskC));
778 Mask &= ~fcPosFinite;
779 } else if ((Mask & fcFinite) == fcNegFinite) {
780 // finite(V) && V < 0 ==> abs(V) u< exp_mask && signbit == 1
781 auto Cmp = assignSPIRVTy(MIRBuilder.buildICmp(CmpInst::Predicate::ICMP_ULT,
782 DstTy, Abs, ExpMaskC));
783 appendToRes(MIRBuilder.buildAnd(DstTy, Cmp, Sign));
784 Mask &= ~fcNegFinite;
785 }
786
787 if (FPClassTest PartialCheck = Mask & (fcZero | fcSubnormal)) {
788 // fcZero | fcSubnormal => test all exponent bits are 0
789 // TODO: Handle sign bit specific cases
790 // TODO: Handle inverted case
791 if (PartialCheck == (fcZero | fcSubnormal)) {
792 auto ExpBits = assignSPIRVTy(MIRBuilder.buildAnd(IntTy, AsInt, ExpMaskC));
793 appendToRes(MIRBuilder.buildICmp(CmpInst::Predicate::ICMP_EQ, DstTy,
794 ExpBits, ZeroC));
795 Mask &= ~PartialCheck;
796 }
797 }
798
799 // Check for individual classes.
800 if (FPClassTest PartialCheck = Mask & fcZero) {
801 if (PartialCheck == fcPosZero)
802 appendToRes(MIRBuilder.buildICmp(CmpInst::Predicate::ICMP_EQ, DstTy,
803 AsInt, ZeroC));
804 else if (PartialCheck == fcZero)
805 appendToRes(
806 MIRBuilder.buildICmp(CmpInst::Predicate::ICMP_EQ, DstTy, Abs, ZeroC));
807 else // fcNegZero
808 appendToRes(MIRBuilder.buildICmp(CmpInst::Predicate::ICMP_EQ, DstTy,
809 AsInt, SignBitC));
810 }
811
812 if (FPClassTest PartialCheck = Mask & fcSubnormal) {
813 // issubnormal(V) ==> unsigned(abs(V) - 1) u< (all mantissa bits set)
814 // issubnormal(V) && V>0 ==> unsigned(V - 1) u< (all mantissa bits set)
815 auto V = (PartialCheck == fcPosSubnormal) ? AsInt : Abs;
816 auto OneC = buildSPIRVConstant(IntTy, 1);
817 auto VMinusOne = MIRBuilder.buildSub(IntTy, V, OneC);
818 auto SubnormalRes = assignSPIRVTy(
819 MIRBuilder.buildICmp(CmpInst::Predicate::ICMP_ULT, DstTy, VMinusOne,
820 buildSPIRVConstant(IntTy, AllOneMantissa)));
821 if (PartialCheck == fcNegSubnormal)
822 SubnormalRes = MIRBuilder.buildAnd(DstTy, SubnormalRes, Sign);
823 appendToRes(std::move(SubnormalRes));
824 }
825
826 if (FPClassTest PartialCheck = Mask & fcInf) {
827 if (PartialCheck == fcPosInf)
828 appendToRes(MIRBuilder.buildICmp(CmpInst::Predicate::ICMP_EQ, DstTy,
829 AsInt, InfC));
830 else if (PartialCheck == fcInf)
831 appendToRes(
832 MIRBuilder.buildICmp(CmpInst::Predicate::ICMP_EQ, DstTy, Abs, InfC));
833 else { // fcNegInf
834 APInt NegInf = APFloat::getInf(Semantics, true).bitcastToAPInt();
835 auto NegInfC = buildSPIRVConstant(IntTy, NegInf);
836 appendToRes(MIRBuilder.buildICmp(CmpInst::Predicate::ICMP_EQ, DstTy,
837 AsInt, NegInfC));
838 }
839 }
840
841 if (FPClassTest PartialCheck = Mask & fcNan) {
842 auto InfWithQnanBitC =
843 buildSPIRVConstant(IntTy, std::move(Inf) | QNaNBitMask);
844 if (PartialCheck == fcNan) {
845 // isnan(V) ==> abs(V) u> int(inf)
846 appendToRes(
847 MIRBuilder.buildICmp(CmpInst::Predicate::ICMP_UGT, DstTy, Abs, InfC));
848 } else if (PartialCheck == fcQNan) {
849 // isquiet(V) ==> abs(V) u>= (unsigned(Inf) | quiet_bit)
850 appendToRes(MIRBuilder.buildICmp(CmpInst::Predicate::ICMP_UGE, DstTy, Abs,
851 InfWithQnanBitC));
852 } else { // fcSNan
853 // issignaling(V) ==> abs(V) u> unsigned(Inf) &&
854 // abs(V) u< (unsigned(Inf) | quiet_bit)
855 auto IsNan = assignSPIRVTy(
856 MIRBuilder.buildICmp(CmpInst::Predicate::ICMP_UGT, DstTy, Abs, InfC));
857 auto IsNotQnan = assignSPIRVTy(MIRBuilder.buildICmp(
858 CmpInst::Predicate::ICMP_ULT, DstTy, Abs, InfWithQnanBitC));
859 appendToRes(MIRBuilder.buildAnd(DstTy, IsNan, IsNotQnan));
860 }
861 }
862
863 if (FPClassTest PartialCheck = Mask & fcNormal) {
864 // isnormal(V) ==> (0 u< exp u< max_exp) ==> (unsigned(exp-1) u<
865 // (max_exp-1))
866 APInt ExpLSB = ExpMask & ~(ExpMask.shl(1));
867 auto ExpMinusOne = assignSPIRVTy(
868 MIRBuilder.buildSub(IntTy, Abs, buildSPIRVConstant(IntTy, ExpLSB)));
869 APInt MaxExpMinusOne = std::move(ExpMask) - ExpLSB;
870 auto NormalRes = assignSPIRVTy(
871 MIRBuilder.buildICmp(CmpInst::Predicate::ICMP_ULT, DstTy, ExpMinusOne,
872 buildSPIRVConstant(IntTy, MaxExpMinusOne)));
873 if (PartialCheck == fcNegNormal)
874 NormalRes = MIRBuilder.buildAnd(DstTy, NormalRes, Sign);
875 else if (PartialCheck == fcPosNormal) {
876 auto PosSign = assignSPIRVTy(MIRBuilder.buildXor(
877 DstTy, Sign, buildSPIRVConstant(DstTy, InversionMask)));
878 NormalRes = MIRBuilder.buildAnd(DstTy, NormalRes, PosSign);
879 }
880 appendToRes(std::move(NormalRes));
881 }
882
883 MIRBuilder.buildCopy(DstReg, Res);
884 MI.eraseFromParent();
885 return true;
886}
unsigned const MachineRegisterInfo * MRI
assert(UImm &&(UImm !=~static_cast< T >(0)) &&"Invalid immediate!")
static void scalarize(Instruction *I, SmallVectorImpl< Instruction * > &Worklist)
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...