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