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. 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. 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. 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. 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 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 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 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" 157 inline Type *getTypedPointerWrapper(Type *ElemTy, unsigned AS) { 158 return TargetExtType::get(ElemTy->getContext(), TYPED_PTR_TARGET_EXT_NAME, 159 {ElemTy}, {AS}); 160 } 161 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 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 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 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 203 inline bool isEquivalentTypes(Type *Ty1, Type *Ty2) { 204 return isUntypedEquivalentToTyExt(Ty1, Ty2) || 205 isUntypedEquivalentToTyExt(Ty2, Ty1); 206 } 207 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 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 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