xref: /freebsd/contrib/llvm-project/llvm/lib/Target/SPIRV/SPIRVUtils.h (revision 0fca6ea1d4eea4c934cfff25ac9ee8ad6fe95583)
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