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/IR/IRBuilder.h"
18 #include "llvm/IR/TypedPointerType.h"
19 #include <string>
20
21 namespace llvm {
22 class MCInst;
23 class MachineFunction;
24 class MachineInstr;
25 class MachineInstrBuilder;
26 class MachineIRBuilder;
27 class MachineRegisterInfo;
28 class Register;
29 class StringRef;
30 class SPIRVInstrInfo;
31 class SPIRVSubtarget;
32
33 // Add the given string as a series of integer operand, inserting null
34 // terminators and padding to make sure the operands all have 32-bit
35 // little-endian words.
36 void addStringImm(const StringRef &Str, MCInst &Inst);
37 void addStringImm(const StringRef &Str, MachineInstrBuilder &MIB);
38 void addStringImm(const StringRef &Str, IRBuilder<> &B,
39 std::vector<Value *> &Args);
40
41 // Read the series of integer operands back as a null-terminated string using
42 // the reverse of the logic in addStringImm.
43 std::string getStringImm(const MachineInstr &MI, unsigned StartIndex);
44
45 // Add the given numerical immediate to MIB.
46 void addNumImm(const APInt &Imm, MachineInstrBuilder &MIB);
47
48 // Add an OpName instruction for the given target register.
49 void buildOpName(Register Target, const StringRef &Name,
50 MachineIRBuilder &MIRBuilder);
51
52 // Add an OpDecorate instruction for the given Reg.
53 void buildOpDecorate(Register Reg, MachineIRBuilder &MIRBuilder,
54 SPIRV::Decoration::Decoration Dec,
55 const std::vector<uint32_t> &DecArgs,
56 StringRef StrImm = "");
57 void buildOpDecorate(Register Reg, MachineInstr &I, const SPIRVInstrInfo &TII,
58 SPIRV::Decoration::Decoration Dec,
59 const std::vector<uint32_t> &DecArgs,
60 StringRef StrImm = "");
61
62 // Add an OpDecorate instruction by "spirv.Decorations" metadata node.
63 void buildOpSpirvDecorations(Register Reg, MachineIRBuilder &MIRBuilder,
64 const MDNode *GVarMD);
65
66 // Convert a SPIR-V storage class to the corresponding LLVM IR address space.
67 unsigned storageClassToAddressSpace(SPIRV::StorageClass::StorageClass SC);
68
69 // Convert an LLVM IR address space to a SPIR-V storage class.
70 SPIRV::StorageClass::StorageClass
71 addressSpaceToStorageClass(unsigned AddrSpace, const SPIRVSubtarget &STI);
72
73 SPIRV::MemorySemantics::MemorySemantics
74 getMemSemanticsForStorageClass(SPIRV::StorageClass::StorageClass SC);
75
76 SPIRV::MemorySemantics::MemorySemantics getMemSemantics(AtomicOrdering Ord);
77
78 // Find def instruction for the given ConstReg, walking through
79 // spv_track_constant and ASSIGN_TYPE instructions. Updates ConstReg by def
80 // of OpConstant instruction.
81 MachineInstr *getDefInstrMaybeConstant(Register &ConstReg,
82 const MachineRegisterInfo *MRI);
83
84 // Get constant integer value of the given ConstReg.
85 uint64_t getIConstVal(Register ConstReg, const MachineRegisterInfo *MRI);
86
87 // Check if MI is a SPIR-V specific intrinsic call.
88 bool isSpvIntrinsic(const MachineInstr &MI, Intrinsic::ID IntrinsicID);
89
90 // Get type of i-th operand of the metadata node.
91 Type *getMDOperandAsType(const MDNode *N, unsigned I);
92
93 // If OpenCL or SPIR-V builtin function name is recognized, return a demangled
94 // name, otherwise return an empty string.
95 std::string getOclOrSpirvBuiltinDemangledName(StringRef Name);
96
97 // Check if a string contains a builtin prefix.
98 bool hasBuiltinTypePrefix(StringRef Name);
99
100 // Check if given LLVM type is a special opaque builtin type.
101 bool isSpecialOpaqueType(const Type *Ty);
102
103 // Check if the function is an SPIR-V entry point
104 bool isEntryPoint(const Function &F);
105
106 // Parse basic scalar type name, substring TypeName, and return LLVM type.
107 Type *parseBasicTypeName(StringRef &TypeName, LLVMContext &Ctx);
108
109 // True if this is an instance of TypedPointerType.
isTypedPointerTy(const Type * T)110 inline bool isTypedPointerTy(const Type *T) {
111 return T && T->getTypeID() == Type::TypedPointerTyID;
112 }
113
114 // True if this is an instance of PointerType.
isUntypedPointerTy(const Type * T)115 inline bool isUntypedPointerTy(const Type *T) {
116 return T && T->getTypeID() == Type::PointerTyID;
117 }
118
119 // True if this is an instance of PointerType or TypedPointerType.
isPointerTy(const Type * T)120 inline bool isPointerTy(const Type *T) {
121 return isUntypedPointerTy(T) || isTypedPointerTy(T);
122 }
123
124 // Get the address space of this pointer or pointer vector type for instances of
125 // PointerType or TypedPointerType.
getPointerAddressSpace(const Type * T)126 inline unsigned getPointerAddressSpace(const Type *T) {
127 Type *SubT = T->getScalarType();
128 return SubT->getTypeID() == Type::PointerTyID
129 ? cast<PointerType>(SubT)->getAddressSpace()
130 : cast<TypedPointerType>(SubT)->getAddressSpace();
131 }
132
133 // Return true if the Argument is decorated with a pointee type
hasPointeeTypeAttr(Argument * Arg)134 inline bool hasPointeeTypeAttr(Argument *Arg) {
135 return Arg->hasByValAttr() || Arg->hasByRefAttr() || Arg->hasStructRetAttr();
136 }
137
138 // Return the pointee type of the argument or nullptr otherwise
getPointeeTypeByAttr(Argument * Arg)139 inline Type *getPointeeTypeByAttr(Argument *Arg) {
140 if (Arg->hasByValAttr())
141 return Arg->getParamByValType();
142 if (Arg->hasStructRetAttr())
143 return Arg->getParamStructRetType();
144 if (Arg->hasByRefAttr())
145 return Arg->getParamByRefType();
146 return nullptr;
147 }
148
reconstructFunctionType(Function * F)149 inline Type *reconstructFunctionType(Function *F) {
150 SmallVector<Type *> ArgTys;
151 for (unsigned i = 0; i < F->arg_size(); ++i)
152 ArgTys.push_back(F->getArg(i)->getType());
153 return FunctionType::get(F->getReturnType(), ArgTys, F->isVarArg());
154 }
155
156 #define TYPED_PTR_TARGET_EXT_NAME "spirv.$TypedPointerType"
getTypedPointerWrapper(Type * ElemTy,unsigned AS)157 inline Type *getTypedPointerWrapper(Type *ElemTy, unsigned AS) {
158 return TargetExtType::get(ElemTy->getContext(), TYPED_PTR_TARGET_EXT_NAME,
159 {ElemTy}, {AS});
160 }
161
isTypedPointerWrapper(TargetExtType * ExtTy)162 inline bool isTypedPointerWrapper(TargetExtType *ExtTy) {
163 return ExtTy->getName() == TYPED_PTR_TARGET_EXT_NAME &&
164 ExtTy->getNumIntParameters() == 1 &&
165 ExtTy->getNumTypeParameters() == 1;
166 }
167
applyWrappers(Type * Ty)168 inline Type *applyWrappers(Type *Ty) {
169 if (auto *ExtTy = dyn_cast<TargetExtType>(Ty)) {
170 if (isTypedPointerWrapper(ExtTy))
171 return TypedPointerType::get(applyWrappers(ExtTy->getTypeParameter(0)),
172 ExtTy->getIntParameter(0));
173 } else if (auto *VecTy = dyn_cast<VectorType>(Ty)) {
174 Type *ElemTy = VecTy->getElementType();
175 Type *NewElemTy = ElemTy->isTargetExtTy() ? applyWrappers(ElemTy) : ElemTy;
176 if (NewElemTy != ElemTy)
177 return VectorType::get(NewElemTy, VecTy->getElementCount());
178 }
179 return Ty;
180 }
181
getPointeeType(Type * Ty)182 inline Type *getPointeeType(Type *Ty) {
183 if (auto PType = dyn_cast<TypedPointerType>(Ty))
184 return PType->getElementType();
185 else if (auto *ExtTy = dyn_cast<TargetExtType>(Ty))
186 if (isTypedPointerWrapper(ExtTy))
187 return applyWrappers(ExtTy->getTypeParameter(0));
188 return nullptr;
189 }
190
isUntypedEquivalentToTyExt(Type * Ty1,Type * Ty2)191 inline bool isUntypedEquivalentToTyExt(Type *Ty1, Type *Ty2) {
192 if (!isUntypedPointerTy(Ty1) || !Ty2)
193 return false;
194 if (auto *ExtTy = dyn_cast<TargetExtType>(Ty2))
195 if (isTypedPointerWrapper(ExtTy) &&
196 ExtTy->getTypeParameter(0) ==
197 IntegerType::getInt8Ty(Ty1->getContext()) &&
198 ExtTy->getIntParameter(0) == cast<PointerType>(Ty1)->getAddressSpace())
199 return true;
200 return false;
201 }
202
isEquivalentTypes(Type * Ty1,Type * Ty2)203 inline bool isEquivalentTypes(Type *Ty1, Type *Ty2) {
204 return isUntypedEquivalentToTyExt(Ty1, Ty2) ||
205 isUntypedEquivalentToTyExt(Ty2, Ty1);
206 }
207
toTypedPointer(Type * Ty)208 inline Type *toTypedPointer(Type *Ty) {
209 if (Type *NewTy = applyWrappers(Ty); NewTy != Ty)
210 return NewTy;
211 return isUntypedPointerTy(Ty)
212 ? TypedPointerType::get(IntegerType::getInt8Ty(Ty->getContext()),
213 getPointerAddressSpace(Ty))
214 : Ty;
215 }
216
toTypedFunPointer(FunctionType * FTy)217 inline Type *toTypedFunPointer(FunctionType *FTy) {
218 Type *OrigRetTy = FTy->getReturnType();
219 Type *RetTy = toTypedPointer(OrigRetTy);
220 bool IsUntypedPtr = false;
221 for (Type *PTy : FTy->params()) {
222 if (isUntypedPointerTy(PTy)) {
223 IsUntypedPtr = true;
224 break;
225 }
226 }
227 if (!IsUntypedPtr && RetTy == OrigRetTy)
228 return FTy;
229 SmallVector<Type *> ParamTys;
230 for (Type *PTy : FTy->params())
231 ParamTys.push_back(toTypedPointer(PTy));
232 return FunctionType::get(RetTy, ParamTys, FTy->isVarArg());
233 }
234
unifyPtrType(const Type * Ty)235 inline const Type *unifyPtrType(const Type *Ty) {
236 if (auto FTy = dyn_cast<FunctionType>(Ty))
237 return toTypedFunPointer(const_cast<FunctionType *>(FTy));
238 return toTypedPointer(const_cast<Type *>(Ty));
239 }
240
241 } // namespace llvm
242 #endif // LLVM_LIB_TARGET_SPIRV_SPIRVUTILS_H
243