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