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