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();
477
478 getActionDefinitionsBuilder({G_UADDO, G_USUBO, G_UMULO, G_SMULO})
479 .alwaysLegal();
480
481 getActionDefinitionsBuilder({G_SADDO, G_SSUBO}).lower();
482
483 // Lowering widens s64 to s128, which needs
484 // SPV_ALTERA_arbitrary_precision_integers. Mark s64 unsupported otherwise.
485 auto &MulFix = getActionDefinitionsBuilder({G_SMULFIX, G_UMULFIX});
486 if (!HasArbitraryPrecisionInts)
487 MulFix.unsupportedFor({s64});
488 MulFix.lower();
489
490 getActionDefinitionsBuilder({G_LROUND, G_LLROUND})
491 .legalForCartesianProduct(allFloatScalarsAndVectors,
492 allIntScalarsAndVectors);
493
494 // FP conversions.
495 getActionDefinitionsBuilder({G_FPTRUNC, G_FPEXT})
496 .legalForCartesianProduct(allFloatScalarsAndVectors);
497
498 // Pointer-handling.
499 getActionDefinitionsBuilder(G_FRAME_INDEX).legalFor({p0});
500
501 getActionDefinitionsBuilder(G_GLOBAL_VALUE).legalFor(allPtrs);
502
503 // Control-flow. In some cases (e.g. constants) s1 may be promoted to s32.
505 getActionDefinitionsBuilder(G_BRCOND).legalFor({s1, s32});
506
508 allFloatScalarsAndVectors, {s32, v2s32, v3s32, v4s32, v8s32, v16s32});
509
510 // TODO: Review the target OpenCL and GLSL Extended Instruction Set specs to
511 // tighten these requirements. Many of these math functions are only legal on
512 // specific bitwidths, so they are not selectable for
513 // allFloatScalarsAndVectors.
514 // clang-format off
515 getActionDefinitionsBuilder({G_STRICT_FSQRT,
516 G_FPOW,
517 G_FEXP,
518 G_FMODF,
519 G_FSINCOS,
520 G_FEXP2,
521 G_FEXP10,
522 G_FLOG,
523 G_FLOG2,
524 G_FLOG10,
525 G_FABS,
526 G_FMINNUM,
527 G_FMAXNUM,
528 G_FCEIL,
529 G_FCOS,
530 G_FSIN,
531 G_FTAN,
532 G_FACOS,
533 G_FASIN,
534 G_FATAN,
535 G_FATAN2,
536 G_FCOSH,
537 G_FSINH,
538 G_FTANH,
539 G_FSQRT,
540 G_FFLOOR,
541 G_FRINT,
542 G_FNEARBYINT,
543 G_INTRINSIC_ROUND,
544 G_INTRINSIC_TRUNC,
545 G_FMINIMUM,
546 G_FMAXIMUM,
547 G_INTRINSIC_ROUNDEVEN})
548 .legalFor(allFloatScalars)
549 .legalFor(allowedFloatVectorTypes)
552 0, ElementCount::getFixed(MaxVectorSize)))
554 // clang-format on
555
556 getActionDefinitionsBuilder(G_FCOPYSIGN)
557 .legalForCartesianProduct(allFloatScalarsAndVectors,
558 allFloatScalarsAndVectors);
559
561 allFloatScalarsAndVectors, allIntScalarsAndVectors);
562
563 if (ST.canUseExtInstSet(SPIRV::InstructionSet::OpenCL_std)) {
565 {G_CTTZ, G_CTTZ_ZERO_POISON, G_CTLZ, G_CTLZ_ZERO_POISON})
566 .legalForCartesianProduct(allIntScalarsAndVectors,
567 allIntScalarsAndVectors);
568
569 // Struct return types become a single scalar, so cannot easily legalize.
570 getActionDefinitionsBuilder({G_SMULH, G_UMULH}).alwaysLegal();
571 }
572
573 getActionDefinitionsBuilder(G_IS_FPCLASS).custom();
574
575 getActionDefinitionsBuilder({G_INTRINSIC, G_INTRINSIC_CONVERGENT,
576 G_INTRINSIC_CONVERGENT_W_SIDE_EFFECTS})
577 .alwaysLegal();
579 getActionDefinitionsBuilder({G_TRAP, G_DEBUGTRAP, G_UBSANTRAP}).alwaysLegal();
580
581 verify(*ST.getInstrInfo());
582}
583
585 MachineInstr &MI) {
586 MachineIRBuilder &MIRBuilder = Helper.MIRBuilder;
587 Register DstReg = MI.getOperand(0).getReg();
588 Register SrcReg = MI.getOperand(1).getReg();
589 Register IdxReg = MI.getOperand(2).getReg();
590
591 MIRBuilder
592 .buildIntrinsic(Intrinsic::spv_extractelt, ArrayRef<Register>{DstReg})
593 .addUse(SrcReg)
594 .addUse(IdxReg);
595 MI.eraseFromParent();
596 return true;
597}
598
600 MachineIRBuilder &MIRBuilder = Helper.MIRBuilder;
601 Register DstReg = MI.getOperand(0).getReg();
602 Register SrcReg = MI.getOperand(1).getReg();
603 Register ValReg = MI.getOperand(2).getReg();
604 Register IdxReg = MI.getOperand(3).getReg();
605
606 MIRBuilder
607 .buildIntrinsic(Intrinsic::spv_insertelt, ArrayRef<Register>{DstReg})
608 .addUse(SrcReg)
609 .addUse(ValReg)
610 .addUse(IdxReg);
611 MI.eraseFromParent();
612 return true;
613}
614
616 LegalizerHelper &Helper,
619 Register ConvReg = MRI.createGenericVirtualRegister(ConvTy);
620 MRI.setRegClass(ConvReg, GR->getRegClass(SpvType));
621 GR->assignSPIRVTypeToVReg(SpvType, ConvReg, Helper.MIRBuilder.getMF());
622 Helper.MIRBuilder.buildInstr(TargetOpcode::G_PTRTOINT)
623 .addDef(ConvReg)
624 .addUse(Reg);
625 return ConvReg;
626}
627
628static bool needsVectorLegalization(const LLT &Ty, const SPIRVSubtarget &ST) {
629 if (!Ty.isVector())
630 return false;
631 unsigned NumElements = Ty.getNumElements();
632 unsigned MaxVectorSize = ST.isShader() ? 4 : 16;
633 return (NumElements > 4 && !isPowerOf2_32(NumElements)) ||
634 NumElements > MaxVectorSize;
635}
636
639 MachineRegisterInfo &MRI = MI.getMF()->getRegInfo();
640 MachineIRBuilder &MIRBuilder = Helper.MIRBuilder;
641 Register DstReg = MI.getOperand(0).getReg();
642 Register PtrReg = MI.getOperand(1).getReg();
643 LLT DstTy = MRI.getType(DstReg);
644
645 if (!DstTy.isVector())
646 return true;
647
648 const SPIRVSubtarget &ST = MI.getMF()->getSubtarget<SPIRVSubtarget>();
649 if (!needsVectorLegalization(DstTy, ST))
650 return true;
651
652 SmallVector<Register, 8> SplitRegs;
653 LLT EltTy = DstTy.getElementType();
654 unsigned NumElts = DstTy.getNumElements();
655
656 LLT PtrTy = MRI.getType(PtrReg);
657 auto Zero = MIRBuilder.buildConstant(LLT::scalar(32), 0);
658
659 for (unsigned i = 0; i < NumElts; ++i) {
660 auto Idx = MIRBuilder.buildConstant(LLT::scalar(32), i);
661 Register EltPtr = MRI.createGenericVirtualRegister(PtrTy);
662
663 MIRBuilder.buildIntrinsic(Intrinsic::spv_gep, ArrayRef<Register>{EltPtr})
664 .addImm(1) // InBounds
665 .addUse(PtrReg)
666 .addUse(Zero.getReg(0))
667 .addUse(Idx.getReg(0));
668
669 MachinePointerInfo EltPtrInfo;
670 Align EltAlign = Align(1);
671 if (!MI.memoperands_empty()) {
672 MachineMemOperand *MMO = *MI.memoperands_begin();
673 EltPtrInfo =
674 MMO->getPointerInfo().getWithOffset(i * EltTy.getSizeInBytes());
675 EltAlign = commonAlignment(MMO->getAlign(), i * EltTy.getSizeInBytes());
676 }
677
678 Register EltReg = MRI.createGenericVirtualRegister(EltTy);
679 MIRBuilder.buildLoad(EltReg, EltPtr, EltPtrInfo, EltAlign);
680 SplitRegs.push_back(EltReg);
681 }
682
683 MIRBuilder.buildBuildVector(DstReg, SplitRegs);
684 MI.eraseFromParent();
685 return true;
686}
687
690 MachineRegisterInfo &MRI = MI.getMF()->getRegInfo();
691 MachineIRBuilder &MIRBuilder = Helper.MIRBuilder;
692 Register ValReg = MI.getOperand(0).getReg();
693 Register PtrReg = MI.getOperand(1).getReg();
694 LLT ValTy = MRI.getType(ValReg);
695
696 assert(ValTy.isVector() && "Expected vector store");
697
698 SmallVector<Register, 8> SplitRegs;
699 LLT EltTy = ValTy.getElementType();
700 unsigned NumElts = ValTy.getNumElements();
701
702 for (unsigned i = 0; i < NumElts; ++i)
703 SplitRegs.push_back(MRI.createGenericVirtualRegister(EltTy));
704
705 MIRBuilder.buildUnmerge(SplitRegs, ValReg);
706
707 LLT PtrTy = MRI.getType(PtrReg);
708 auto Zero = MIRBuilder.buildConstant(LLT::scalar(32), 0);
709
710 for (unsigned i = 0; i < NumElts; ++i) {
711 auto Idx = MIRBuilder.buildConstant(LLT::scalar(32), i);
712 Register EltPtr = MRI.createGenericVirtualRegister(PtrTy);
713
714 MIRBuilder.buildIntrinsic(Intrinsic::spv_gep, ArrayRef<Register>{EltPtr})
715 .addImm(1) // InBounds
716 .addUse(PtrReg)
717 .addUse(Zero.getReg(0))
718 .addUse(Idx.getReg(0));
719
720 MachinePointerInfo EltPtrInfo;
721 Align EltAlign = Align(1);
722 if (!MI.memoperands_empty()) {
723 MachineMemOperand *MMO = *MI.memoperands_begin();
724 EltPtrInfo =
725 MMO->getPointerInfo().getWithOffset(i * EltTy.getSizeInBytes());
726 EltAlign = commonAlignment(MMO->getAlign(), i * EltTy.getSizeInBytes());
727 }
728
729 MIRBuilder.buildStore(SplitRegs[i], EltPtr, EltPtrInfo, EltAlign);
730 }
731
732 MI.eraseFromParent();
733 return true;
734}
735
738 LostDebugLocObserver &LocObserver) const {
739 MachineRegisterInfo &MRI = MI.getMF()->getRegInfo();
740 switch (MI.getOpcode()) {
741 default:
742 // TODO: implement legalization for other opcodes.
743 return true;
744 case TargetOpcode::G_BITCAST:
745 return legalizeBitcast(Helper, MI);
746 case TargetOpcode::G_EXTRACT_VECTOR_ELT:
747 return legalizeExtractVectorElt(Helper, MI);
748 case TargetOpcode::G_INSERT_VECTOR_ELT:
749 return legalizeInsertVectorElt(Helper, MI);
750 case TargetOpcode::G_INTRINSIC:
751 case TargetOpcode::G_INTRINSIC_W_SIDE_EFFECTS:
752 return legalizeIntrinsic(Helper, MI);
753 case TargetOpcode::G_IS_FPCLASS:
754 return legalizeIsFPClass(Helper, MI, LocObserver);
755 case TargetOpcode::G_ICMP: {
756 auto &Op0 = MI.getOperand(2);
757 auto &Op1 = MI.getOperand(3);
758 Register Reg0 = Op0.getReg();
759 Register Reg1 = Op1.getReg();
761 static_cast<CmpInst::Predicate>(MI.getOperand(1).getPredicate());
762 if ((!ST->canDirectlyComparePointers() ||
764 MRI.getType(Reg0).isPointer() && MRI.getType(Reg1).isPointer()) {
765 LLT ConvT = LLT::scalar(ST->getPointerSize());
766 Type *LLVMTy = IntegerType::get(MI.getMF()->getFunction().getContext(),
767 ST->getPointerSize());
768 SPIRVTypeInst SpirvTy = GR->getOrCreateSPIRVType(
769 LLVMTy, Helper.MIRBuilder, SPIRV::AccessQualifier::ReadWrite, true);
770 Op0.setReg(convertPtrToInt(Reg0, ConvT, SpirvTy, Helper, MRI, GR));
771 Op1.setReg(convertPtrToInt(Reg1, ConvT, SpirvTy, Helper, MRI, GR));
772 }
773 return true;
774 }
775 case TargetOpcode::G_LOAD:
776 return legalizeLoad(Helper, MI, GR);
777 case TargetOpcode::G_STORE:
778 return legalizeStore(Helper, MI, GR);
779 }
780}
781
784 Register SrcReg, LLT SrcTy,
785 MachinePointerInfo &PtrInfo, Align &VecAlign) {
786 MachineIRBuilder &MIRBuilder = Helper.MIRBuilder;
787 MachineRegisterInfo &MRI = *MIRBuilder.getMRI();
788
789 VecAlign = Helper.getStackTemporaryAlignment(SrcTy);
790 auto StackTemp = Helper.createStackTemporary(
791 TypeSize::getFixed(SrcTy.getSizeInBytes()), VecAlign, PtrInfo);
792
793 // Set the type of StackTemp to a pointer to an array of the element type.
794 SPIRVTypeInst SpvSrcTy = GR->getSPIRVTypeForVReg(SrcReg);
795 SPIRVTypeInst EltSpvTy = GR->getScalarOrVectorComponentType(SpvSrcTy);
796 const Type *LLVMEltTy = GR->getTypeForSPIRVType(EltSpvTy);
797 const Type *LLVMArrTy =
798 ArrayType::get(const_cast<Type *>(LLVMEltTy), SrcTy.getNumElements());
799 SPIRVTypeInst ArrSpvTy = GR->getOrCreateSPIRVType(
800 LLVMArrTy, MIRBuilder, SPIRV::AccessQualifier::ReadWrite, true);
801 SPIRVTypeInst PtrToArrSpvTy = GR->getOrCreateSPIRVPointerType(
802 ArrSpvTy, MIRBuilder, SPIRV::StorageClass::Function);
803
804 Register StackReg = StackTemp.getReg(0);
805 MRI.setRegClass(StackReg, GR->getRegClass(PtrToArrSpvTy));
806 GR->assignSPIRVTypeToVReg(PtrToArrSpvTy, StackReg, MIRBuilder.getMF());
807
808 return StackTemp;
809}
810
813 LLVM_DEBUG(dbgs() << "Found a bitcast instruction\n");
814 MachineIRBuilder &MIRBuilder = Helper.MIRBuilder;
815 MachineRegisterInfo &MRI = *MIRBuilder.getMRI();
816 const SPIRVSubtarget &ST = MI.getMF()->getSubtarget<SPIRVSubtarget>();
817
818 Register DstReg = MI.getOperand(0).getReg();
819 Register SrcReg = MI.getOperand(2).getReg();
820 LLT DstTy = MRI.getType(DstReg);
821 LLT SrcTy = MRI.getType(SrcReg);
822
823 // If an spv_bitcast needs to be legalized, we convert it to G_BITCAST to
824 // allow using the generic legalization rules.
825 if (needsVectorLegalization(DstTy, ST) ||
826 needsVectorLegalization(SrcTy, ST)) {
827 LLVM_DEBUG(dbgs() << "Replacing with a G_BITCAST\n");
828 MIRBuilder.buildBitcast(DstReg, SrcReg);
829 MI.eraseFromParent();
830 }
831 return true;
832}
833
836 MachineIRBuilder &MIRBuilder = Helper.MIRBuilder;
837 MachineRegisterInfo &MRI = *MIRBuilder.getMRI();
838 const SPIRVSubtarget &ST = MI.getMF()->getSubtarget<SPIRVSubtarget>();
839
840 Register DstReg = MI.getOperand(0).getReg();
841 LLT DstTy = MRI.getType(DstReg);
842
843 if (needsVectorLegalization(DstTy, ST)) {
844 Register SrcReg = MI.getOperand(2).getReg();
845 Register ValReg = MI.getOperand(3).getReg();
846 LLT SrcTy = MRI.getType(SrcReg);
847 MachineOperand &IdxOperand = MI.getOperand(4);
848
849 if (getImm(IdxOperand, &MRI)) {
850 uint64_t IdxVal = foldImm(IdxOperand, &MRI);
851 if (IdxVal < SrcTy.getNumElements()) {
853 SPIRVTypeInst ElementType =
855 LLT ElementLLTTy = GR->getRegType(ElementType);
856 for (unsigned I = 0, E = SrcTy.getNumElements(); I < E; ++I) {
857 Register Reg = MRI.createGenericVirtualRegister(ElementLLTTy);
858 MRI.setRegClass(Reg, GR->getRegClass(ElementType));
859 GR->assignSPIRVTypeToVReg(ElementType, Reg, *MI.getMF());
860 Regs.push_back(Reg);
861 }
862 MIRBuilder.buildUnmerge(Regs, SrcReg);
863 Regs[IdxVal] = ValReg;
864 MIRBuilder.buildBuildVector(DstReg, Regs);
865 MI.eraseFromParent();
866 return true;
867 }
868 }
869
870 LLT EltTy = SrcTy.getElementType();
871 Align VecAlign;
872 MachinePointerInfo PtrInfo;
873 auto StackTemp = createStackTemporaryForVector(Helper, GR, SrcReg, SrcTy,
874 PtrInfo, VecAlign);
875
876 MIRBuilder.buildStore(SrcReg, StackTemp, PtrInfo, VecAlign);
877
878 Register IdxReg = IdxOperand.getReg();
879 LLT PtrTy = MRI.getType(StackTemp.getReg(0));
880 Register EltPtr = MRI.createGenericVirtualRegister(PtrTy);
881 auto Zero = MIRBuilder.buildConstant(LLT::scalar(32), 0);
882
883 MIRBuilder.buildIntrinsic(Intrinsic::spv_gep, ArrayRef<Register>{EltPtr})
884 .addImm(1) // InBounds
885 .addUse(StackTemp.getReg(0))
886 .addUse(Zero.getReg(0))
887 .addUse(IdxReg);
888
890 Align EltAlign = Helper.getStackTemporaryAlignment(EltTy);
891 MIRBuilder.buildStore(ValReg, EltPtr, EltPtrInfo, EltAlign);
892
893 MIRBuilder.buildLoad(DstReg, StackTemp, PtrInfo, VecAlign);
894 MI.eraseFromParent();
895 return true;
896 }
897 return true;
898}
899
902 MachineIRBuilder &MIRBuilder = Helper.MIRBuilder;
903 MachineRegisterInfo &MRI = *MIRBuilder.getMRI();
904 const SPIRVSubtarget &ST = MI.getMF()->getSubtarget<SPIRVSubtarget>();
905
906 Register SrcReg = MI.getOperand(2).getReg();
907 LLT SrcTy = MRI.getType(SrcReg);
908
909 if (needsVectorLegalization(SrcTy, ST)) {
910 Register DstReg = MI.getOperand(0).getReg();
911 MachineOperand &IdxOperand = MI.getOperand(3);
912
913 if (getImm(IdxOperand, &MRI)) {
914 uint64_t IdxVal = foldImm(IdxOperand, &MRI);
915 if (IdxVal < SrcTy.getNumElements()) {
916 LLT DstTy = MRI.getType(DstReg);
918 SPIRVTypeInst DstSpvTy = GR->getSPIRVTypeForVReg(DstReg);
919 for (unsigned I = 0, E = SrcTy.getNumElements(); I < E; ++I) {
920 if (I == IdxVal) {
921 Regs.push_back(DstReg);
922 } else {
924 MRI.setRegClass(Reg, GR->getRegClass(DstSpvTy));
925 GR->assignSPIRVTypeToVReg(DstSpvTy, Reg, *MI.getMF());
926 Regs.push_back(Reg);
927 }
928 }
929 MIRBuilder.buildUnmerge(Regs, SrcReg);
930 MI.eraseFromParent();
931 return true;
932 }
933 }
934
935 LLT EltTy = SrcTy.getElementType();
936 Align VecAlign;
937 MachinePointerInfo PtrInfo;
938 auto StackTemp = createStackTemporaryForVector(Helper, GR, SrcReg, SrcTy,
939 PtrInfo, VecAlign);
940
941 MIRBuilder.buildStore(SrcReg, StackTemp, PtrInfo, VecAlign);
942
943 Register IdxReg = IdxOperand.getReg();
944 LLT PtrTy = MRI.getType(StackTemp.getReg(0));
945 Register EltPtr = MRI.createGenericVirtualRegister(PtrTy);
946 auto Zero = MIRBuilder.buildConstant(LLT::scalar(32), 0);
947
948 MIRBuilder.buildIntrinsic(Intrinsic::spv_gep, ArrayRef<Register>{EltPtr})
949 .addImm(1) // InBounds
950 .addUse(StackTemp.getReg(0))
951 .addUse(Zero.getReg(0))
952 .addUse(IdxReg);
953
955 Align EltAlign = Helper.getStackTemporaryAlignment(EltTy);
956 MIRBuilder.buildLoad(DstReg, EltPtr, EltPtrInfo, EltAlign);
957
958 MI.eraseFromParent();
959 return true;
960 }
961 return true;
962}
963
966 MachineIRBuilder &MIRBuilder = Helper.MIRBuilder;
967 MachineRegisterInfo &MRI = *MIRBuilder.getMRI();
968 const SPIRVSubtarget &ST = MI.getMF()->getSubtarget<SPIRVSubtarget>();
969
970 Register DstReg = MI.getOperand(0).getReg();
971 LLT DstTy = MRI.getType(DstReg);
972
973 if (!needsVectorLegalization(DstTy, ST))
974 return true;
975
977 if (MI.getNumOperands() == 2) {
978 // The "null" case: no values are attached.
979 LLT EltTy = DstTy.getElementType();
980 auto Zero = MIRBuilder.buildConstant(EltTy, 0);
981 SPIRVTypeInst SpvDstTy = GR->getSPIRVTypeForVReg(DstReg);
982 SPIRVTypeInst SpvEltTy = GR->getScalarOrVectorComponentType(SpvDstTy);
983 GR->assignSPIRVTypeToVReg(SpvEltTy, Zero.getReg(0), MIRBuilder.getMF());
984 for (unsigned i = 0; i < DstTy.getNumElements(); ++i)
985 SrcRegs.push_back(Zero.getReg(0));
986 } else {
987 for (unsigned i = 2; i < MI.getNumOperands(); ++i) {
988 SrcRegs.push_back(MI.getOperand(i).getReg());
989 }
990 }
991 MIRBuilder.buildBuildVector(DstReg, SrcRegs);
992 MI.eraseFromParent();
993 return true;
994}
995
997 MachineInstr &MI) const {
998 LLVM_DEBUG(dbgs() << "legalizeIntrinsic: " << MI);
999 auto IntrinsicID = cast<GIntrinsic>(MI).getIntrinsicID();
1000 switch (IntrinsicID) {
1001 case Intrinsic::spv_bitcast:
1002 return legalizeSpvBitcast(Helper, MI, GR);
1003 case Intrinsic::spv_insertelt:
1004 return legalizeSpvInsertElt(Helper, MI, GR);
1005 case Intrinsic::spv_extractelt:
1006 return legalizeSpvExtractElt(Helper, MI, GR);
1007 case Intrinsic::spv_const_composite:
1008 return legalizeSpvConstComposite(Helper, MI, GR);
1009 }
1010 return true;
1011}
1012
1013bool SPIRVLegalizerInfo::legalizeBitcast(LegalizerHelper &Helper,
1014 MachineInstr &MI) const {
1015 // Once the G_BITCAST is using vectors that are allowed, we turn it back into
1016 // an spv_bitcast to avoid verifier problems when the register types are the
1017 // same for the source and the result. Note that the SPIR-V types associated
1018 // with the bitcast can be different even if the register types are the same.
1019 MachineIRBuilder &MIRBuilder = Helper.MIRBuilder;
1020 Register DstReg = MI.getOperand(0).getReg();
1021 Register SrcReg = MI.getOperand(1).getReg();
1022 SmallVector<Register, 1> DstRegs = {DstReg};
1023 MIRBuilder.buildIntrinsic(Intrinsic::spv_bitcast, DstRegs).addUse(SrcReg);
1024 MI.eraseFromParent();
1025 return true;
1026}
1027
1028// Note this code was copied from LegalizerHelper::lowerISFPCLASS and adjusted
1029// to ensure that all instructions created during the lowering have SPIR-V types
1030// assigned to them.
1031bool SPIRVLegalizerInfo::legalizeIsFPClass(
1033 LostDebugLocObserver &LocObserver) const {
1034 auto [DstReg, DstTy, SrcReg, SrcTy] = MI.getFirst2RegLLTs();
1035 FPClassTest Mask = static_cast<FPClassTest>(MI.getOperand(2).getImm());
1036
1037 auto &MIRBuilder = Helper.MIRBuilder;
1038 auto &MF = MIRBuilder.getMF();
1039 MachineRegisterInfo &MRI = MF.getRegInfo();
1040
1041 Type *LLVMDstTy =
1042 IntegerType::get(MIRBuilder.getContext(), DstTy.getScalarSizeInBits());
1043 if (DstTy.isVector())
1044 LLVMDstTy = VectorType::get(LLVMDstTy, DstTy.getElementCount());
1045 SPIRVTypeInst SPIRVDstTy = GR->getOrCreateSPIRVType(
1046 LLVMDstTy, MIRBuilder, SPIRV::AccessQualifier::ReadWrite,
1047 /*EmitIR*/ true);
1048
1049 unsigned BitSize = SrcTy.getScalarSizeInBits();
1050 const fltSemantics &Semantics = getFltSemanticForLLT(SrcTy.getScalarType());
1051
1052 LLT IntTy = LLT::scalar(BitSize);
1053 Type *LLVMIntTy = IntegerType::get(MIRBuilder.getContext(), BitSize);
1054 if (SrcTy.isVector()) {
1055 IntTy = LLT::vector(SrcTy.getElementCount(), IntTy);
1056 LLVMIntTy = VectorType::get(LLVMIntTy, SrcTy.getElementCount());
1057 }
1058 SPIRVTypeInst SPIRVIntTy = GR->getOrCreateSPIRVType(
1059 LLVMIntTy, MIRBuilder, SPIRV::AccessQualifier::ReadWrite,
1060 /*EmitIR*/ true);
1061
1062 // Clang doesn't support capture of structured bindings:
1063 LLT DstTyCopy = DstTy;
1064 const auto assignSPIRVTy = [&](MachineInstrBuilder &&MI) {
1065 // Assign this MI's (assumed only) destination to one of the two types we
1066 // expect: either the G_IS_FPCLASS's destination type, or the integer type
1067 // bitcast from the source type.
1068 LLT MITy = MRI.getType(MI.getReg(0));
1069 assert((MITy == IntTy || MITy == DstTyCopy) &&
1070 "Unexpected LLT type while lowering G_IS_FPCLASS");
1071 SPIRVTypeInst SPVTy = MITy == IntTy ? SPIRVIntTy : SPIRVDstTy;
1072 GR->assignSPIRVTypeToVReg(SPVTy, MI.getReg(0), MF);
1073 return MI;
1074 };
1075
1076 // Helper to build and assign a constant in one go
1077 const auto buildSPIRVConstant = [&](LLT Ty, auto &&C) -> MachineInstrBuilder {
1078 if (!Ty.isFixedVector())
1079 return assignSPIRVTy(MIRBuilder.buildConstant(Ty, C));
1080 auto ScalarC = MIRBuilder.buildConstant(Ty.getScalarType(), C);
1081 assert((Ty == IntTy || Ty == DstTyCopy) &&
1082 "Unexpected LLT type while lowering constant for G_IS_FPCLASS");
1083 SPIRVTypeInst VecEltTy = GR->getOrCreateSPIRVType(
1084 (Ty == IntTy ? LLVMIntTy : LLVMDstTy)->getScalarType(), MIRBuilder,
1085 SPIRV::AccessQualifier::ReadWrite,
1086 /*EmitIR*/ true);
1087 GR->assignSPIRVTypeToVReg(VecEltTy, ScalarC.getReg(0), MF);
1088 return assignSPIRVTy(MIRBuilder.buildSplatBuildVector(Ty, ScalarC));
1089 };
1090
1091 if (Mask == fcNone) {
1092 MIRBuilder.buildCopy(DstReg, buildSPIRVConstant(DstTy, 0));
1093 MI.eraseFromParent();
1094 return true;
1095 }
1096 if (Mask == fcAllFlags) {
1097 MIRBuilder.buildCopy(DstReg, buildSPIRVConstant(DstTy, 1));
1098 MI.eraseFromParent();
1099 return true;
1100 }
1101
1102 // Note that rather than creating a COPY here (between a floating-point and
1103 // integer type of the same size) we create a SPIR-V bitcast immediately. We
1104 // can't create a G_BITCAST because the LLTs are the same, and we can't seem
1105 // to correctly lower COPYs to SPIR-V bitcasts at this moment.
1106 Register ResVReg = MRI.createGenericVirtualRegister(IntTy);
1107 MRI.setRegClass(ResVReg, GR->getRegClass(SPIRVIntTy));
1108 GR->assignSPIRVTypeToVReg(SPIRVIntTy, ResVReg, Helper.MIRBuilder.getMF());
1109 auto AsInt = MIRBuilder.buildInstr(SPIRV::OpBitcast)
1110 .addDef(ResVReg)
1111 .addUse(GR->getSPIRVTypeID(SPIRVIntTy))
1112 .addUse(SrcReg);
1113 AsInt = assignSPIRVTy(std::move(AsInt));
1114
1115 // Various masks.
1116 APInt SignBit = APInt::getSignMask(BitSize);
1117 APInt ValueMask = APInt::getSignedMaxValue(BitSize); // All bits but sign.
1118 APInt Inf = APFloat::getInf(Semantics).bitcastToAPInt(); // Exp and int bit.
1119 APInt ExpMask = Inf;
1120 APInt AllOneMantissa = APFloat::getLargest(Semantics).bitcastToAPInt() & ~Inf;
1121 APInt QNaNBitMask =
1122 APInt::getOneBitSet(BitSize, AllOneMantissa.getActiveBits() - 1);
1123 APInt InversionMask = APInt::getAllOnes(DstTy.getScalarSizeInBits());
1124
1125 auto SignBitC = buildSPIRVConstant(IntTy, SignBit);
1126 auto ValueMaskC = buildSPIRVConstant(IntTy, ValueMask);
1127 auto InfC = buildSPIRVConstant(IntTy, Inf);
1128 auto ExpMaskC = buildSPIRVConstant(IntTy, ExpMask);
1129 auto ZeroC = buildSPIRVConstant(IntTy, 0);
1130
1131 auto Abs = assignSPIRVTy(MIRBuilder.buildAnd(IntTy, AsInt, ValueMaskC));
1132 auto Sign = assignSPIRVTy(
1133 MIRBuilder.buildICmp(CmpInst::Predicate::ICMP_NE, DstTy, AsInt, Abs));
1134
1135 auto Res = buildSPIRVConstant(DstTy, 0);
1136
1137 const auto appendToRes = [&](MachineInstrBuilder &&ToAppend) {
1138 Res = assignSPIRVTy(
1139 MIRBuilder.buildOr(DstTyCopy, Res, assignSPIRVTy(std::move(ToAppend))));
1140 };
1141
1142 // Tests that involve more than one class should be processed first.
1143 if ((Mask & fcFinite) == fcFinite) {
1144 // finite(V) ==> abs(V) u< exp_mask
1145 appendToRes(MIRBuilder.buildICmp(CmpInst::Predicate::ICMP_ULT, DstTy, Abs,
1146 ExpMaskC));
1147 Mask &= ~fcFinite;
1148 } else if ((Mask & fcFinite) == fcPosFinite) {
1149 // finite(V) && V > 0 ==> V u< exp_mask
1150 appendToRes(MIRBuilder.buildICmp(CmpInst::Predicate::ICMP_ULT, DstTy, AsInt,
1151 ExpMaskC));
1152 Mask &= ~fcPosFinite;
1153 } else if ((Mask & fcFinite) == fcNegFinite) {
1154 // finite(V) && V < 0 ==> abs(V) u< exp_mask && signbit == 1
1155 auto Cmp = assignSPIRVTy(MIRBuilder.buildICmp(CmpInst::Predicate::ICMP_ULT,
1156 DstTy, Abs, ExpMaskC));
1157 appendToRes(MIRBuilder.buildAnd(DstTy, Cmp, Sign));
1158 Mask &= ~fcNegFinite;
1159 }
1160
1161 if (FPClassTest PartialCheck = Mask & (fcZero | fcSubnormal)) {
1162 // fcZero | fcSubnormal => test all exponent bits are 0
1163 // TODO: Handle sign bit specific cases
1164 // TODO: Handle inverted case
1165 if (PartialCheck == (fcZero | fcSubnormal)) {
1166 auto ExpBits = assignSPIRVTy(MIRBuilder.buildAnd(IntTy, AsInt, ExpMaskC));
1167 appendToRes(MIRBuilder.buildICmp(CmpInst::Predicate::ICMP_EQ, DstTy,
1168 ExpBits, ZeroC));
1169 Mask &= ~PartialCheck;
1170 }
1171 }
1172
1173 // Check for individual classes.
1174 if (FPClassTest PartialCheck = Mask & fcZero) {
1175 if (PartialCheck == fcPosZero)
1176 appendToRes(MIRBuilder.buildICmp(CmpInst::Predicate::ICMP_EQ, DstTy,
1177 AsInt, ZeroC));
1178 else if (PartialCheck == fcZero)
1179 appendToRes(
1180 MIRBuilder.buildICmp(CmpInst::Predicate::ICMP_EQ, DstTy, Abs, ZeroC));
1181 else // fcNegZero
1182 appendToRes(MIRBuilder.buildICmp(CmpInst::Predicate::ICMP_EQ, DstTy,
1183 AsInt, SignBitC));
1184 }
1185
1186 if (FPClassTest PartialCheck = Mask & fcSubnormal) {
1187 // issubnormal(V) ==> unsigned(abs(V) - 1) u< (all mantissa bits set)
1188 // issubnormal(V) && V>0 ==> unsigned(V - 1) u< (all mantissa bits set)
1189 auto V = (PartialCheck == fcPosSubnormal) ? AsInt : Abs;
1190 auto OneC = buildSPIRVConstant(IntTy, 1);
1191 auto VMinusOne = MIRBuilder.buildSub(IntTy, V, OneC);
1192 auto SubnormalRes = assignSPIRVTy(
1193 MIRBuilder.buildICmp(CmpInst::Predicate::ICMP_ULT, DstTy, VMinusOne,
1194 buildSPIRVConstant(IntTy, AllOneMantissa)));
1195 if (PartialCheck == fcNegSubnormal)
1196 SubnormalRes = MIRBuilder.buildAnd(DstTy, SubnormalRes, Sign);
1197 appendToRes(std::move(SubnormalRes));
1198 }
1199
1200 if (FPClassTest PartialCheck = Mask & fcInf) {
1201 if (PartialCheck == fcPosInf)
1202 appendToRes(MIRBuilder.buildICmp(CmpInst::Predicate::ICMP_EQ, DstTy,
1203 AsInt, InfC));
1204 else if (PartialCheck == fcInf)
1205 appendToRes(
1206 MIRBuilder.buildICmp(CmpInst::Predicate::ICMP_EQ, DstTy, Abs, InfC));
1207 else { // fcNegInf
1208 APInt NegInf = APFloat::getInf(Semantics, true).bitcastToAPInt();
1209 auto NegInfC = buildSPIRVConstant(IntTy, NegInf);
1210 appendToRes(MIRBuilder.buildICmp(CmpInst::Predicate::ICMP_EQ, DstTy,
1211 AsInt, NegInfC));
1212 }
1213 }
1214
1215 if (FPClassTest PartialCheck = Mask & fcNan) {
1216 auto InfWithQnanBitC =
1217 buildSPIRVConstant(IntTy, std::move(Inf) | QNaNBitMask);
1218 if (PartialCheck == fcNan) {
1219 // isnan(V) ==> abs(V) u> int(inf)
1220 appendToRes(
1221 MIRBuilder.buildICmp(CmpInst::Predicate::ICMP_UGT, DstTy, Abs, InfC));
1222 } else if (PartialCheck == fcQNan) {
1223 // isquiet(V) ==> abs(V) u>= (unsigned(Inf) | quiet_bit)
1224 appendToRes(MIRBuilder.buildICmp(CmpInst::Predicate::ICMP_UGE, DstTy, Abs,
1225 InfWithQnanBitC));
1226 } else { // fcSNan
1227 // issignaling(V) ==> abs(V) u> unsigned(Inf) &&
1228 // abs(V) u< (unsigned(Inf) | quiet_bit)
1229 auto IsNan = assignSPIRVTy(
1230 MIRBuilder.buildICmp(CmpInst::Predicate::ICMP_UGT, DstTy, Abs, InfC));
1231 auto IsNotQnan = assignSPIRVTy(MIRBuilder.buildICmp(
1232 CmpInst::Predicate::ICMP_ULT, DstTy, Abs, InfWithQnanBitC));
1233 appendToRes(MIRBuilder.buildAnd(DstTy, IsNan, IsNotQnan));
1234 }
1235 }
1236
1237 if (FPClassTest PartialCheck = Mask & fcNormal) {
1238 // isnormal(V) ==> (0 u< exp u< max_exp) ==> (unsigned(exp-1) u<
1239 // (max_exp-1))
1240 APInt ExpLSB = ExpMask & ~(ExpMask.shl(1));
1241 auto ExpMinusOne = assignSPIRVTy(
1242 MIRBuilder.buildSub(IntTy, Abs, buildSPIRVConstant(IntTy, ExpLSB)));
1243 APInt MaxExpMinusOne = std::move(ExpMask) - ExpLSB;
1244 auto NormalRes = assignSPIRVTy(
1245 MIRBuilder.buildICmp(CmpInst::Predicate::ICMP_ULT, DstTy, ExpMinusOne,
1246 buildSPIRVConstant(IntTy, MaxExpMinusOne)));
1247 if (PartialCheck == fcNegNormal)
1248 NormalRes = MIRBuilder.buildAnd(DstTy, NormalRes, Sign);
1249 else if (PartialCheck == fcPosNormal) {
1250 auto PosSign = assignSPIRVTy(MIRBuilder.buildXor(
1251 DstTy, Sign, buildSPIRVConstant(DstTy, InversionMask)));
1252 NormalRes = MIRBuilder.buildAnd(DstTy, NormalRes, PosSign);
1253 }
1254 appendToRes(std::move(NormalRes));
1255 }
1256
1257 MIRBuilder.buildCopy(DstReg, Res);
1258 MI.eraseFromParent();
1259 return true;
1260}
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