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