xref: /freebsd-src/contrib/llvm-project/llvm/lib/Target/SPIRV/SPIRVUtils.h (revision 0fca6ea1d4eea4c934cfff25ac9ee8ad6fe95583)
181ad6265SDimitry Andric //===--- SPIRVUtils.h ---- SPIR-V Utility Functions -------------*- C++ -*-===//
281ad6265SDimitry Andric //
381ad6265SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
481ad6265SDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
581ad6265SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
681ad6265SDimitry Andric //
781ad6265SDimitry Andric //===----------------------------------------------------------------------===//
881ad6265SDimitry Andric //
981ad6265SDimitry Andric // This file contains miscellaneous utility functions.
1081ad6265SDimitry Andric //
1181ad6265SDimitry Andric //===----------------------------------------------------------------------===//
1281ad6265SDimitry Andric 
1381ad6265SDimitry Andric #ifndef LLVM_LIB_TARGET_SPIRV_SPIRVUTILS_H
1481ad6265SDimitry Andric #define LLVM_LIB_TARGET_SPIRV_SPIRVUTILS_H
1581ad6265SDimitry Andric 
1681ad6265SDimitry Andric #include "MCTargetDesc/SPIRVBaseInfo.h"
1781ad6265SDimitry Andric #include "llvm/IR/IRBuilder.h"
18*0fca6ea1SDimitry Andric #include "llvm/IR/TypedPointerType.h"
1981ad6265SDimitry Andric #include <string>
2081ad6265SDimitry Andric 
2181ad6265SDimitry Andric namespace llvm {
2281ad6265SDimitry Andric class MCInst;
2381ad6265SDimitry Andric class MachineFunction;
2481ad6265SDimitry Andric class MachineInstr;
2581ad6265SDimitry Andric class MachineInstrBuilder;
2681ad6265SDimitry Andric class MachineIRBuilder;
2781ad6265SDimitry Andric class MachineRegisterInfo;
2881ad6265SDimitry Andric class Register;
2981ad6265SDimitry Andric class StringRef;
3081ad6265SDimitry Andric class SPIRVInstrInfo;
31*0fca6ea1SDimitry Andric class SPIRVSubtarget;
3281ad6265SDimitry Andric 
3381ad6265SDimitry Andric // Add the given string as a series of integer operand, inserting null
3481ad6265SDimitry Andric // terminators and padding to make sure the operands all have 32-bit
3581ad6265SDimitry Andric // little-endian words.
36bdd1243dSDimitry Andric void addStringImm(const StringRef &Str, MCInst &Inst);
37bdd1243dSDimitry Andric void addStringImm(const StringRef &Str, MachineInstrBuilder &MIB);
38bdd1243dSDimitry Andric void addStringImm(const StringRef &Str, IRBuilder<> &B,
39bdd1243dSDimitry Andric                   std::vector<Value *> &Args);
4081ad6265SDimitry Andric 
4181ad6265SDimitry Andric // Read the series of integer operands back as a null-terminated string using
4281ad6265SDimitry Andric // the reverse of the logic in addStringImm.
43bdd1243dSDimitry Andric std::string getStringImm(const MachineInstr &MI, unsigned StartIndex);
4481ad6265SDimitry Andric 
4581ad6265SDimitry Andric // Add the given numerical immediate to MIB.
46bdd1243dSDimitry Andric void addNumImm(const APInt &Imm, MachineInstrBuilder &MIB);
4781ad6265SDimitry Andric 
4881ad6265SDimitry Andric // Add an OpName instruction for the given target register.
49bdd1243dSDimitry Andric void buildOpName(Register Target, const StringRef &Name,
50bdd1243dSDimitry Andric                  MachineIRBuilder &MIRBuilder);
5181ad6265SDimitry Andric 
5281ad6265SDimitry Andric // Add an OpDecorate instruction for the given Reg.
53bdd1243dSDimitry Andric void buildOpDecorate(Register Reg, MachineIRBuilder &MIRBuilder,
54bdd1243dSDimitry Andric                      SPIRV::Decoration::Decoration Dec,
5581ad6265SDimitry Andric                      const std::vector<uint32_t> &DecArgs,
56bdd1243dSDimitry Andric                      StringRef StrImm = "");
57bdd1243dSDimitry Andric void buildOpDecorate(Register Reg, MachineInstr &I, const SPIRVInstrInfo &TII,
58bdd1243dSDimitry Andric                      SPIRV::Decoration::Decoration Dec,
5981ad6265SDimitry Andric                      const std::vector<uint32_t> &DecArgs,
60bdd1243dSDimitry Andric                      StringRef StrImm = "");
6181ad6265SDimitry Andric 
62*0fca6ea1SDimitry Andric // Add an OpDecorate instruction by "spirv.Decorations" metadata node.
63*0fca6ea1SDimitry Andric void buildOpSpirvDecorations(Register Reg, MachineIRBuilder &MIRBuilder,
64*0fca6ea1SDimitry Andric                              const MDNode *GVarMD);
65*0fca6ea1SDimitry Andric 
6681ad6265SDimitry Andric // Convert a SPIR-V storage class to the corresponding LLVM IR address space.
67bdd1243dSDimitry Andric unsigned storageClassToAddressSpace(SPIRV::StorageClass::StorageClass SC);
6881ad6265SDimitry Andric 
6981ad6265SDimitry Andric // Convert an LLVM IR address space to a SPIR-V storage class.
70bdd1243dSDimitry Andric SPIRV::StorageClass::StorageClass
71*0fca6ea1SDimitry Andric addressSpaceToStorageClass(unsigned AddrSpace, const SPIRVSubtarget &STI);
7281ad6265SDimitry Andric 
73bdd1243dSDimitry Andric SPIRV::MemorySemantics::MemorySemantics
74bdd1243dSDimitry Andric getMemSemanticsForStorageClass(SPIRV::StorageClass::StorageClass SC);
7581ad6265SDimitry Andric 
76bdd1243dSDimitry Andric SPIRV::MemorySemantics::MemorySemantics getMemSemantics(AtomicOrdering Ord);
77fcaf7f86SDimitry Andric 
7881ad6265SDimitry Andric // Find def instruction for the given ConstReg, walking through
7981ad6265SDimitry Andric // spv_track_constant and ASSIGN_TYPE instructions. Updates ConstReg by def
8081ad6265SDimitry Andric // of OpConstant instruction.
81bdd1243dSDimitry Andric MachineInstr *getDefInstrMaybeConstant(Register &ConstReg,
82bdd1243dSDimitry Andric                                        const MachineRegisterInfo *MRI);
8381ad6265SDimitry Andric 
8481ad6265SDimitry Andric // Get constant integer value of the given ConstReg.
85bdd1243dSDimitry Andric uint64_t getIConstVal(Register ConstReg, const MachineRegisterInfo *MRI);
8681ad6265SDimitry Andric 
87fcaf7f86SDimitry Andric // Check if MI is a SPIR-V specific intrinsic call.
881db9f3b2SDimitry Andric bool isSpvIntrinsic(const MachineInstr &MI, Intrinsic::ID IntrinsicID);
89fcaf7f86SDimitry Andric 
9081ad6265SDimitry Andric // Get type of i-th operand of the metadata node.
91bdd1243dSDimitry Andric Type *getMDOperandAsType(const MDNode *N, unsigned I);
92bdd1243dSDimitry Andric 
93bdd1243dSDimitry Andric // If OpenCL or SPIR-V builtin function name is recognized, return a demangled
94bdd1243dSDimitry Andric // name, otherwise return an empty string.
95bdd1243dSDimitry Andric std::string getOclOrSpirvBuiltinDemangledName(StringRef Name);
96bdd1243dSDimitry Andric 
975f757f3fSDimitry Andric // Check if a string contains a builtin prefix.
985f757f3fSDimitry Andric bool hasBuiltinTypePrefix(StringRef Name);
995f757f3fSDimitry Andric 
100bdd1243dSDimitry Andric // Check if given LLVM type is a special opaque builtin type.
101bdd1243dSDimitry Andric bool isSpecialOpaqueType(const Type *Ty);
102*0fca6ea1SDimitry Andric 
103*0fca6ea1SDimitry Andric // Check if the function is an SPIR-V entry point
104*0fca6ea1SDimitry Andric bool isEntryPoint(const Function &F);
105*0fca6ea1SDimitry Andric 
106*0fca6ea1SDimitry Andric // Parse basic scalar type name, substring TypeName, and return LLVM type.
107*0fca6ea1SDimitry Andric Type *parseBasicTypeName(StringRef &TypeName, LLVMContext &Ctx);
108*0fca6ea1SDimitry Andric 
109*0fca6ea1SDimitry Andric // True if this is an instance of TypedPointerType.
110*0fca6ea1SDimitry Andric inline bool isTypedPointerTy(const Type *T) {
111*0fca6ea1SDimitry Andric   return T && T->getTypeID() == Type::TypedPointerTyID;
112*0fca6ea1SDimitry Andric }
113*0fca6ea1SDimitry Andric 
114*0fca6ea1SDimitry Andric // True if this is an instance of PointerType.
115*0fca6ea1SDimitry Andric inline bool isUntypedPointerTy(const Type *T) {
116*0fca6ea1SDimitry Andric   return T && T->getTypeID() == Type::PointerTyID;
117*0fca6ea1SDimitry Andric }
118*0fca6ea1SDimitry Andric 
119*0fca6ea1SDimitry Andric // True if this is an instance of PointerType or TypedPointerType.
120*0fca6ea1SDimitry Andric inline bool isPointerTy(const Type *T) {
121*0fca6ea1SDimitry Andric   return isUntypedPointerTy(T) || isTypedPointerTy(T);
122*0fca6ea1SDimitry Andric }
123*0fca6ea1SDimitry Andric 
124*0fca6ea1SDimitry Andric // Get the address space of this pointer or pointer vector type for instances of
125*0fca6ea1SDimitry Andric // PointerType or TypedPointerType.
126*0fca6ea1SDimitry Andric inline unsigned getPointerAddressSpace(const Type *T) {
127*0fca6ea1SDimitry Andric   Type *SubT = T->getScalarType();
128*0fca6ea1SDimitry Andric   return SubT->getTypeID() == Type::PointerTyID
129*0fca6ea1SDimitry Andric              ? cast<PointerType>(SubT)->getAddressSpace()
130*0fca6ea1SDimitry Andric              : cast<TypedPointerType>(SubT)->getAddressSpace();
131*0fca6ea1SDimitry Andric }
132*0fca6ea1SDimitry Andric 
133*0fca6ea1SDimitry Andric // Return true if the Argument is decorated with a pointee type
134*0fca6ea1SDimitry Andric inline bool hasPointeeTypeAttr(Argument *Arg) {
135*0fca6ea1SDimitry Andric   return Arg->hasByValAttr() || Arg->hasByRefAttr() || Arg->hasStructRetAttr();
136*0fca6ea1SDimitry Andric }
137*0fca6ea1SDimitry Andric 
138*0fca6ea1SDimitry Andric // Return the pointee type of the argument or nullptr otherwise
139*0fca6ea1SDimitry Andric inline Type *getPointeeTypeByAttr(Argument *Arg) {
140*0fca6ea1SDimitry Andric   if (Arg->hasByValAttr())
141*0fca6ea1SDimitry Andric     return Arg->getParamByValType();
142*0fca6ea1SDimitry Andric   if (Arg->hasStructRetAttr())
143*0fca6ea1SDimitry Andric     return Arg->getParamStructRetType();
144*0fca6ea1SDimitry Andric   if (Arg->hasByRefAttr())
145*0fca6ea1SDimitry Andric     return Arg->getParamByRefType();
146*0fca6ea1SDimitry Andric   return nullptr;
147*0fca6ea1SDimitry Andric }
148*0fca6ea1SDimitry Andric 
149*0fca6ea1SDimitry Andric inline Type *reconstructFunctionType(Function *F) {
150*0fca6ea1SDimitry Andric   SmallVector<Type *> ArgTys;
151*0fca6ea1SDimitry Andric   for (unsigned i = 0; i < F->arg_size(); ++i)
152*0fca6ea1SDimitry Andric     ArgTys.push_back(F->getArg(i)->getType());
153*0fca6ea1SDimitry Andric   return FunctionType::get(F->getReturnType(), ArgTys, F->isVarArg());
154*0fca6ea1SDimitry Andric }
155*0fca6ea1SDimitry Andric 
156*0fca6ea1SDimitry Andric #define TYPED_PTR_TARGET_EXT_NAME "spirv.$TypedPointerType"
157*0fca6ea1SDimitry Andric inline Type *getTypedPointerWrapper(Type *ElemTy, unsigned AS) {
158*0fca6ea1SDimitry Andric   return TargetExtType::get(ElemTy->getContext(), TYPED_PTR_TARGET_EXT_NAME,
159*0fca6ea1SDimitry Andric                             {ElemTy}, {AS});
160*0fca6ea1SDimitry Andric }
161*0fca6ea1SDimitry Andric 
162*0fca6ea1SDimitry Andric inline bool isTypedPointerWrapper(TargetExtType *ExtTy) {
163*0fca6ea1SDimitry Andric   return ExtTy->getName() == TYPED_PTR_TARGET_EXT_NAME &&
164*0fca6ea1SDimitry Andric          ExtTy->getNumIntParameters() == 1 &&
165*0fca6ea1SDimitry Andric          ExtTy->getNumTypeParameters() == 1;
166*0fca6ea1SDimitry Andric }
167*0fca6ea1SDimitry Andric 
168*0fca6ea1SDimitry Andric inline Type *applyWrappers(Type *Ty) {
169*0fca6ea1SDimitry Andric   if (auto *ExtTy = dyn_cast<TargetExtType>(Ty)) {
170*0fca6ea1SDimitry Andric     if (isTypedPointerWrapper(ExtTy))
171*0fca6ea1SDimitry Andric       return TypedPointerType::get(applyWrappers(ExtTy->getTypeParameter(0)),
172*0fca6ea1SDimitry Andric                                    ExtTy->getIntParameter(0));
173*0fca6ea1SDimitry Andric   } else if (auto *VecTy = dyn_cast<VectorType>(Ty)) {
174*0fca6ea1SDimitry Andric     Type *ElemTy = VecTy->getElementType();
175*0fca6ea1SDimitry Andric     Type *NewElemTy = ElemTy->isTargetExtTy() ? applyWrappers(ElemTy) : ElemTy;
176*0fca6ea1SDimitry Andric     if (NewElemTy != ElemTy)
177*0fca6ea1SDimitry Andric       return VectorType::get(NewElemTy, VecTy->getElementCount());
178*0fca6ea1SDimitry Andric   }
179*0fca6ea1SDimitry Andric   return Ty;
180*0fca6ea1SDimitry Andric }
181*0fca6ea1SDimitry Andric 
182*0fca6ea1SDimitry Andric inline Type *getPointeeType(Type *Ty) {
183*0fca6ea1SDimitry Andric   if (auto PType = dyn_cast<TypedPointerType>(Ty))
184*0fca6ea1SDimitry Andric     return PType->getElementType();
185*0fca6ea1SDimitry Andric   else if (auto *ExtTy = dyn_cast<TargetExtType>(Ty))
186*0fca6ea1SDimitry Andric     if (isTypedPointerWrapper(ExtTy))
187*0fca6ea1SDimitry Andric       return applyWrappers(ExtTy->getTypeParameter(0));
188*0fca6ea1SDimitry Andric   return nullptr;
189*0fca6ea1SDimitry Andric }
190*0fca6ea1SDimitry Andric 
191*0fca6ea1SDimitry Andric inline bool isUntypedEquivalentToTyExt(Type *Ty1, Type *Ty2) {
192*0fca6ea1SDimitry Andric   if (!isUntypedPointerTy(Ty1) || !Ty2)
193*0fca6ea1SDimitry Andric     return false;
194*0fca6ea1SDimitry Andric   if (auto *ExtTy = dyn_cast<TargetExtType>(Ty2))
195*0fca6ea1SDimitry Andric     if (isTypedPointerWrapper(ExtTy) &&
196*0fca6ea1SDimitry Andric         ExtTy->getTypeParameter(0) ==
197*0fca6ea1SDimitry Andric             IntegerType::getInt8Ty(Ty1->getContext()) &&
198*0fca6ea1SDimitry Andric         ExtTy->getIntParameter(0) == cast<PointerType>(Ty1)->getAddressSpace())
199*0fca6ea1SDimitry Andric       return true;
200*0fca6ea1SDimitry Andric   return false;
201*0fca6ea1SDimitry Andric }
202*0fca6ea1SDimitry Andric 
203*0fca6ea1SDimitry Andric inline bool isEquivalentTypes(Type *Ty1, Type *Ty2) {
204*0fca6ea1SDimitry Andric   return isUntypedEquivalentToTyExt(Ty1, Ty2) ||
205*0fca6ea1SDimitry Andric          isUntypedEquivalentToTyExt(Ty2, Ty1);
206*0fca6ea1SDimitry Andric }
207*0fca6ea1SDimitry Andric 
208*0fca6ea1SDimitry Andric inline Type *toTypedPointer(Type *Ty) {
209*0fca6ea1SDimitry Andric   if (Type *NewTy = applyWrappers(Ty); NewTy != Ty)
210*0fca6ea1SDimitry Andric     return NewTy;
211*0fca6ea1SDimitry Andric   return isUntypedPointerTy(Ty)
212*0fca6ea1SDimitry Andric              ? TypedPointerType::get(IntegerType::getInt8Ty(Ty->getContext()),
213*0fca6ea1SDimitry Andric                                      getPointerAddressSpace(Ty))
214*0fca6ea1SDimitry Andric              : Ty;
215*0fca6ea1SDimitry Andric }
216*0fca6ea1SDimitry Andric 
217*0fca6ea1SDimitry Andric inline Type *toTypedFunPointer(FunctionType *FTy) {
218*0fca6ea1SDimitry Andric   Type *OrigRetTy = FTy->getReturnType();
219*0fca6ea1SDimitry Andric   Type *RetTy = toTypedPointer(OrigRetTy);
220*0fca6ea1SDimitry Andric   bool IsUntypedPtr = false;
221*0fca6ea1SDimitry Andric   for (Type *PTy : FTy->params()) {
222*0fca6ea1SDimitry Andric     if (isUntypedPointerTy(PTy)) {
223*0fca6ea1SDimitry Andric       IsUntypedPtr = true;
224*0fca6ea1SDimitry Andric       break;
225*0fca6ea1SDimitry Andric     }
226*0fca6ea1SDimitry Andric   }
227*0fca6ea1SDimitry Andric   if (!IsUntypedPtr && RetTy == OrigRetTy)
228*0fca6ea1SDimitry Andric     return FTy;
229*0fca6ea1SDimitry Andric   SmallVector<Type *> ParamTys;
230*0fca6ea1SDimitry Andric   for (Type *PTy : FTy->params())
231*0fca6ea1SDimitry Andric     ParamTys.push_back(toTypedPointer(PTy));
232*0fca6ea1SDimitry Andric   return FunctionType::get(RetTy, ParamTys, FTy->isVarArg());
233*0fca6ea1SDimitry Andric }
234*0fca6ea1SDimitry Andric 
235*0fca6ea1SDimitry Andric inline const Type *unifyPtrType(const Type *Ty) {
236*0fca6ea1SDimitry Andric   if (auto FTy = dyn_cast<FunctionType>(Ty))
237*0fca6ea1SDimitry Andric     return toTypedFunPointer(const_cast<FunctionType *>(FTy));
238*0fca6ea1SDimitry Andric   return toTypedPointer(const_cast<Type *>(Ty));
239*0fca6ea1SDimitry Andric }
240*0fca6ea1SDimitry Andric 
241bdd1243dSDimitry Andric } // namespace llvm
24281ad6265SDimitry Andric #endif // LLVM_LIB_TARGET_SPIRV_SPIRVUTILS_H
243