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