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