1//===--- SPIRVUtils.h ---- SPIR-V Utility Functions -------------*- 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 contains miscellaneous utility functions.
10//
11//===----------------------------------------------------------------------===//
12
13#ifndef LLVM_LIB_TARGET_SPIRV_SPIRVUTILS_H
14#define LLVM_LIB_TARGET_SPIRV_SPIRVUTILS_H
15
16#include "MCTargetDesc/SPIRVBaseInfo.h"
17#include "llvm/ADT/DenseMap.h"
18#include "llvm/ADT/SmallPtrSet.h"
19#include "llvm/ADT/StringMap.h"
20#include "llvm/Analysis/LoopInfo.h"
21#include "llvm/CodeGen/MachineBasicBlock.h"
22#include "llvm/IR/Dominators.h"
23#include "llvm/IR/GlobalVariable.h"
24#include "llvm/IR/IRBuilder.h"
25#include "llvm/IR/TypedPointerType.h"
26#include <queue>
27#include <set>
28#include <string>
29
30#include "SPIRVTypeInst.h"
31
32namespace llvm {
33class MCInst;
34class MachineFunction;
35class MachineInstrBuilder;
36class MachineIRBuilder;
37class MachineRegisterInfo;
38class Register;
39class StringRef;
40class Triple;
41class SPIRVInstrInfo;
42class SPIRVSubtarget;
43class SPIRVGlobalRegistry;
44
45// This class implements a partial ordering visitor, which visits a cyclic graph
46// in natural topological-like ordering. Topological ordering is not defined for
47// directed graphs with cycles, so this assumes cycles are a single node, and
48// ignores back-edges. The cycle is visited from the entry in the same
49// topological-like ordering.
50//
51// Note: this visitor REQUIRES a reducible graph.
52//
53// This means once we visit a node, we know all the possible ancestors have been
54// visited.
55//
56// clang-format off
57//
58// Given this graph:
59//
60// ,-> B -\
61// A -+ +---> D ----> E -> F -> G -> H
62// `-> C -/ ^ |
63// +-----------------+
64//
65// Visit order is:
66// A, [B, C in any order], D, E, F, G, H
67//
68// clang-format on
69//
70// Changing the function CFG between the construction of the visitor and
71// visiting is undefined. The visitor can be reused, but if the CFG is updated,
72// the visitor must be rebuilt.
73class PartialOrderingVisitor {
74 DomTreeBuilder::BBDomTree DT;
75 LoopInfo LI;
76
77 SmallPtrSet<BasicBlock *, 0> Queued;
78 std::queue<BasicBlock *> ToVisit;
79
80 struct OrderInfo {
81 size_t Rank;
82 size_t TraversalIndex;
83 };
84
85 using BlockToOrderInfoMap = DenseMap<BasicBlock *, OrderInfo>;
86 BlockToOrderInfoMap BlockToOrder;
87 std::vector<BasicBlock *> Order;
88
89 // Get all basic-blocks reachable from Start.
90 SmallPtrSet<BasicBlock *, 0> getReachableFrom(BasicBlock *Start);
91
92 // Internal function used to determine the partial ordering.
93 // Visits |BB| with the current rank being |Rank|.
94 size_t visit(BasicBlock *BB, size_t Rank);
95
96 bool CanBeVisited(BasicBlock *BB) const;
97
98public:
99 size_t GetNodeRank(BasicBlock *BB) const;
100
101 // Build the visitor to operate on the function F.
102 PartialOrderingVisitor(Function &F);
103
104 // Returns the dominator tree computed for the function this visitor
105 // operates on.
106 const DomTreeBuilder::BBDomTree &getDominatorTree() const { return DT; }
107
108 // Returns true is |LHS| comes before |RHS| in the partial ordering.
109 // If |LHS| and |RHS| have the same rank, the traversal order determines the
110 // order (order is stable).
111 bool compare(const BasicBlock *LHS, const BasicBlock *RHS) const;
112
113 // Visit the function starting from the basic block |Start|, and calling |Op|
114 // on each visited BB. This traversal ignores back-edges, meaning this won't
115 // visit a node to which |Start| is not an ancestor.
116 // If Op returns |true|, the visitor continues. If |Op| returns false, the
117 // visitor will stop at that rank. This means if 2 nodes share the same rank,
118 // and Op returns false when visiting the first, the second will be visited
119 // afterwards. But none of their successors will.
120 void partialOrderVisit(BasicBlock &Start,
121 std::function<bool(BasicBlock *)> Op);
122};
123
124namespace SPIRV {
125struct FPFastMathDefaultInfo {
126 const Type *Ty = nullptr;
127 unsigned FastMathFlags = 0;
128 // When SPV_KHR_float_controls2 ContractionOff and SignzeroInfNanPreserve are
129 // deprecated, and we replace them with FPFastMathDefault appropriate flags
130 // instead. However, we have no guarantee about the order in which we will
131 // process execution modes. Therefore it could happen that we first process
132 // ContractionOff, setting AllowContraction bit to 0, and then we process
133 // FPFastMathDefault enabling AllowContraction bit, effectively invalidating
134 // ContractionOff. Because of that, it's best to keep separate bits for the
135 // different execution modes, and we will try and combine them later when we
136 // emit OpExecutionMode instructions.
137 bool ContractionOff = false;
138 bool SignedZeroInfNanPreserve = false;
139 bool FPFastMathDefault = false;
140
141 FPFastMathDefaultInfo() = default;
142 FPFastMathDefaultInfo(const Type *Ty, unsigned FastMathFlags)
143 : Ty(Ty), FastMathFlags(FastMathFlags) {}
144 bool operator==(const FPFastMathDefaultInfo &Other) const {
145 return Ty == Other.Ty && FastMathFlags == Other.FastMathFlags &&
146 ContractionOff == Other.ContractionOff &&
147 SignedZeroInfNanPreserve == Other.SignedZeroInfNanPreserve &&
148 FPFastMathDefault == Other.FPFastMathDefault;
149 }
150};
151
152struct FPFastMathDefaultInfoVector
153 : public SmallVector<SPIRV::FPFastMathDefaultInfo, 3> {
154 static size_t computeFPFastMathDefaultInfoVecIndex(size_t BitWidth) {
155 switch (BitWidth) {
156 case 16: // half
157 return 0;
158 case 32: // float
159 return 1;
160 case 64: // double
161 return 2;
162 default:
163 report_fatal_error(reason: "Expected BitWidth to be 16, 32, 64", gen_crash_diag: false);
164 }
165 llvm_unreachable(
166 "Unreachable code in computeFPFastMathDefaultInfoVecIndex");
167 }
168};
169
170// This code restores function args/retvalue types for composite cases
171// because the final types should still be aggregate whereas they're i32
172// during the translation to cope with aggregate flattening etc.
173FunctionType *getOriginalFunctionType(const Function &F);
174FunctionType *getOriginalFunctionType(const CallBase &CB);
175// This handles retrieving the original ASM constraints, which we had to spoof
176// into having a single output.
177StringRef getOriginalAsmConstraints(const CallBase &CB);
178} // namespace SPIRV
179
180// Add the given string as a series of integer operand, inserting null
181// terminators and padding to make sure the operands all have 32-bit
182// little-endian words.
183void addStringImm(StringRef Str, MCInst &Inst);
184void addStringImm(StringRef Str, MachineInstrBuilder &MIB);
185
186// Read the series of integer operands back as a null-terminated string using
187// the reverse of the logic in addStringImm.
188std::string getStringImm(const MachineInstr &MI, unsigned StartIndex);
189
190// Returns the string constant that the register refers to. It is assumed that
191// Reg is a global value that contains a string.
192std::string getStringValueFromReg(Register Reg, MachineRegisterInfo &MRI);
193
194// Add the given numerical immediate to MIB.
195void addNumImm(const APInt &Imm, MachineInstrBuilder &MIB);
196
197// Add an OpName instruction for the given target register.
198void buildOpName(Register Target, StringRef Name, MachineIRBuilder &MIRBuilder);
199void buildOpName(Register Target, StringRef Name, MachineInstr &I,
200 const SPIRVInstrInfo &TII);
201
202// Add an OpDecorate instruction for the given Reg.
203void buildOpDecorate(Register Reg, MachineIRBuilder &MIRBuilder,
204 SPIRV::Decoration::Decoration Dec,
205 ArrayRef<uint32_t> DecArgs, StringRef StrImm = "");
206void buildOpDecorate(Register Reg, MachineInstr &I, const SPIRVInstrInfo &TII,
207 SPIRV::Decoration::Decoration Dec,
208 ArrayRef<uint32_t> DecArgs, StringRef StrImm = "");
209
210// Add an OpDecorate instruction for the given Reg.
211void buildOpMemberDecorate(Register Reg, MachineIRBuilder &MIRBuilder,
212 SPIRV::Decoration::Decoration Dec, uint32_t Member,
213 ArrayRef<uint32_t> DecArgs, StringRef StrImm = "");
214
215// Add an OpDecorate instruction by "spirv.Decorations" metadata node.
216void buildOpSpirvDecorations(Register Reg, MachineIRBuilder &MIRBuilder,
217 const MDNode *GVarMD, const SPIRVSubtarget &ST);
218
219// Return a valid position for the OpVariable instruction inside a function,
220// i.e., at the beginning of the first block of the function.
221MachineBasicBlock::iterator getOpVariableMBBIt(MachineFunction &MF);
222
223// Return a valid position for the instruction at the end of the block before
224// terminators and debug instructions.
225MachineBasicBlock::iterator getInsertPtValidEnd(MachineBasicBlock *MBB);
226
227// Returns true if a pointer to the storage class can be casted to/from a
228// pointer to the Generic storage class.
229constexpr bool isGenericCastablePtr(SPIRV::StorageClass::StorageClass SC) {
230 switch (SC) {
231 case SPIRV::StorageClass::Workgroup:
232 case SPIRV::StorageClass::CrossWorkgroup:
233 case SPIRV::StorageClass::Function:
234 case SPIRV::StorageClass::CodeSectionINTEL:
235 return true;
236 default:
237 return false;
238 }
239}
240
241// Convert a SPIR-V storage class to the corresponding LLVM IR address space.
242// TODO: maybe the following two functions should be handled in the subtarget
243// to allow for different OpenCL vs Vulkan handling.
244constexpr unsigned
245storageClassToAddressSpace(SPIRV::StorageClass::StorageClass SC) {
246 switch (SC) {
247 case SPIRV::StorageClass::Function:
248 return 0;
249 case SPIRV::StorageClass::CrossWorkgroup:
250 return 1;
251 case SPIRV::StorageClass::UniformConstant:
252 return 2;
253 case SPIRV::StorageClass::Workgroup:
254 return 3;
255 case SPIRV::StorageClass::Generic:
256 return 4;
257 case SPIRV::StorageClass::DeviceOnlyINTEL:
258 return 5;
259 case SPIRV::StorageClass::HostOnlyINTEL:
260 return 6;
261 case SPIRV::StorageClass::Input:
262 return 7;
263 case SPIRV::StorageClass::Output:
264 return 8;
265 case SPIRV::StorageClass::CodeSectionINTEL:
266 return 9;
267 case SPIRV::StorageClass::Private:
268 return 10;
269 case SPIRV::StorageClass::StorageBuffer:
270 return 11;
271 case SPIRV::StorageClass::Uniform:
272 return 12;
273 case SPIRV::StorageClass::PushConstant:
274 return 13;
275 default:
276 report_fatal_error(reason: "Unable to get address space id");
277 }
278}
279
280// Convert an LLVM IR address space to a SPIR-V storage class.
281SPIRV::StorageClass::StorageClass
282addressSpaceToStorageClass(unsigned AddrSpace, const SPIRVSubtarget &STI);
283
284SPIRV::MemorySemantics::MemorySemantics
285getMemSemanticsForStorageClass(SPIRV::StorageClass::StorageClass SC);
286
287SPIRV::MemorySemantics::MemorySemantics getMemSemantics(AtomicOrdering Ord);
288
289uint32_t getMemSemanticsWithStorageClass(const Triple &TT, uint32_t OrderSem,
290 uint32_t StorageClassSem);
291
292SPIRV::Scope::Scope getMemScope(const Triple &TT, LLVMContext &Ctx,
293 SyncScope::ID Id);
294
295// Find def instruction for the given ConstReg, walking through
296// spv_track_constant and ASSIGN_TYPE instructions. Updates ConstReg by def
297// of OpConstant instruction.
298MachineInstr *getDefInstrMaybeConstant(Register &ConstReg,
299 const MachineRegisterInfo *MRI);
300
301// Get constant integer value of the given ConstReg.
302uint64_t getIConstVal(Register ConstReg, const MachineRegisterInfo *MRI);
303
304// Get constant integer value of the given ConstReg, sign-extended.
305int64_t getIConstValSext(Register ConstReg, const MachineRegisterInfo *MRI);
306
307// Check if MI is a SPIR-V specific intrinsic call.
308bool isSpvIntrinsic(const MachineInstr &MI, Intrinsic::ID IntrinsicID);
309// Check if it's a SPIR-V specific intrinsic call.
310bool isSpvIntrinsic(const Value *Arg);
311
312// Get type of i-th operand of the metadata node.
313Type *getMDOperandAsType(const MDNode *N, unsigned I);
314
315// Get the i-th operand of the metadata node as a ConstantInt, or nullptr if it
316// is out of range or not a ConstantInt.
317ConstantInt *getMDOperandAsConstInt(const MDNode *N, unsigned I);
318
319// If OpenCL or SPIR-V builtin function name is recognized, return a demangled
320// name, otherwise return an empty string.
321std::string getOclOrSpirvBuiltinDemangledName(StringRef Name);
322
323// Check if a string contains a builtin prefix.
324bool hasBuiltinTypePrefix(StringRef Name);
325
326// Check if given LLVM type is a special opaque builtin type.
327bool isSpecialOpaqueType(const Type *Ty);
328
329// Check if the function is an SPIR-V entry point
330bool isEntryPoint(const Function &F);
331
332// Parse basic scalar type name, substring TypeName, and return LLVM type.
333Type *parseBasicTypeName(StringRef &TypeName, LLVMContext &Ctx);
334
335// Sort blocks in a partial ordering, so each block is after all its
336// dominators. This should match both the SPIR-V and the MIR requirements.
337// Returns true if the function was changed.
338bool sortBlocks(Function &F);
339
340// Create a stack slot in the entry block of F for a value of the given type.
341AllocaInst *createVariable(Function &F, Type *Type);
342
343// Create a value in BB set to the value associated with the branch the block
344// terminator will take.
345Value *
346createExitVariable(BasicBlock *BB,
347 const DenseMap<BasicBlock *, ConstantInt *> &TargetToValue);
348
349// Check for peeled array structs and recursively reconstitute them. In HLSL
350// CBuffers, arrays may have padding between the elements, but not after the
351// last element. To represent this in LLVM IR an array [N x T] will be
352// represented as {[N-1 x {T, spirv.Padding}], T}. The function
353// matchPeeledArrayPattern recognizes this pattern retrieving the type {T,
354// spirv.Padding}, and the size N.
355bool matchPeeledArrayPattern(const StructType *Ty, Type *&OriginalElementType,
356 uint64_t &TotalSize);
357
358// This function will turn the type {[N-1 x {T, spirv.Padding}], T} back into
359// [N x {T, spirv.Padding}]. So it can be translated into SPIR-V. The offset
360// decorations will be such that there will be no padding after the array when
361// relevant.
362Type *reconstitutePeeledArrayType(Type *Ty);
363
364inline bool hasInitializer(const GlobalVariable *GV) {
365 if (!GV->hasInitializer())
366 return false;
367 if (const auto *Init = GV->getInitializer(); isa<UndefValue>(Val: Init))
368 return GV->isConstant() && Init->getType()->isAggregateType();
369 return true;
370}
371
372// True if this is an instance of TypedPointerType.
373inline bool isTypedPointerTy(const Type *T) {
374 return T && T->getTypeID() == Type::TypedPointerTyID;
375}
376
377// True if this is an instance of PointerType.
378inline bool isUntypedPointerTy(const Type *T) {
379 return T && T->getTypeID() == Type::PointerTyID;
380}
381
382// True if this is an instance of PointerType or TypedPointerType.
383inline bool isPointerTy(const Type *T) {
384 return isUntypedPointerTy(T) || isTypedPointerTy(T);
385}
386
387// True if this is a vector whose element type is an (untyped) PointerType.
388inline bool isUntypedPointerVectorTy(const Type *T) {
389 return isa_and_nonnull<VectorType>(Val: T) &&
390 isUntypedPointerTy(T: T->getScalarType());
391}
392
393// Get the address space of this pointer or pointer vector type for instances of
394// PointerType or TypedPointerType.
395inline unsigned getPointerAddressSpace(const Type *T) {
396 Type *SubT = T->getScalarType();
397 return SubT->getTypeID() == Type::PointerTyID
398 ? cast<PointerType>(Val: SubT)->getAddressSpace()
399 : cast<TypedPointerType>(Val: SubT)->getAddressSpace();
400}
401
402// Return true if the Argument is decorated with a pointee type
403inline bool hasPointeeTypeAttr(Argument *Arg) {
404 return Arg->hasByValAttr() || Arg->hasByRefAttr() || Arg->hasStructRetAttr();
405}
406
407// Return the pointee type of the argument or nullptr otherwise
408inline Type *getPointeeTypeByAttr(Argument *Arg) {
409 if (Arg->hasByValAttr())
410 return Arg->getParamByValType();
411 if (Arg->hasStructRetAttr())
412 return Arg->getParamStructRetType();
413 if (Arg->hasByRefAttr())
414 return Arg->getParamByRefType();
415 return nullptr;
416}
417
418#define TYPED_PTR_TARGET_EXT_NAME "spirv.$TypedPointerType"
419inline Type *getTypedPointerWrapper(Type *ElemTy, unsigned AS) {
420 return TargetExtType::get(Context&: ElemTy->getContext(), TYPED_PTR_TARGET_EXT_NAME,
421 Types: {ElemTy}, Ints: {AS});
422}
423
424inline bool isTypedPointerWrapper(const TargetExtType *ExtTy) {
425 return ExtTy->getName() == TYPED_PTR_TARGET_EXT_NAME &&
426 ExtTy->getNumIntParameters() == 1 &&
427 ExtTy->getNumTypeParameters() == 1;
428}
429
430// True if this is an instance of PointerType or TypedPointerType.
431inline bool isPointerTyOrWrapper(const Type *Ty) {
432 if (auto *ExtTy = dyn_cast<TargetExtType>(Val: Ty))
433 return isTypedPointerWrapper(ExtTy);
434 return isPointerTy(T: Ty);
435}
436
437inline Type *applyWrappers(Type *Ty) {
438 if (auto *ExtTy = dyn_cast<TargetExtType>(Val: Ty)) {
439 if (isTypedPointerWrapper(ExtTy))
440 return TypedPointerType::get(ElementType: applyWrappers(Ty: ExtTy->getTypeParameter(i: 0)),
441 AddressSpace: ExtTy->getIntParameter(i: 0));
442 } else if (auto *VecTy = dyn_cast<VectorType>(Val: Ty)) {
443 Type *ElemTy = VecTy->getElementType();
444 Type *NewElemTy = ElemTy->isTargetExtTy() ? applyWrappers(Ty: ElemTy) : ElemTy;
445 if (NewElemTy != ElemTy)
446 return VectorType::get(ElementType: NewElemTy, EC: VecTy->getElementCount());
447 }
448 return Ty;
449}
450
451inline Type *getPointeeType(const Type *Ty) {
452 if (Ty) {
453 if (auto PType = dyn_cast<TypedPointerType>(Val: Ty))
454 return PType->getElementType();
455 else if (auto *ExtTy = dyn_cast<TargetExtType>(Val: Ty))
456 if (isTypedPointerWrapper(ExtTy))
457 return ExtTy->getTypeParameter(i: 0);
458 }
459 return nullptr;
460}
461
462inline bool isUntypedEquivalentToTyExt(Type *Ty1, Type *Ty2) {
463 if (!isUntypedPointerTy(T: Ty1) || !Ty2)
464 return false;
465 if (auto *ExtTy = dyn_cast<TargetExtType>(Val: Ty2))
466 if (isTypedPointerWrapper(ExtTy) &&
467 ExtTy->getTypeParameter(i: 0) ==
468 IntegerType::getInt8Ty(C&: Ty1->getContext()) &&
469 ExtTy->getIntParameter(i: 0) == cast<PointerType>(Val: Ty1)->getAddressSpace())
470 return true;
471 return false;
472}
473
474inline bool isEquivalentTypes(Type *Ty1, Type *Ty2) {
475 return isUntypedEquivalentToTyExt(Ty1, Ty2) ||
476 isUntypedEquivalentToTyExt(Ty1: Ty2, Ty2: Ty1);
477}
478
479inline Type *toTypedPointer(Type *Ty) {
480 if (Type *NewTy = applyWrappers(Ty); NewTy != Ty)
481 return NewTy;
482 return isUntypedPointerTy(T: Ty)
483 ? TypedPointerType::get(ElementType: IntegerType::getInt8Ty(C&: Ty->getContext()),
484 AddressSpace: getPointerAddressSpace(T: Ty))
485 : Ty;
486}
487
488inline Type *toTypedFunPointer(FunctionType *FTy) {
489 Type *OrigRetTy = FTy->getReturnType();
490 Type *RetTy = toTypedPointer(Ty: OrigRetTy);
491 bool IsUntypedPtr = false;
492 for (Type *PTy : FTy->params()) {
493 if (isUntypedPointerTy(T: PTy)) {
494 IsUntypedPtr = true;
495 break;
496 }
497 }
498 if (!IsUntypedPtr && RetTy == OrigRetTy)
499 return FTy;
500 SmallVector<Type *> ParamTys;
501 for (Type *PTy : FTy->params())
502 ParamTys.push_back(Elt: toTypedPointer(Ty: PTy));
503 return FunctionType::get(Result: RetTy, Params: ParamTys, isVarArg: FTy->isVarArg());
504}
505
506inline const Type *unifyPtrType(const Type *Ty) {
507 if (auto FTy = dyn_cast<FunctionType>(Val: Ty))
508 return toTypedFunPointer(FTy: const_cast<FunctionType *>(FTy));
509 return toTypedPointer(Ty: const_cast<Type *>(Ty));
510}
511
512inline bool isVector1(Type *Ty) {
513 auto *FVTy = dyn_cast<FixedVectorType>(Val: Ty);
514 return FVTy && FVTy->getNumElements() == 1;
515}
516
517// We define this predicate out of line to avoid having to include all OpTypes.
518bool isVectorType(SPIRVTypeInst SPVTy);
519
520inline bool isLongVectorEXT(const Type *Ty) {
521 if (auto *FVTy = dyn_cast<FixedVectorType>(Val: Ty)) {
522 unsigned N = FVTy->getNumElements();
523 // Per specification: `Vector types must be parameterized only with 2, 3, or
524 // 4 components, plus any additional sizes enabled by capabilities.`, and we
525 // always enable the Vector16 capability.
526 return N != 2 && N != 3 && N != 4 && N != 8 && N != 16;
527 }
528 return false;
529}
530
531// Modify an LLVM type to conform with future transformations in IRTranslator.
532// At the moment use cases comprise only a <1 x Type> vector. To extend when/if
533// needed.
534inline Type *normalizeType(Type *Ty, bool CanUseAnyVectorRank) {
535 if (CanUseAnyVectorRank)
536 return Ty;
537
538 auto *FVTy = dyn_cast<FixedVectorType>(Val: Ty);
539 if (!FVTy || FVTy->getNumElements() != 1)
540 return Ty;
541 // If it's a <1 x Type> vector type, replace it by the element type, because
542 // it's not a legal vector type in LLT and IRTranslator will represent it as
543 // the scalar eventually.
544 return normalizeType(Ty: FVTy->getElementType(), CanUseAnyVectorRank);
545}
546
547inline PoisonValue *getNormalizedPoisonValue(Type *Ty,
548 bool CanUseAnyVectorRank) {
549 return PoisonValue::get(T: normalizeType(Ty, CanUseAnyVectorRank));
550}
551
552inline MetadataAsValue *buildMD(Value *Arg) {
553 LLVMContext &Ctx = Arg->getContext();
554 return MetadataAsValue::get(
555 Context&: Ctx, MD: MDNode::get(Context&: Ctx, MDs: ValueAsMetadata::getConstant(C: Arg)));
556}
557
558CallInst *buildIntrWithMD(Intrinsic::ID IntrID, ArrayRef<Type *> Types,
559 Value *Arg, Value *Arg2, ArrayRef<Constant *> Imms,
560 IRBuilder<> &B);
561
562MachineInstr *getVRegDef(MachineRegisterInfo &MRI, Register Reg);
563
564#define SPIRV_BACKEND_SERVICE_FUN_NAME "__spirv_backend_service_fun"
565#define SPIRV_WAS_AVAILABLE_EXTERNALLY_ATTR "spv.was-available-externally"
566
567void setRegClassType(Register Reg, const Type *Ty, SPIRVGlobalRegistry *GR,
568 MachineIRBuilder &MIRBuilder,
569 SPIRV::AccessQualifier::AccessQualifier AccessQual,
570 bool EmitIR, bool Force = false);
571void setRegClassType(Register Reg, SPIRVTypeInst SpvType,
572 SPIRVGlobalRegistry *GR, MachineRegisterInfo *MRI,
573 const MachineFunction &MF, bool Force = false);
574Register createVirtualRegister(SPIRVTypeInst SpvType, SPIRVGlobalRegistry *GR,
575 MachineRegisterInfo *MRI,
576 const MachineFunction &MF);
577Register createVirtualRegister(SPIRVTypeInst SpvType, SPIRVGlobalRegistry *GR,
578 MachineIRBuilder &MIRBuilder);
579Register createVirtualRegister(
580 const Type *Ty, SPIRVGlobalRegistry *GR, MachineIRBuilder &MIRBuilder,
581 SPIRV::AccessQualifier::AccessQualifier AccessQual, bool EmitIR);
582
583// Return true if there is an opaque pointer type nested in the argument.
584bool isNestedPointer(const Type *Ty);
585
586enum FPDecorationId { NONE, RTE, RTZ, RTP, RTN, SAT };
587
588inline FPDecorationId demangledPostfixToDecorationId(const std::string &S) {
589 static const StringMap<FPDecorationId> Mapping = {
590 {"rte", FPDecorationId::RTE},
591 {"rtz", FPDecorationId::RTZ},
592 {"rtp", FPDecorationId::RTP},
593 {"rtn", FPDecorationId::RTN},
594 {"sat", FPDecorationId::SAT}};
595 auto It = Mapping.find(Key: S);
596 return It == Mapping.end() ? FPDecorationId::NONE : It->second;
597}
598
599SmallVector<MachineInstr *, 4>
600createContinuedInstructions(MachineIRBuilder &MIRBuilder, unsigned Opcode,
601 unsigned MinWC, unsigned ContinuedOpcode,
602 ArrayRef<Register> Args, Register ReturnRegister,
603 Register TypeID);
604
605// Instruction selection directed by type folding.
606const std::set<unsigned> &getTypeFoldingSupportedOpcodes();
607bool isTypeFoldingSupported(unsigned Opcode);
608
609// Get loop controls from llvm.loop. metadata.
610SmallVector<unsigned, 1> getSpirvLoopControlOperandsFromLoopMetadata(Loop *L);
611SmallVector<unsigned, 1>
612getSpirvLoopControlOperandsFromLoopMetadata(MDNode *LoopMD);
613
614// Traversing [g]MIR accounting for pseudo-instructions.
615MachineInstr *passCopy(MachineInstr *Def, const MachineRegisterInfo *MRI);
616MachineInstr *getDef(const MachineOperand &MO, const MachineRegisterInfo *MRI);
617MachineInstr *getImm(const MachineOperand &MO, const MachineRegisterInfo *MRI);
618int64_t foldImm(const MachineOperand &MO, const MachineRegisterInfo *MRI);
619unsigned getArrayComponentCount(const MachineRegisterInfo *MRI,
620 const MachineInstr *ResType);
621
622std::optional<SPIRV::LinkageType::LinkageType>
623getSpirvLinkageTypeFor(const SPIRVSubtarget &ST, const GlobalValue &GV);
624Function *getOrCreateBackendServiceFunction(Module &M);
625} // namespace llvm
626#endif // LLVM_LIB_TARGET_SPIRV_SPIRVUTILS_H
627