LLVM 24.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"
17#include "SPIRVUtils.h"
24#include "llvm/IR/IntrinsicsSPIRV.h"
25#include "llvm/Support/Debug.h"
27
28using namespace llvm;
29using namespace llvm::LegalizeActions;
30using namespace llvm::LegalityPredicates;
31
32#define DEBUG_TYPE "spirv-legalizer"
33
34LegalityPredicate typeOfExtendedScalars(unsigned TypeIdx, bool IsExtendedInts) {
35 return [IsExtendedInts, TypeIdx](const LegalityQuery &Query) {
36 const LLT Ty = Query.Types[TypeIdx];
37 return IsExtendedInts && Ty.isValid() && Ty.isScalar();
38 };
39}
40
42 using namespace TargetOpcode;
43
44 this->ST = &ST;
45 GR = ST.getSPIRVGlobalRegistry();
46
47 const LLT s1 = LLT::scalar(1);
48 const LLT s8 = LLT::scalar(8);
49 const LLT s16 = LLT::scalar(16);
50 const LLT s32 = LLT::scalar(32);
51 const LLT s64 = LLT::scalar(64);
52 const LLT s128 = LLT::scalar(128);
53
54 const LLT v16s64 = LLT::fixed_vector(16, 64);
55 const LLT v16s32 = LLT::fixed_vector(16, 32);
56 const LLT v16s16 = LLT::fixed_vector(16, 16);
57 const LLT v16s8 = LLT::fixed_vector(16, 8);
58 const LLT v16s1 = LLT::fixed_vector(16, 1);
59
60 const LLT v8s64 = LLT::fixed_vector(8, 64);
61 const LLT v8s32 = LLT::fixed_vector(8, 32);
62 const LLT v8s16 = LLT::fixed_vector(8, 16);
63 const LLT v8s8 = LLT::fixed_vector(8, 8);
64 const LLT v8s1 = LLT::fixed_vector(8, 1);
65
66 const LLT v4s64 = LLT::fixed_vector(4, 64);
67 const LLT v4s32 = LLT::fixed_vector(4, 32);
68 const LLT v4s16 = LLT::fixed_vector(4, 16);
69 const LLT v4s8 = LLT::fixed_vector(4, 8);
70 const LLT v4s1 = LLT::fixed_vector(4, 1);
71
72 const LLT v3s64 = LLT::fixed_vector(3, 64);
73 const LLT v3s32 = LLT::fixed_vector(3, 32);
74 const LLT v3s16 = LLT::fixed_vector(3, 16);
75 const LLT v3s8 = LLT::fixed_vector(3, 8);
76 const LLT v3s1 = LLT::fixed_vector(3, 1);
77
78 const LLT v2s64 = LLT::fixed_vector(2, 64);
79 const LLT v2s32 = LLT::fixed_vector(2, 32);
80 const LLT v2s16 = LLT::fixed_vector(2, 16);
81 const LLT v2s8 = LLT::fixed_vector(2, 8);
82 const LLT v2s1 = LLT::fixed_vector(2, 1);
83
84 const unsigned PSize = ST.getPointerSize();
85 const LLT p0 = LLT::pointer(0, PSize); // Function
86 const LLT p1 = LLT::pointer(1, PSize); // CrossWorkgroup
87 const LLT p2 = LLT::pointer(2, PSize); // UniformConstant
88 const LLT p3 = LLT::pointer(3, PSize); // Workgroup
89 const LLT p4 = LLT::pointer(4, PSize); // Generic
90 const LLT p5 =
91 LLT::pointer(5, PSize); // Input, SPV_INTEL_usm_storage_classes (Device)
92 const LLT p6 = LLT::pointer(6, PSize); // SPV_INTEL_usm_storage_classes (Host)
93 const LLT p7 = LLT::pointer(7, PSize); // Input
94 const LLT p8 = LLT::pointer(8, PSize); // Output
95 const LLT p9 =
96 LLT::pointer(9, PSize); // CodeSectionINTEL, SPV_INTEL_function_pointers
97 const LLT p10 = LLT::pointer(10, PSize); // Private
98 const LLT p11 = LLT::pointer(11, PSize); // StorageBuffer
99 const LLT p12 = LLT::pointer(12, PSize); // Uniform
100 const LLT p13 = LLT::pointer(13, PSize); // PushConstant
101
102 // TODO: remove copy-pasting here by using concatenation in some way.
103 auto allPtrsScalarsAndVectors = {
104 p0, p1, p2, p3, p4, p5, p6, p7, p8,
105 p9, p10, p11, p12, p13, s1, s8, s16, s32,
106 s64, s128, v2s1, v2s8, v2s16, v2s32, v2s64, v3s1, v3s8,
107 v3s16, v3s32, v3s64, v4s1, v4s8, v4s16, v4s32, v4s64, v8s1,
108 v8s8, v8s16, v8s32, v8s64, v16s1, v16s8, v16s16, v16s32, v16s64};
109
110 auto allVectors = {v2s1, v2s8, v2s16, v2s32, v2s64, v3s1, v3s8,
111 v3s16, v3s32, v3s64, v4s1, v4s8, v4s16, v4s32,
112 v4s64, v8s1, v8s8, v8s16, v8s32, v8s64, v16s1,
113 v16s8, v16s16, v16s32, v16s64};
114
115 auto allShaderVectors = {v2s1, v2s8, v2s16, v2s32, v2s64,
116 v3s1, v3s8, v3s16, v3s32, v3s64,
117 v4s1, v4s8, v4s16, v4s32, v4s64};
118
119 auto allScalars = {s1, s8, s16, s32, s64};
120
121 auto allScalarsAndVectors = {
122 s1, s8, s16, s32, s64, s128, v2s1, v2s8,
123 v2s16, v2s32, v2s64, v3s1, v3s8, v3s16, v3s32, v3s64,
124 v4s1, v4s8, v4s16, v4s32, v4s64, v8s1, v8s8, v8s16,
125 v8s32, v8s64, v16s1, v16s8, v16s16, v16s32, v16s64};
126
127 auto allIntScalarsAndVectors = {
128 s8, s16, s32, s64, s128, v2s8, v2s16, v2s32, v2s64,
129 v3s8, v3s16, v3s32, v3s64, v4s8, v4s16, v4s32, v4s64, v8s8,
130 v8s16, v8s32, v8s64, v16s8, v16s16, v16s32, v16s64};
131
132 auto allBoolScalarsAndVectors = {s1, v2s1, v3s1, v4s1, v8s1, v16s1};
133 auto allBoolVectors = {v2s1, v3s1, v4s1, v8s1, v16s1};
134
135 auto allIntScalars = {s8, s16, s32, s64, s128};
136
137 auto allFloatScalarsAndF16Vector2AndVector4s = {s16, s32, s64, v2s16, v4s16};
138
139 auto allFloatScalars = {s16, s32, s64};
140
141 auto allFloatScalarsAndVectors = {
142 s16, s32, s64, v2s16, v2s32, v2s64, v3s16, v3s32, v3s64,
143 v4s16, v4s32, v4s64, v8s16, v8s32, v8s64, v16s16, v16s32, v16s64};
144
145 auto allShaderFloatVectors = {v2s16, v2s32, v2s64, v3s16, v3s32,
146 v3s64, v4s16, v4s32, v4s64};
147
148 auto allFloatVectors = {v2s16, v2s32, v2s64, v3s16, v3s32,
149 v3s64, v4s16, v4s32, v4s64, v8s16,
150 v8s32, v8s64, v16s16, v16s32, v16s64};
151
152 auto &allowedFloatVectorTypes =
153 ST.isShader() ? allShaderFloatVectors : allFloatVectors;
154
155 auto allFloatAndIntScalarsAndPtrs = {s8, s16, s32, s64, p0, p1,
156 p2, p3, p4, p5, p6, p7,
157 p8, p9, p10, p11, p12, p13};
158
159 auto allPtrs = {p0, p1, p2, p3, p4, p5, p6, p7, p8, p9, p10, p11, p12, p13};
160
161 auto &allowedVectorTypes = ST.isShader() ? allShaderVectors : allVectors;
162
163 bool HasArbitraryPrecisionInts = ST.canUseExtension(
164 SPIRV::Extension::SPV_ALTERA_arbitrary_precision_integers);
165 bool IsExtendedInts =
166 HasArbitraryPrecisionInts ||
167 ST.canUseExtension(SPIRV::Extension::SPV_KHR_bit_instructions) ||
168 ST.canUseExtension(SPIRV::Extension::SPV_INTEL_int4);
169 auto ExtendedIntScalarsAndVectors =
170 [IsExtendedInts](const LegalityQuery &Query) {
171 const LLT Ty = Query.Types[0];
172 return IsExtendedInts && Ty.isValid() &&
173 !Ty.isPointerOrPointerVector() && Ty.getScalarSizeInBits() > 1;
174 };
175 auto ExtendedScalarsAndVectorsProduct = [IsExtendedInts](
176 const LegalityQuery &Query) {
177 const LLT Ty1 = Query.Types[0], Ty2 = Query.Types[1];
178 return IsExtendedInts && Ty1.isValid() && Ty2.isValid() &&
179 !Ty1.isPointerOrPointerVector() && !Ty2.isPointerOrPointerVector();
180 };
181 auto ExtendedPtrsScalarsAndVectors =
182 [IsExtendedInts](const LegalityQuery &Query) {
183 const LLT Ty = Query.Types[0];
184 return IsExtendedInts && Ty.isValid();
185 };
186
187 // The universal validation rules in the SPIR-V specification state that
188 // vector sizes are typically limited to 2, 3, or 4. However, larger vector
189 // sizes (8 and 16) are enabled when the Kernel capability is present. For
190 // shader execution models, vector sizes are strictly limited to 4. In
191 // non-shader contexts, vector sizes of 8 and 16 are also permitted, but
192 // arbitrary sizes (e.g., 6 or 11) are not.
193 uint32_t MaxVectorSize = ST.isShader() ? 4 : 16;
194 LLVM_DEBUG(dbgs() << "MaxVectorSize: " << MaxVectorSize << "\n");
195
196 for (auto Opc : getTypeFoldingSupportedOpcodes()) {
197 switch (Opc) {
198 case G_EXTRACT_VECTOR_ELT:
199 case G_UREM:
200 case G_SREM:
201 case G_UDIV:
202 case G_SDIV:
203 case G_FREM:
204 break;
205 default:
207 .customFor(allScalars)
208 .customFor(allowedVectorTypes)
212 0, ElementCount::getFixed(MaxVectorSize)))
213 .custom();
214 break;
215 }
216 }
217
218 getActionDefinitionsBuilder({G_UREM, G_SREM, G_SDIV, G_UDIV, G_FREM})
219 .customFor(allScalars)
220 .customFor(allowedVectorTypes)
224 0, ElementCount::getFixed(MaxVectorSize)))
225 .custom();
226
227 getActionDefinitionsBuilder({G_FMA, G_STRICT_FMA})
228 .legalFor(allScalars)
229 .legalFor(allowedVectorTypes)
233 0, ElementCount::getFixed(MaxVectorSize)))
234 .alwaysLegal();
235
236 getActionDefinitionsBuilder(G_INTRINSIC_W_SIDE_EFFECTS).custom();
237
238 getActionDefinitionsBuilder(G_SHUFFLE_VECTOR)
239 .legalForCartesianProduct(allowedVectorTypes, allowedVectorTypes)
241 .lowerIf(vectorElementCountIsGreaterThan(0, MaxVectorSize))
243 .lowerIf(vectorElementCountIsGreaterThan(1, MaxVectorSize));
244
245 getActionDefinitionsBuilder(G_EXTRACT_VECTOR_ELT)
249 1, ElementCount::getFixed(MaxVectorSize)))
250 .custom();
251
252 getActionDefinitionsBuilder(G_INSERT_VECTOR_ELT)
256 0, ElementCount::getFixed(MaxVectorSize)))
257 .custom();
258
259 // Illegal G_UNMERGE_VALUES instructions should be handled
260 // during the combine phase.
261 getActionDefinitionsBuilder(G_BUILD_VECTOR)
265 0, ElementCount::getFixed(MaxVectorSize)));
266
267 // When entering the legalizer, there should be no G_BITCAST instructions.
268 // They should all be calls to the `spv_bitcast` intrinsic. The call to
269 // the intrinsic will be converted to a G_BITCAST during legalization if
270 // the vectors are not legal. After using the rules to legalize a G_BITCAST,
271 // we turn it back into a call to the intrinsic with a custom rule to avoid
272 // potential machine verifier failures.
278 0, ElementCount::getFixed(MaxVectorSize)))
279 .lowerIf(vectorElementCountIsGreaterThan(1, MaxVectorSize))
280 .custom();
281
282 // If the result is still illegal, the combiner should be able to remove it.
283 getActionDefinitionsBuilder(G_CONCAT_VECTORS)
284 .legalForCartesianProduct(allowedVectorTypes, allowedVectorTypes);
285
286 getActionDefinitionsBuilder(G_SPLAT_VECTOR)
287 .legalFor(allowedVectorTypes)
291 .alwaysLegal();
292
293 // Vector Reduction Operations
295 {G_VECREDUCE_SMIN, G_VECREDUCE_SMAX, G_VECREDUCE_UMIN, G_VECREDUCE_UMAX,
296 G_VECREDUCE_ADD, G_VECREDUCE_MUL, G_VECREDUCE_FMUL, G_VECREDUCE_FMIN,
297 G_VECREDUCE_FMAX, G_VECREDUCE_FMINIMUM, G_VECREDUCE_FMAXIMUM,
298 G_VECREDUCE_OR, G_VECREDUCE_AND, G_VECREDUCE_XOR})
299 .legalFor(allowedVectorTypes)
300 .scalarize(1)
301 .lower();
302
303 getActionDefinitionsBuilder({G_VECREDUCE_SEQ_FADD, G_VECREDUCE_SEQ_FMUL})
304 .scalarize(2)
305 .lower();
306
307 // Illegal G_UNMERGE_VALUES instructions should be handled
308 // during the combine phase.
309 getActionDefinitionsBuilder(G_UNMERGE_VALUES)
311
312 getActionDefinitionsBuilder({G_MEMCPY, G_MEMCPY_INLINE, G_MEMMOVE})
313 .unsupportedIf(LegalityPredicates::any(typeIs(0, p9), typeIs(1, p9)))
314 .legalIf(all(typeInSet(0, allPtrs), typeInSet(1, allPtrs)));
315
316 getActionDefinitionsBuilder({G_MEMSET, G_MEMSET_INLINE})
317 .unsupportedIf(typeIs(0, p9))
318 .legalIf(all(typeInSet(0, allPtrs), typeInSet(1, allIntScalars)));
319
320 getActionDefinitionsBuilder(G_ADDRSPACE_CAST)
321 .legalForCartesianProduct(allPtrs, allPtrs);
322
323 // Should we be legalizing bad scalar sizes like s5 here instead
324 // of handling them in the instruction selector?
325 getActionDefinitionsBuilder({G_LOAD, G_STORE})
326 .unsupportedIf(typeIs(1, p9))
327 .legalForCartesianProduct(allowedVectorTypes, allPtrs)
328 .legalForCartesianProduct(allPtrs, allPtrs)
329 .legalIf(isScalar(0))
330 .custom();
331
332 getActionDefinitionsBuilder({G_SMIN, G_SMAX, G_UMIN, G_UMAX, G_ABS,
333 G_BITREVERSE, G_SADDSAT, G_UADDSAT, G_SSUBSAT,
334 G_USUBSAT, G_SCMP, G_UCMP})
335 .legalFor(allIntScalarsAndVectors)
336 .legalIf(ExtendedIntScalarsAndVectors)
337 // LLVM i1 maps to OpTypeBool, not OpTypeInt.
338 .scalarizeIf(typeInSet(0, allBoolVectors), 0)
339 .minScalar(0, s32);
340
341 getActionDefinitionsBuilder({G_SSHLSAT, G_USHLSAT}).lower();
342
343 getActionDefinitionsBuilder({G_FLDEXP, G_STRICT_FLDEXP})
344 .legalForCartesianProduct(allFloatScalarsAndVectors, allIntScalars);
345
346 getActionDefinitionsBuilder({G_FPTOSI, G_FPTOUI})
347 .legalForCartesianProduct(allIntScalarsAndVectors,
348 allFloatScalarsAndVectors);
349
350 getActionDefinitionsBuilder({G_FPTOSI_SAT, G_FPTOUI_SAT})
351 .legalForCartesianProduct(allIntScalarsAndVectors,
352 allFloatScalarsAndVectors);
353
354 getActionDefinitionsBuilder({G_SITOFP, G_UITOFP})
355 .legalForCartesianProduct(allFloatScalarsAndVectors,
356 allScalarsAndVectors);
357
359 .legalForCartesianProduct(allIntScalarsAndVectors)
360 .legalIf(ExtendedScalarsAndVectorsProduct);
361
362 getActionDefinitionsBuilder({G_TRUNC, G_ZEXT, G_SEXT, G_ANYEXT})
363 .legalForCartesianProduct(allScalarsAndVectors)
364 .legalIf(ExtendedScalarsAndVectorsProduct)
368 0, ElementCount::getFixed(MaxVectorSize)));
369
370 getActionDefinitionsBuilder(G_SEXT_INREG)
374 0, ElementCount::getFixed(MaxVectorSize)))
375 .lower();
376
380 0, ElementCount::getFixed(MaxVectorSize)))
381 .legalFor(allPtrsScalarsAndVectors)
382 .legalIf(ExtendedPtrsScalarsAndVectors)
384
386 all(typeInSet(0, allPtrsScalarsAndVectors),
387 typeInSet(1, allPtrsScalarsAndVectors)));
388
389 getActionDefinitionsBuilder({G_IMPLICIT_DEF, G_FREEZE})
390 .legalFor({s1, s128})
391 .legalFor(allFloatAndIntScalarsAndPtrs)
392 .legalFor(allowedVectorTypes)
393 .legalIf([](const LegalityQuery &Query) {
394 return Query.Types[0].isPointerVector();
395 })
396 .moreElementsToNextPow2(0)
397 .fewerElementsIf(vectorElementCountIsGreaterThan(0, MaxVectorSize),
399 0, ElementCount::getFixed(MaxVectorSize)));
400
401 getActionDefinitionsBuilder({G_STACKSAVE, G_STACKRESTORE}).alwaysLegal();
402
404 .legalForCartesianProduct(allPtrs, allIntScalars)
405 .legalIf(
406 all(typeInSet(0, allPtrs), typeOfExtendedScalars(1, IsExtendedInts)))
407 .legalIf([](const LegalityQuery &Query) {
408 const LLT DstTy = Query.Types[0];
409 const LLT SrcTy = Query.Types[1];
410 return DstTy.isPointerVector() && SrcTy.isVector() &&
411 !SrcTy.isPointer() &&
412 DstTy.getNumElements() == SrcTy.getNumElements();
413 });
415 .legalForCartesianProduct(allIntScalars, allPtrs)
416 .legalIf(
417 all(typeOfExtendedScalars(0, IsExtendedInts), typeInSet(1, allPtrs)))
418 .legalIf([](const LegalityQuery &Query) {
419 const LLT DstTy = Query.Types[0];
420 const LLT SrcTy = Query.Types[1];
421 return SrcTy.isPointerVector() && DstTy.isVector() &&
422 !DstTy.isPointer() &&
423 DstTy.getNumElements() == SrcTy.getNumElements();
424 });
426 .legalForCartesianProduct(allPtrs, allIntScalars)
427 .legalIf(
428 all(typeInSet(0, allPtrs), typeOfExtendedScalars(1, IsExtendedInts)));
429
431 .legalForCartesianProduct(allPtrs, allIntScalars)
432 .legalIf(
433 all(typeInSet(0, allPtrs), typeOfExtendedScalars(1, IsExtendedInts)))
434 .legalIf([](const LegalityQuery &Query) {
435 const LLT PtrTy = Query.Types[0];
436 const LLT MaskTy = Query.Types[1];
437 return PtrTy.isPointerVector() && MaskTy.isVector() &&
438 !MaskTy.isPointer() &&
439 PtrTy.getNumElements() == MaskTy.getNumElements();
440 });
441
442 // ST.canDirectlyComparePointers() for pointer args is supported in
443 // legalizeCustom().
446 all(typeIs(0, p9), typeInSet(1, allPtrs), typeIsNot(1, p9)),
447 all(typeInSet(0, allPtrs), typeIsNot(0, p9), typeIs(1, p9))))
448 .legalIf([IsExtendedInts](const LegalityQuery &Query) {
449 const LLT Ty = Query.Types[1];
450 return IsExtendedInts && Ty.isValid() && !Ty.isPointerOrPointerVector();
451 })
452 .customIf(all(typeInSet(0, allBoolScalarsAndVectors),
453 typeInSet(1, allPtrsScalarsAndVectors)));
454
456 all(typeInSet(0, allBoolScalarsAndVectors),
457 typeInSet(1, allFloatScalarsAndVectors)));
458
459 getActionDefinitionsBuilder({G_ATOMICRMW_OR, G_ATOMICRMW_ADD, G_ATOMICRMW_AND,
460 G_ATOMICRMW_MAX, G_ATOMICRMW_MIN,
461 G_ATOMICRMW_SUB, G_ATOMICRMW_XOR,
462 G_ATOMICRMW_UMAX, G_ATOMICRMW_UMIN})
463 .legalForCartesianProduct(allIntScalars, allPtrs);
464
466 {G_ATOMICRMW_FADD, G_ATOMICRMW_FSUB, G_ATOMICRMW_FMIN, G_ATOMICRMW_FMAX})
467 .legalForCartesianProduct(allFloatScalarsAndF16Vector2AndVector4s,
468 allPtrs);
469
470 getActionDefinitionsBuilder(G_ATOMICRMW_XCHG)
471 .legalForCartesianProduct(allFloatAndIntScalarsAndPtrs, allPtrs);
472
473 getActionDefinitionsBuilder(G_ATOMIC_CMPXCHG_WITH_SUCCESS).lower();
474 // TODO: add proper legalization rules.
475 getActionDefinitionsBuilder(G_ATOMIC_CMPXCHG).alwaysLegal();
476
477 getActionDefinitionsBuilder({G_UADDO, G_USUBO, G_UMULO, G_SMULO})
478 .alwaysLegal();
479
480 getActionDefinitionsBuilder({G_SADDO, G_SSUBO}).lower();
481
482 // Lowering widens s64 to s128, which needs
483 // SPV_ALTERA_arbitrary_precision_integers. Mark s64 unsupported otherwise.
484 auto &MulFix = getActionDefinitionsBuilder({G_SMULFIX, G_UMULFIX});
485 if (!HasArbitraryPrecisionInts)
486 MulFix.unsupportedFor({s64});
487 MulFix.lower();
488
489 getActionDefinitionsBuilder({G_LROUND, G_LLROUND})
490 .legalForCartesianProduct(allFloatScalarsAndVectors,
491 allIntScalarsAndVectors);
492
493 // FP conversions.
494 getActionDefinitionsBuilder({G_FPTRUNC, G_FPEXT})
495 .legalForCartesianProduct(allFloatScalarsAndVectors);
496
497 // Pointer-handling.
498 getActionDefinitionsBuilder(G_FRAME_INDEX).legalFor({p0});
499
500 getActionDefinitionsBuilder(G_GLOBAL_VALUE).legalFor(allPtrs);
501
502 // Control-flow. In some cases (e.g. constants) s1 may be promoted to s32.
504 getActionDefinitionsBuilder(G_BRCOND).legalFor({s1, s32});
505
507 allFloatScalarsAndVectors, {s32, v2s32, v3s32, v4s32, v8s32, v16s32});
508
509 // TODO: Review the target OpenCL and GLSL Extended Instruction Set specs to
510 // tighten these requirements. Many of these math functions are only legal on
511 // specific bitwidths, so they are not selectable for
512 // allFloatScalarsAndVectors.
513 // clang-format off
514 getActionDefinitionsBuilder({G_STRICT_FSQRT,
515 G_FPOW,
516 G_FEXP,
517 G_FMODF,
518 G_FSINCOS,
519 G_FEXP2,
520 G_FEXP10,
521 G_FLOG,
522 G_FLOG2,
523 G_FLOG10,
524 G_FABS,
525 G_FMINNUM,
526 G_FMAXNUM,
527 G_FCEIL,
528 G_FCOS,
529 G_FSIN,
530 G_FTAN,
531 G_FACOS,
532 G_FASIN,
533 G_FATAN,
534 G_FATAN2,
535 G_FCOSH,
536 G_FSINH,
537 G_FTANH,
538 G_FSQRT,
539 G_FFLOOR,
540 G_FRINT,
541 G_FNEARBYINT,
542 G_INTRINSIC_ROUND,
543 G_INTRINSIC_TRUNC,
544 G_FMINIMUM,
545 G_FMAXIMUM,
546 G_INTRINSIC_ROUNDEVEN})
547 .legalFor(allFloatScalars)
548 .legalFor(allowedFloatVectorTypes)
551 0, ElementCount::getFixed(MaxVectorSize)))
553 // clang-format on
554
555 getActionDefinitionsBuilder(G_FCOPYSIGN)
556 .legalForCartesianProduct(allFloatScalarsAndVectors,
557 allFloatScalarsAndVectors);
558
560 allFloatScalarsAndVectors, allIntScalarsAndVectors);
561
562 if (ST.canUseExtInstSet(SPIRV::InstructionSet::OpenCL_std)) {
564 {G_CTTZ, G_CTTZ_ZERO_POISON, G_CTLZ, G_CTLZ_ZERO_POISON})
565 .legalForCartesianProduct(allIntScalarsAndVectors,
566 allIntScalarsAndVectors);
567
568 // Struct return types become a single scalar, so cannot easily legalize.
569 getActionDefinitionsBuilder({G_SMULH, G_UMULH}).alwaysLegal();
570 }
571
572 getActionDefinitionsBuilder(G_IS_FPCLASS).custom();
573
574 getActionDefinitionsBuilder({G_INTRINSIC, G_INTRINSIC_CONVERGENT,
575 G_INTRINSIC_CONVERGENT_W_SIDE_EFFECTS})
576 .alwaysLegal();
578 getActionDefinitionsBuilder({G_TRAP, G_DEBUGTRAP, G_UBSANTRAP}).alwaysLegal();
579
580 verify(*ST.getInstrInfo());
581}
582
584 MachineInstr &MI) {
585 MachineIRBuilder &MIRBuilder = Helper.MIRBuilder;
586 Register DstReg = MI.getOperand(0).getReg();
587 Register SrcReg = MI.getOperand(1).getReg();
588 Register IdxReg = MI.getOperand(2).getReg();
589
590 MIRBuilder
591 .buildIntrinsic(Intrinsic::spv_extractelt, ArrayRef<Register>{DstReg})
592 .addUse(SrcReg)
593 .addUse(IdxReg);
594 MI.eraseFromParent();
595 return true;
596}
597
599 MachineIRBuilder &MIRBuilder = Helper.MIRBuilder;
600 Register DstReg = MI.getOperand(0).getReg();
601 Register SrcReg = MI.getOperand(1).getReg();
602 Register ValReg = MI.getOperand(2).getReg();
603 Register IdxReg = MI.getOperand(3).getReg();
604
605 MIRBuilder
606 .buildIntrinsic(Intrinsic::spv_insertelt, ArrayRef<Register>{DstReg})
607 .addUse(SrcReg)
608 .addUse(ValReg)
609 .addUse(IdxReg);
610 MI.eraseFromParent();
611 return true;
612}
613
615 LegalizerHelper &Helper,
618 Register ConvReg = MRI.createGenericVirtualRegister(ConvTy);
619 MRI.setRegClass(ConvReg, GR->getRegClass(SpvType));
620 GR->assignSPIRVTypeToVReg(SpvType, ConvReg, Helper.MIRBuilder.getMF());
621 Helper.MIRBuilder.buildInstr(TargetOpcode::G_PTRTOINT)
622 .addDef(ConvReg)
623 .addUse(Reg);
624 return ConvReg;
625}
626
627static bool needsVectorLegalization(const LLT &Ty, const SPIRVSubtarget &ST) {
628 if (!Ty.isVector())
629 return false;
630 unsigned NumElements = Ty.getNumElements();
631 unsigned MaxVectorSize = ST.isShader() ? 4 : 16;
632 return (NumElements > 4 && !isPowerOf2_32(NumElements)) ||
633 NumElements > MaxVectorSize;
634}
635
638 MachineRegisterInfo &MRI = MI.getMF()->getRegInfo();
639 MachineIRBuilder &MIRBuilder = Helper.MIRBuilder;
640 Register DstReg = MI.getOperand(0).getReg();
641 Register PtrReg = MI.getOperand(1).getReg();
642 LLT DstTy = MRI.getType(DstReg);
643
644 if (!DstTy.isVector())
645 return true;
646
647 const SPIRVSubtarget &ST = MI.getMF()->getSubtarget<SPIRVSubtarget>();
648 if (!needsVectorLegalization(DstTy, ST))
649 return true;
650
651 SmallVector<Register, 8> SplitRegs;
652 LLT EltTy = DstTy.getElementType();
653 unsigned NumElts = DstTy.getNumElements();
654
655 LLT PtrTy = MRI.getType(PtrReg);
656 auto Zero = MIRBuilder.buildConstant(LLT::scalar(32), 0);
657
658 for (unsigned i = 0; i < NumElts; ++i) {
659 auto Idx = MIRBuilder.buildConstant(LLT::scalar(32), i);
660 Register EltPtr = MRI.createGenericVirtualRegister(PtrTy);
661
662 MIRBuilder.buildIntrinsic(Intrinsic::spv_gep, ArrayRef<Register>{EltPtr})
663 .addImm(1) // InBounds
664 .addUse(PtrReg)
665 .addUse(Zero.getReg(0))
666 .addUse(Idx.getReg(0));
667
668 MachinePointerInfo EltPtrInfo;
669 Align EltAlign = Align(1);
670 if (!MI.memoperands_empty()) {
671 MachineMemOperand *MMO = *MI.memoperands_begin();
672 EltPtrInfo =
673 MMO->getPointerInfo().getWithOffset(i * EltTy.getSizeInBytes());
674 EltAlign = commonAlignment(MMO->getAlign(), i * EltTy.getSizeInBytes());
675 }
676
677 Register EltReg = MRI.createGenericVirtualRegister(EltTy);
678 MIRBuilder.buildLoad(EltReg, EltPtr, EltPtrInfo, EltAlign);
679 SplitRegs.push_back(EltReg);
680 }
681
682 MIRBuilder.buildBuildVector(DstReg, SplitRegs);
683 MI.eraseFromParent();
684 return true;
685}
686
689 MachineRegisterInfo &MRI = MI.getMF()->getRegInfo();
690 MachineIRBuilder &MIRBuilder = Helper.MIRBuilder;
691 Register ValReg = MI.getOperand(0).getReg();
692 Register PtrReg = MI.getOperand(1).getReg();
693 LLT ValTy = MRI.getType(ValReg);
694
695 assert(ValTy.isVector() && "Expected vector store");
696
697 SmallVector<Register, 8> SplitRegs;
698 LLT EltTy = ValTy.getElementType();
699 unsigned NumElts = ValTy.getNumElements();
700
701 for (unsigned i = 0; i < NumElts; ++i)
702 SplitRegs.push_back(MRI.createGenericVirtualRegister(EltTy));
703
704 MIRBuilder.buildUnmerge(SplitRegs, ValReg);
705
706 LLT PtrTy = MRI.getType(PtrReg);
707 auto Zero = MIRBuilder.buildConstant(LLT::scalar(32), 0);
708
709 for (unsigned i = 0; i < NumElts; ++i) {
710 auto Idx = MIRBuilder.buildConstant(LLT::scalar(32), i);
711 Register EltPtr = MRI.createGenericVirtualRegister(PtrTy);
712
713 MIRBuilder.buildIntrinsic(Intrinsic::spv_gep, ArrayRef<Register>{EltPtr})
714 .addImm(1) // InBounds
715 .addUse(PtrReg)
716 .addUse(Zero.getReg(0))
717 .addUse(Idx.getReg(0));
718
719 MachinePointerInfo EltPtrInfo;
720 Align EltAlign = Align(1);
721 if (!MI.memoperands_empty()) {
722 MachineMemOperand *MMO = *MI.memoperands_begin();
723 EltPtrInfo =
724 MMO->getPointerInfo().getWithOffset(i * EltTy.getSizeInBytes());
725 EltAlign = commonAlignment(MMO->getAlign(), i * EltTy.getSizeInBytes());
726 }
727
728 MIRBuilder.buildStore(SplitRegs[i], EltPtr, EltPtrInfo, EltAlign);
729 }
730
731 MI.eraseFromParent();
732 return true;
733}
734
737 LostDebugLocObserver &LocObserver) const {
738 MachineRegisterInfo &MRI = MI.getMF()->getRegInfo();
739 switch (MI.getOpcode()) {
740 default:
741 // TODO: implement legalization for other opcodes.
742 return true;
743 case TargetOpcode::G_BITCAST:
744 return legalizeBitcast(Helper, MI);
745 case TargetOpcode::G_EXTRACT_VECTOR_ELT:
746 return legalizeExtractVectorElt(Helper, MI);
747 case TargetOpcode::G_INSERT_VECTOR_ELT:
748 return legalizeInsertVectorElt(Helper, MI);
749 case TargetOpcode::G_INTRINSIC:
750 case TargetOpcode::G_INTRINSIC_W_SIDE_EFFECTS:
751 return legalizeIntrinsic(Helper, MI);
752 case TargetOpcode::G_IS_FPCLASS:
753 return legalizeIsFPClass(Helper, MI, LocObserver);
754 case TargetOpcode::G_ICMP: {
755 auto &Op0 = MI.getOperand(2);
756 auto &Op1 = MI.getOperand(3);
757 Register Reg0 = Op0.getReg();
758 Register Reg1 = Op1.getReg();
760 static_cast<CmpInst::Predicate>(MI.getOperand(1).getPredicate());
761 if ((!ST->canDirectlyComparePointers() ||
763 MRI.getType(Reg0).isPointer() && MRI.getType(Reg1).isPointer()) {
764 LLT ConvT = LLT::scalar(ST->getPointerSize());
765 Type *LLVMTy = IntegerType::get(MI.getMF()->getFunction().getContext(),
766 ST->getPointerSize());
767 SPIRVTypeInst SpirvTy = GR->getOrCreateSPIRVType(
768 LLVMTy, Helper.MIRBuilder, SPIRV::AccessQualifier::ReadWrite, true);
769 Op0.setReg(convertPtrToInt(Reg0, ConvT, SpirvTy, Helper, MRI, GR));
770 Op1.setReg(convertPtrToInt(Reg1, ConvT, SpirvTy, Helper, MRI, GR));
771 }
772 return true;
773 }
774 case TargetOpcode::G_LOAD:
775 return legalizeLoad(Helper, MI, GR);
776 case TargetOpcode::G_STORE:
777 return legalizeStore(Helper, MI, GR);
778 }
779}
780
783 Register SrcReg, LLT SrcTy,
784 MachinePointerInfo &PtrInfo, Align &VecAlign) {
785 MachineIRBuilder &MIRBuilder = Helper.MIRBuilder;
786 MachineRegisterInfo &MRI = *MIRBuilder.getMRI();
787
788 VecAlign = Helper.getStackTemporaryAlignment(SrcTy);
789 auto StackTemp = Helper.createStackTemporary(
790 TypeSize::getFixed(SrcTy.getSizeInBytes()), VecAlign, PtrInfo);
791
792 // Set the type of StackTemp to a pointer to an array of the element type.
793 SPIRVTypeInst SpvSrcTy = GR->getSPIRVTypeForVReg(SrcReg);
794 SPIRVTypeInst EltSpvTy = GR->getScalarOrVectorComponentType(SpvSrcTy);
795 const Type *LLVMEltTy = GR->getTypeForSPIRVType(EltSpvTy);
796 const Type *LLVMArrTy =
797 ArrayType::get(const_cast<Type *>(LLVMEltTy), SrcTy.getNumElements());
798 SPIRVTypeInst ArrSpvTy = GR->getOrCreateSPIRVType(
799 LLVMArrTy, MIRBuilder, SPIRV::AccessQualifier::ReadWrite, true);
800 SPIRVTypeInst PtrToArrSpvTy = GR->getOrCreateSPIRVPointerType(
801 ArrSpvTy, MIRBuilder, SPIRV::StorageClass::Function);
802
803 Register StackReg = StackTemp.getReg(0);
804 MRI.setRegClass(StackReg, GR->getRegClass(PtrToArrSpvTy));
805 GR->assignSPIRVTypeToVReg(PtrToArrSpvTy, StackReg, MIRBuilder.getMF());
806
807 return StackTemp;
808}
809
812 LLVM_DEBUG(dbgs() << "Found a bitcast instruction\n");
813 MachineIRBuilder &MIRBuilder = Helper.MIRBuilder;
814 MachineRegisterInfo &MRI = *MIRBuilder.getMRI();
815 const SPIRVSubtarget &ST = MI.getMF()->getSubtarget<SPIRVSubtarget>();
816
817 Register DstReg = MI.getOperand(0).getReg();
818 Register SrcReg = MI.getOperand(2).getReg();
819 LLT DstTy = MRI.getType(DstReg);
820 LLT SrcTy = MRI.getType(SrcReg);
821
822 // If an spv_bitcast needs to be legalized, we convert it to G_BITCAST to
823 // allow using the generic legalization rules.
824 if (needsVectorLegalization(DstTy, ST) ||
825 needsVectorLegalization(SrcTy, ST)) {
826 LLVM_DEBUG(dbgs() << "Replacing with a G_BITCAST\n");
827 MIRBuilder.buildBitcast(DstReg, SrcReg);
828 MI.eraseFromParent();
829 }
830 return true;
831}
832
835 MachineIRBuilder &MIRBuilder = Helper.MIRBuilder;
836 MachineRegisterInfo &MRI = *MIRBuilder.getMRI();
837 const SPIRVSubtarget &ST = MI.getMF()->getSubtarget<SPIRVSubtarget>();
838
839 Register DstReg = MI.getOperand(0).getReg();
840 LLT DstTy = MRI.getType(DstReg);
841
842 if (needsVectorLegalization(DstTy, ST)) {
843 Register SrcReg = MI.getOperand(2).getReg();
844 Register ValReg = MI.getOperand(3).getReg();
845 LLT SrcTy = MRI.getType(SrcReg);
846 MachineOperand &IdxOperand = MI.getOperand(4);
847
848 if (getImm(IdxOperand, &MRI)) {
849 uint64_t IdxVal = foldImm(IdxOperand, &MRI);
850 if (IdxVal < SrcTy.getNumElements()) {
852 SPIRVTypeInst ElementType =
854 LLT ElementLLTTy = GR->getRegType(ElementType);
855 for (unsigned I = 0, E = SrcTy.getNumElements(); I < E; ++I) {
856 Register Reg = MRI.createGenericVirtualRegister(ElementLLTTy);
857 MRI.setRegClass(Reg, GR->getRegClass(ElementType));
858 GR->assignSPIRVTypeToVReg(ElementType, Reg, *MI.getMF());
859 Regs.push_back(Reg);
860 }
861 MIRBuilder.buildUnmerge(Regs, SrcReg);
862 Regs[IdxVal] = ValReg;
863 MIRBuilder.buildBuildVector(DstReg, Regs);
864 MI.eraseFromParent();
865 return true;
866 }
867 }
868
869 LLT EltTy = SrcTy.getElementType();
870 Align VecAlign;
871 MachinePointerInfo PtrInfo;
872 auto StackTemp = createStackTemporaryForVector(Helper, GR, SrcReg, SrcTy,
873 PtrInfo, VecAlign);
874
875 MIRBuilder.buildStore(SrcReg, StackTemp, PtrInfo, VecAlign);
876
877 Register IdxReg = IdxOperand.getReg();
878 LLT PtrTy = MRI.getType(StackTemp.getReg(0));
879 Register EltPtr = MRI.createGenericVirtualRegister(PtrTy);
880 auto Zero = MIRBuilder.buildConstant(LLT::scalar(32), 0);
881
882 MIRBuilder.buildIntrinsic(Intrinsic::spv_gep, ArrayRef<Register>{EltPtr})
883 .addImm(1) // InBounds
884 .addUse(StackTemp.getReg(0))
885 .addUse(Zero.getReg(0))
886 .addUse(IdxReg);
887
889 Align EltAlign = Helper.getStackTemporaryAlignment(EltTy);
890 MIRBuilder.buildStore(ValReg, EltPtr, EltPtrInfo, EltAlign);
891
892 MIRBuilder.buildLoad(DstReg, StackTemp, PtrInfo, VecAlign);
893 MI.eraseFromParent();
894 return true;
895 }
896 return true;
897}
898
901 MachineIRBuilder &MIRBuilder = Helper.MIRBuilder;
902 MachineRegisterInfo &MRI = *MIRBuilder.getMRI();
903 const SPIRVSubtarget &ST = MI.getMF()->getSubtarget<SPIRVSubtarget>();
904
905 Register SrcReg = MI.getOperand(2).getReg();
906 LLT SrcTy = MRI.getType(SrcReg);
907
908 if (needsVectorLegalization(SrcTy, ST)) {
909 Register DstReg = MI.getOperand(0).getReg();
910 MachineOperand &IdxOperand = MI.getOperand(3);
911
912 if (getImm(IdxOperand, &MRI)) {
913 uint64_t IdxVal = foldImm(IdxOperand, &MRI);
914 if (IdxVal < SrcTy.getNumElements()) {
915 LLT DstTy = MRI.getType(DstReg);
917 SPIRVTypeInst DstSpvTy = GR->getSPIRVTypeForVReg(DstReg);
918 for (unsigned I = 0, E = SrcTy.getNumElements(); I < E; ++I) {
919 if (I == IdxVal) {
920 Regs.push_back(DstReg);
921 } else {
923 MRI.setRegClass(Reg, GR->getRegClass(DstSpvTy));
924 GR->assignSPIRVTypeToVReg(DstSpvTy, Reg, *MI.getMF());
925 Regs.push_back(Reg);
926 }
927 }
928 MIRBuilder.buildUnmerge(Regs, SrcReg);
929 MI.eraseFromParent();
930 return true;
931 }
932 }
933
934 LLT EltTy = SrcTy.getElementType();
935 Align VecAlign;
936 MachinePointerInfo PtrInfo;
937 auto StackTemp = createStackTemporaryForVector(Helper, GR, SrcReg, SrcTy,
938 PtrInfo, VecAlign);
939
940 MIRBuilder.buildStore(SrcReg, StackTemp, PtrInfo, VecAlign);
941
942 Register IdxReg = IdxOperand.getReg();
943 LLT PtrTy = MRI.getType(StackTemp.getReg(0));
944 Register EltPtr = MRI.createGenericVirtualRegister(PtrTy);
945 auto Zero = MIRBuilder.buildConstant(LLT::scalar(32), 0);
946
947 MIRBuilder.buildIntrinsic(Intrinsic::spv_gep, ArrayRef<Register>{EltPtr})
948 .addImm(1) // InBounds
949 .addUse(StackTemp.getReg(0))
950 .addUse(Zero.getReg(0))
951 .addUse(IdxReg);
952
954 Align EltAlign = Helper.getStackTemporaryAlignment(EltTy);
955 MIRBuilder.buildLoad(DstReg, EltPtr, EltPtrInfo, EltAlign);
956
957 MI.eraseFromParent();
958 return true;
959 }
960 return true;
961}
962
965 MachineIRBuilder &MIRBuilder = Helper.MIRBuilder;
966 MachineRegisterInfo &MRI = *MIRBuilder.getMRI();
967 const SPIRVSubtarget &ST = MI.getMF()->getSubtarget<SPIRVSubtarget>();
968
969 Register DstReg = MI.getOperand(0).getReg();
970 LLT DstTy = MRI.getType(DstReg);
971
972 if (!needsVectorLegalization(DstTy, ST))
973 return true;
974
976 if (MI.getNumOperands() == 2) {
977 // The "null" case: no values are attached.
978 LLT EltTy = DstTy.getElementType();
979 auto Zero = MIRBuilder.buildConstant(EltTy, 0);
980 SPIRVTypeInst SpvDstTy = GR->getSPIRVTypeForVReg(DstReg);
981 SPIRVTypeInst SpvEltTy = GR->getScalarOrVectorComponentType(SpvDstTy);
982 GR->assignSPIRVTypeToVReg(SpvEltTy, Zero.getReg(0), MIRBuilder.getMF());
983 for (unsigned i = 0; i < DstTy.getNumElements(); ++i)
984 SrcRegs.push_back(Zero.getReg(0));
985 } else {
986 for (unsigned i = 2; i < MI.getNumOperands(); ++i) {
987 SrcRegs.push_back(MI.getOperand(i).getReg());
988 }
989 }
990 MIRBuilder.buildBuildVector(DstReg, SrcRegs);
991 MI.eraseFromParent();
992 return true;
993}
994
996 MachineInstr &MI) const {
997 LLVM_DEBUG(dbgs() << "legalizeIntrinsic: " << MI);
998 auto IntrinsicID = cast<GIntrinsic>(MI).getIntrinsicID();
999 switch (IntrinsicID) {
1000 case Intrinsic::spv_bitcast:
1001 return legalizeSpvBitcast(Helper, MI, GR);
1002 case Intrinsic::spv_insertelt:
1003 return legalizeSpvInsertElt(Helper, MI, GR);
1004 case Intrinsic::spv_extractelt:
1005 return legalizeSpvExtractElt(Helper, MI, GR);
1006 case Intrinsic::spv_const_composite:
1007 return legalizeSpvConstComposite(Helper, MI, GR);
1008 }
1009 return true;
1010}
1011
1012bool SPIRVLegalizerInfo::legalizeBitcast(LegalizerHelper &Helper,
1013 MachineInstr &MI) const {
1014 // Once the G_BITCAST is using vectors that are allowed, we turn it back into
1015 // an spv_bitcast to avoid verifier problems when the register types are the
1016 // same for the source and the result. Note that the SPIR-V types associated
1017 // with the bitcast can be different even if the register types are the same.
1018 MachineIRBuilder &MIRBuilder = Helper.MIRBuilder;
1019 Register DstReg = MI.getOperand(0).getReg();
1020 Register SrcReg = MI.getOperand(1).getReg();
1021 SmallVector<Register, 1> DstRegs = {DstReg};
1022 MIRBuilder.buildIntrinsic(Intrinsic::spv_bitcast, DstRegs).addUse(SrcReg);
1023 MI.eraseFromParent();
1024 return true;
1025}
1026
1027// Note this code was copied from LegalizerHelper::lowerISFPCLASS and adjusted
1028// to ensure that all instructions created during the lowering have SPIR-V types
1029// assigned to them.
1030bool SPIRVLegalizerInfo::legalizeIsFPClass(
1032 LostDebugLocObserver &LocObserver) const {
1033 auto [DstReg, DstTy, SrcReg, SrcTy] = MI.getFirst2RegLLTs();
1034 FPClassTest Mask = static_cast<FPClassTest>(MI.getOperand(2).getImm());
1035
1036 auto &MIRBuilder = Helper.MIRBuilder;
1037 auto &MF = MIRBuilder.getMF();
1038 MachineRegisterInfo &MRI = MF.getRegInfo();
1039
1040 Type *LLVMDstTy =
1041 IntegerType::get(MIRBuilder.getContext(), DstTy.getScalarSizeInBits());
1042 if (DstTy.isVector())
1043 LLVMDstTy = VectorType::get(LLVMDstTy, DstTy.getElementCount());
1044 SPIRVTypeInst SPIRVDstTy = GR->getOrCreateSPIRVType(
1045 LLVMDstTy, MIRBuilder, SPIRV::AccessQualifier::ReadWrite,
1046 /*EmitIR*/ true);
1047
1048 unsigned BitSize = SrcTy.getScalarSizeInBits();
1049 const fltSemantics &Semantics = getFltSemanticForLLT(SrcTy.getScalarType());
1050
1051 LLT IntTy = LLT::scalar(BitSize);
1052 Type *LLVMIntTy = IntegerType::get(MIRBuilder.getContext(), BitSize);
1053 if (SrcTy.isVector()) {
1054 IntTy = LLT::vector(SrcTy.getElementCount(), IntTy);
1055 LLVMIntTy = VectorType::get(LLVMIntTy, SrcTy.getElementCount());
1056 }
1057 SPIRVTypeInst SPIRVIntTy = GR->getOrCreateSPIRVType(
1058 LLVMIntTy, MIRBuilder, SPIRV::AccessQualifier::ReadWrite,
1059 /*EmitIR*/ true);
1060
1061 // Clang doesn't support capture of structured bindings:
1062 LLT DstTyCopy = DstTy;
1063 const auto assignSPIRVTy = [&](MachineInstrBuilder &&MI) {
1064 // Assign this MI's (assumed only) destination to one of the two types we
1065 // expect: either the G_IS_FPCLASS's destination type, or the integer type
1066 // bitcast from the source type.
1067 LLT MITy = MRI.getType(MI.getReg(0));
1068 assert((MITy == IntTy || MITy == DstTyCopy) &&
1069 "Unexpected LLT type while lowering G_IS_FPCLASS");
1070 SPIRVTypeInst SPVTy = MITy == IntTy ? SPIRVIntTy : SPIRVDstTy;
1071 GR->assignSPIRVTypeToVReg(SPVTy, MI.getReg(0), MF);
1072 return MI;
1073 };
1074
1075 // Helper to build and assign a constant in one go
1076 const auto buildSPIRVConstant = [&](LLT Ty, auto &&C) -> MachineInstrBuilder {
1077 if (!Ty.isFixedVector())
1078 return assignSPIRVTy(MIRBuilder.buildConstant(Ty, C));
1079 auto ScalarC = MIRBuilder.buildConstant(Ty.getScalarType(), C);
1080 assert((Ty == IntTy || Ty == DstTyCopy) &&
1081 "Unexpected LLT type while lowering constant for G_IS_FPCLASS");
1082 SPIRVTypeInst VecEltTy = GR->getOrCreateSPIRVType(
1083 (Ty == IntTy ? LLVMIntTy : LLVMDstTy)->getScalarType(), MIRBuilder,
1084 SPIRV::AccessQualifier::ReadWrite,
1085 /*EmitIR*/ true);
1086 GR->assignSPIRVTypeToVReg(VecEltTy, ScalarC.getReg(0), MF);
1087 return assignSPIRVTy(MIRBuilder.buildSplatBuildVector(Ty, ScalarC));
1088 };
1089
1090 if (Mask == fcNone) {
1091 MIRBuilder.buildCopy(DstReg, buildSPIRVConstant(DstTy, 0));
1092 MI.eraseFromParent();
1093 return true;
1094 }
1095 if (Mask == fcAllFlags) {
1096 MIRBuilder.buildCopy(DstReg, buildSPIRVConstant(DstTy, 1));
1097 MI.eraseFromParent();
1098 return true;
1099 }
1100
1101 // Note that rather than creating a COPY here (between a floating-point and
1102 // integer type of the same size) we create a SPIR-V bitcast immediately. We
1103 // can't create a G_BITCAST because the LLTs are the same, and we can't seem
1104 // to correctly lower COPYs to SPIR-V bitcasts at this moment.
1105 Register ResVReg = MRI.createGenericVirtualRegister(IntTy);
1106 MRI.setRegClass(ResVReg, GR->getRegClass(SPIRVIntTy));
1107 GR->assignSPIRVTypeToVReg(SPIRVIntTy, ResVReg, Helper.MIRBuilder.getMF());
1108 auto AsInt = MIRBuilder.buildInstr(SPIRV::OpBitcast)
1109 .addDef(ResVReg)
1110 .addUse(GR->getSPIRVTypeID(SPIRVIntTy))
1111 .addUse(SrcReg);
1112 AsInt = assignSPIRVTy(std::move(AsInt));
1113
1114 // Various masks.
1115 APInt SignBit = APInt::getSignMask(BitSize);
1116 APInt ValueMask = APInt::getSignedMaxValue(BitSize); // All bits but sign.
1117 APInt Inf = APFloat::getInf(Semantics).bitcastToAPInt(); // Exp and int bit.
1118 APInt ExpMask = Inf;
1119 APInt AllOneMantissa = APFloat::getLargest(Semantics).bitcastToAPInt() & ~Inf;
1120 APInt QNaNBitMask =
1121 APInt::getOneBitSet(BitSize, AllOneMantissa.getActiveBits() - 1);
1122 APInt InversionMask = APInt::getAllOnes(DstTy.getScalarSizeInBits());
1123
1124 auto SignBitC = buildSPIRVConstant(IntTy, SignBit);
1125 auto ValueMaskC = buildSPIRVConstant(IntTy, ValueMask);
1126 auto InfC = buildSPIRVConstant(IntTy, Inf);
1127 auto ExpMaskC = buildSPIRVConstant(IntTy, ExpMask);
1128 auto ZeroC = buildSPIRVConstant(IntTy, 0);
1129
1130 auto Abs = assignSPIRVTy(MIRBuilder.buildAnd(IntTy, AsInt, ValueMaskC));
1131 auto Sign = assignSPIRVTy(
1132 MIRBuilder.buildICmp(CmpInst::Predicate::ICMP_NE, DstTy, AsInt, Abs));
1133
1134 auto Res = buildSPIRVConstant(DstTy, 0);
1135
1136 const auto appendToRes = [&](MachineInstrBuilder &&ToAppend) {
1137 Res = assignSPIRVTy(
1138 MIRBuilder.buildOr(DstTyCopy, Res, assignSPIRVTy(std::move(ToAppend))));
1139 };
1140
1141 // Tests that involve more than one class should be processed first.
1142 if ((Mask & fcFinite) == fcFinite) {
1143 // finite(V) ==> abs(V) u< exp_mask
1144 appendToRes(MIRBuilder.buildICmp(CmpInst::Predicate::ICMP_ULT, DstTy, Abs,
1145 ExpMaskC));
1146 Mask &= ~fcFinite;
1147 } else if ((Mask & fcFinite) == fcPosFinite) {
1148 // finite(V) && V > 0 ==> V u< exp_mask
1149 appendToRes(MIRBuilder.buildICmp(CmpInst::Predicate::ICMP_ULT, DstTy, AsInt,
1150 ExpMaskC));
1151 Mask &= ~fcPosFinite;
1152 } else if ((Mask & fcFinite) == fcNegFinite) {
1153 // finite(V) && V < 0 ==> abs(V) u< exp_mask && signbit == 1
1154 auto Cmp = assignSPIRVTy(MIRBuilder.buildICmp(CmpInst::Predicate::ICMP_ULT,
1155 DstTy, Abs, ExpMaskC));
1156 appendToRes(MIRBuilder.buildAnd(DstTy, Cmp, Sign));
1157 Mask &= ~fcNegFinite;
1158 }
1159
1160 if (FPClassTest PartialCheck = Mask & (fcZero | fcSubnormal)) {
1161 // fcZero | fcSubnormal => test all exponent bits are 0
1162 // TODO: Handle sign bit specific cases
1163 // TODO: Handle inverted case
1164 if (PartialCheck == (fcZero | fcSubnormal)) {
1165 auto ExpBits = assignSPIRVTy(MIRBuilder.buildAnd(IntTy, AsInt, ExpMaskC));
1166 appendToRes(MIRBuilder.buildICmp(CmpInst::Predicate::ICMP_EQ, DstTy,
1167 ExpBits, ZeroC));
1168 Mask &= ~PartialCheck;
1169 }
1170 }
1171
1172 // Check for individual classes.
1173 if (FPClassTest PartialCheck = Mask & fcZero) {
1174 if (PartialCheck == fcPosZero)
1175 appendToRes(MIRBuilder.buildICmp(CmpInst::Predicate::ICMP_EQ, DstTy,
1176 AsInt, ZeroC));
1177 else if (PartialCheck == fcZero)
1178 appendToRes(
1179 MIRBuilder.buildICmp(CmpInst::Predicate::ICMP_EQ, DstTy, Abs, ZeroC));
1180 else // fcNegZero
1181 appendToRes(MIRBuilder.buildICmp(CmpInst::Predicate::ICMP_EQ, DstTy,
1182 AsInt, SignBitC));
1183 }
1184
1185 if (FPClassTest PartialCheck = Mask & fcSubnormal) {
1186 // issubnormal(V) ==> unsigned(abs(V) - 1) u< (all mantissa bits set)
1187 // issubnormal(V) && V>0 ==> unsigned(V - 1) u< (all mantissa bits set)
1188 auto V = (PartialCheck == fcPosSubnormal) ? AsInt : Abs;
1189 auto OneC = buildSPIRVConstant(IntTy, 1);
1190 auto VMinusOne = MIRBuilder.buildSub(IntTy, V, OneC);
1191 auto SubnormalRes = assignSPIRVTy(
1192 MIRBuilder.buildICmp(CmpInst::Predicate::ICMP_ULT, DstTy, VMinusOne,
1193 buildSPIRVConstant(IntTy, AllOneMantissa)));
1194 if (PartialCheck == fcNegSubnormal)
1195 SubnormalRes = MIRBuilder.buildAnd(DstTy, SubnormalRes, Sign);
1196 appendToRes(std::move(SubnormalRes));
1197 }
1198
1199 if (FPClassTest PartialCheck = Mask & fcInf) {
1200 if (PartialCheck == fcPosInf)
1201 appendToRes(MIRBuilder.buildICmp(CmpInst::Predicate::ICMP_EQ, DstTy,
1202 AsInt, InfC));
1203 else if (PartialCheck == fcInf)
1204 appendToRes(
1205 MIRBuilder.buildICmp(CmpInst::Predicate::ICMP_EQ, DstTy, Abs, InfC));
1206 else { // fcNegInf
1207 APInt NegInf = APFloat::getInf(Semantics, true).bitcastToAPInt();
1208 auto NegInfC = buildSPIRVConstant(IntTy, NegInf);
1209 appendToRes(MIRBuilder.buildICmp(CmpInst::Predicate::ICMP_EQ, DstTy,
1210 AsInt, NegInfC));
1211 }
1212 }
1213
1214 if (FPClassTest PartialCheck = Mask & fcNan) {
1215 auto InfWithQnanBitC =
1216 buildSPIRVConstant(IntTy, std::move(Inf) | QNaNBitMask);
1217 if (PartialCheck == fcNan) {
1218 // isnan(V) ==> abs(V) u> int(inf)
1219 appendToRes(
1220 MIRBuilder.buildICmp(CmpInst::Predicate::ICMP_UGT, DstTy, Abs, InfC));
1221 } else if (PartialCheck == fcQNan) {
1222 // isquiet(V) ==> abs(V) u>= (unsigned(Inf) | quiet_bit)
1223 appendToRes(MIRBuilder.buildICmp(CmpInst::Predicate::ICMP_UGE, DstTy, Abs,
1224 InfWithQnanBitC));
1225 } else { // fcSNan
1226 // issignaling(V) ==> abs(V) u> unsigned(Inf) &&
1227 // abs(V) u< (unsigned(Inf) | quiet_bit)
1228 auto IsNan = assignSPIRVTy(
1229 MIRBuilder.buildICmp(CmpInst::Predicate::ICMP_UGT, DstTy, Abs, InfC));
1230 auto IsNotQnan = assignSPIRVTy(MIRBuilder.buildICmp(
1231 CmpInst::Predicate::ICMP_ULT, DstTy, Abs, InfWithQnanBitC));
1232 appendToRes(MIRBuilder.buildAnd(DstTy, IsNan, IsNotQnan));
1233 }
1234 }
1235
1236 if (FPClassTest PartialCheck = Mask & fcNormal) {
1237 // isnormal(V) ==> (0 u< exp u< max_exp) ==> (unsigned(exp-1) u<
1238 // (max_exp-1))
1239 APInt ExpLSB = ExpMask & ~(ExpMask.shl(1));
1240 auto ExpMinusOne = assignSPIRVTy(
1241 MIRBuilder.buildSub(IntTy, Abs, buildSPIRVConstant(IntTy, ExpLSB)));
1242 APInt MaxExpMinusOne = std::move(ExpMask) - ExpLSB;
1243 auto NormalRes = assignSPIRVTy(
1244 MIRBuilder.buildICmp(CmpInst::Predicate::ICMP_ULT, DstTy, ExpMinusOne,
1245 buildSPIRVConstant(IntTy, MaxExpMinusOne)));
1246 if (PartialCheck == fcNegNormal)
1247 NormalRes = MIRBuilder.buildAnd(DstTy, NormalRes, Sign);
1248 else if (PartialCheck == fcPosNormal) {
1249 auto PosSign = assignSPIRVTy(MIRBuilder.buildXor(
1250 DstTy, Sign, buildSPIRVConstant(DstTy, InversionMask)));
1251 NormalRes = MIRBuilder.buildAnd(DstTy, NormalRes, PosSign);
1252 }
1253 appendToRes(std::move(NormalRes));
1254 }
1255
1256 MIRBuilder.buildCopy(DstReg, Res);
1257 MI.eraseFromParent();
1258 return true;
1259}
assert(UImm &&(UImm !=~static_cast< T >(0)) &&"Invalid immediate!")
static GCRegistry::Add< ShadowStackGC > C("shadow-stack", "Very portable GC for uncooperative code generators")
static GCRegistry::Add< CoreCLRGC > E("coreclr", "CoreCLR-compatible GC")
static void scalarize(Instruction *I, SmallVectorImpl< Instruction * > &Worklist)
Declares convenience wrapper classes for interpreting MachineInstr instances as specific generic oper...
IRTranslator LLVM IR MI
#define I(x, y, z)
Definition MD5.cpp:57
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 legalizeSpvInsertElt(LegalizerHelper &Helper, MachineInstr &MI, SPIRVGlobalRegistry *GR)
static bool needsVectorLegalization(const LLT &Ty, const SPIRVSubtarget &ST)
static bool legalizeInsertVectorElt(LegalizerHelper &Helper, MachineInstr &MI)
static MachineInstrBuilder createStackTemporaryForVector(LegalizerHelper &Helper, SPIRVGlobalRegistry *GR, Register SrcReg, LLT SrcTy, MachinePointerInfo &PtrInfo, Align &VecAlign)
static Register convertPtrToInt(Register Reg, LLT ConvTy, SPIRVTypeInst SpvType, LegalizerHelper &Helper, MachineRegisterInfo &MRI, SPIRVGlobalRegistry *GR)
LegalityPredicate typeOfExtendedScalars(unsigned TypeIdx, bool IsExtendedInts)
static bool legalizeStore(LegalizerHelper &Helper, MachineInstr &MI, SPIRVGlobalRegistry *GR)
static bool legalizeExtractVectorElt(LegalizerHelper &Helper, MachineInstr &MI)
static bool legalizeSpvExtractElt(LegalizerHelper &Helper, MachineInstr &MI, SPIRVGlobalRegistry *GR)
static bool legalizeSpvBitcast(LegalizerHelper &Helper, MachineInstr &MI, SPIRVGlobalRegistry *GR)
static bool legalizeSpvConstComposite(LegalizerHelper &Helper, MachineInstr &MI, SPIRVGlobalRegistry *GR)
static bool legalizeLoad(LegalizerHelper &Helper, MachineInstr &MI, SPIRVGlobalRegistry *GR)
#define LLVM_DEBUG(...)
Definition Debug.h:119
APInt bitcastToAPInt() const
Definition APFloat.h:1467
static APFloat getLargest(const fltSemantics &Sem, bool Negative=false)
Returns the largest finite number in the given semantics.
Definition APFloat.h:1234
static APFloat getInf(const fltSemantics &Sem, bool Negative=false)
Factory for Positive and Negative Infinity.
Definition APFloat.h:1194
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:1537
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:880
static APInt getOneBitSet(unsigned numBits, unsigned BitNo)
Return an APInt with exactly one bit set in the result.
Definition APInt.h:240
Represent a constant reference to an array (0 or more elements consecutively in memory),...
Definition ArrayRef.h:40
static LLVM_ABI ArrayType * get(Type *ElementType, uint64_t NumElements)
This static method is the primary way to construct an ArrayType.
Predicate
This enumeration lists the possible predicates for CmpInst subclasses.
Definition InstrTypes.h:740
@ ICMP_UGE
unsigned greater or equal
Definition InstrTypes.h:764
@ ICMP_UGT
unsigned greater than
Definition InstrTypes.h:763
@ ICMP_ULT
unsigned less than
Definition InstrTypes.h:765
@ ICMP_NE
not equal
Definition InstrTypes.h:762
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:348
static constexpr LLT vector(ElementCount EC, unsigned ScalarSizeInBits)
Get a low-level vector of some number of elements and element width.
LLT getScalarType() const
constexpr bool isPointerVector() const
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.
constexpr bool isPointer() const
constexpr unsigned getAddressSpace() const
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 TypeSize getSizeInBytes() const
Returns the total size of the type in bytes, i.e.
LLT getElementType() const
Returns the vector's element type. Only valid for vector types.
LegalizeRuleSet & minScalar(unsigned TypeIdx, const LLT Ty)
Ensure the scalar is at least as wide as Ty.
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 & unsupportedFor(std::initializer_list< LLT > Types)
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 & 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)
LLVM_ABI MachineInstrBuilder createStackTemporary(TypeSize Bytes, Align Alignment, MachinePointerInfo &PtrInfo)
Create a stack temporary based on the size in bytes and the alignment.
MachineIRBuilder & MIRBuilder
Expose MIRBuilder so clients can set their own RecordInsertInstruction functions.
LLVM_ABI Align getStackTemporaryAlignment(LLT Type, Align MinAlign=Align()) const
Return the alignment to use for a stack temporary object with the given type.
LegalizeRuleSet & getActionDefinitionsBuilder(unsigned Opcode)
Get the action definition builder for the given opcode.
MachineRegisterInfo & getRegInfo()
getRegInfo - Return information about the registers currently in use.
Helper class to build MachineInstr.
LLVMContext & getContext() const
MachineInstrBuilder buildUnmerge(ArrayRef< LLT > Res, const SrcOp &Op)
Build and insert Res0, ... = G_UNMERGE_VALUES Op.
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 buildBuildVector(const DstOp &Res, ArrayRef< Register > Ops)
Build and insert Res = G_BUILD_VECTOR Op0, ...
MachineInstrBuilder buildLoad(const DstOp &Res, const SrcOp &Addr, MachineMemOperand &MMO)
Build and insert Res = G_LOAD Addr, MMO.
MachineInstrBuilder buildStore(const SrcOp &Val, const SrcOp &Addr, MachineMemOperand &MMO)
Build and insert G_STORE Val, Addr, MMO.
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, RegState Flags={}, unsigned SubReg=0) const
Add a virtual register use operand.
const MachineInstrBuilder & addDef(Register RegNo, RegState Flags={}, unsigned SubReg=0) const
Add a virtual register definition operand.
Representation of each machine instruction.
A description of a memory reference used in the backend.
const MachinePointerInfo & getPointerInfo() const
LLVM_ABI Align getAlign() const
Return the minimum known alignment in bytes of the actual memory reference.
MachineOperand class - Representation of each machine instruction operand.
Register getReg() const
getReg - Returns the register number.
MachineRegisterInfo - Keep track of information for virtual and physical registers,...
LLT getType(Register Reg) const
Get the low-level type of Reg or LLT{} if Reg is not a generic (target independent) virtual register.
LLVM_ABI void setRegClass(Register Reg, const TargetRegisterClass *RC)
setRegClass - Set the register class of the specified virtual register.
LLVM_ABI Register createGenericVirtualRegister(LLT Ty, StringRef Name="")
Create and return a new generic virtual register with low-level type Ty.
Wrapper class representing virtual and physical registers.
Definition Register.h:20
void assignSPIRVTypeToVReg(SPIRVTypeInst Type, Register VReg, const MachineFunction &MF)
SPIRVTypeInst getOrCreateSPIRVPointerType(const Type *BaseType, MachineIRBuilder &MIRBuilder, SPIRV::StorageClass::StorageClass SC, bool ForceTyped=false)
const TargetRegisterClass * getRegClass(SPIRVTypeInst SpvType) const
const Type * getTypeForSPIRVType(SPIRVTypeInst Ty) const
LLT getRegType(SPIRVTypeInst SpvType) const
SPIRVTypeInst getScalarOrVectorComponentType(SPIRVTypeInst Type) const
SPIRVTypeInst getOrCreateSPIRVType(const Type *Type, MachineInstr &I, SPIRV::AccessQualifier::AccessQualifier AQ, bool EmitIR)
SPIRVTypeInst getSPIRVTypeForVReg(Register VReg, const MachineFunction *MF=nullptr) 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
void push_back(const T &Elt)
This is a 'vector' (really, a variable-sized array), optimized for the case when the array is small.
static constexpr TypeSize getFixed(ScalarTy ExactSize)
Definition TypeSize.h:343
The instances of the Type class are immutable: once they are created, they are never changed.
Definition Type.h:46
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.
LLVM_ABI LegalityPredicate isScalar(unsigned TypeIdx)
True iff the specified type index is a scalar.
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:280
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:209
const std::set< unsigned > & getTypeFoldingSupportedOpcodes()
int64_t foldImm(const MachineOperand &MO, const MachineRegisterInfo *MRI)
decltype(auto) cast(const From &Val)
cast<X> - Return the argument parameter cast to the specified type.
Definition Casting.h:559
Align commonAlignment(Align A, uint64_t Offset)
Returns the alignment that satisfies both alignments.
Definition Alignment.h:201
This struct is a compact representation of a valid (non-zero power of two) alignment.
Definition Alignment.h:39
The LegalityQuery object bundles together all the information that's needed to decide whether a given...
ArrayRef< LLT > Types
This class contains a discriminated union of information about pointers in memory operands,...
MachinePointerInfo getWithOffset(int64_t O) const