1 //===-- SPIRVGlobalRegistry.h - SPIR-V Global Registry ----------*- 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 // SPIRVGlobalRegistry is used to maintain rich type information required for 10 // SPIR-V even after lowering from LLVM IR to GMIR. It can convert an llvm::Type 11 // into an OpTypeXXX instruction, and map it to a virtual register. Also it 12 // builds and supports consistency of constants and global variables. 13 // 14 //===----------------------------------------------------------------------===// 15 16 #ifndef LLVM_LIB_TARGET_SPIRV_SPIRVTYPEMANAGER_H 17 #define LLVM_LIB_TARGET_SPIRV_SPIRVTYPEMANAGER_H 18 19 #include "MCTargetDesc/SPIRVBaseInfo.h" 20 #include "SPIRVDuplicatesTracker.h" 21 #include "SPIRVInstrInfo.h" 22 #include "llvm/CodeGen/GlobalISel/MachineIRBuilder.h" 23 24 namespace llvm { 25 using SPIRVType = const MachineInstr; 26 27 class SPIRVGlobalRegistry { 28 // Registers holding values which have types associated with them. 29 // Initialized upon VReg definition in IRTranslator. 30 // Do not confuse this with DuplicatesTracker as DT maps Type* to <MF, Reg> 31 // where Reg = OpType... 32 // while VRegToTypeMap tracks SPIR-V type assigned to other regs (i.e. not 33 // type-declaring ones). 34 DenseMap<const MachineFunction *, DenseMap<Register, SPIRVType *>> 35 VRegToTypeMap; 36 37 SPIRVGeneralDuplicatesTracker DT; 38 39 DenseMap<SPIRVType *, const Type *> SPIRVToLLVMType; 40 41 // Look for an equivalent of the newType in the map. Return the equivalent 42 // if it's found, otherwise insert newType to the map and return the type. 43 const MachineInstr *checkSpecialInstr(const SPIRV::SpecialTypeDescriptor &TD, 44 MachineIRBuilder &MIRBuilder); 45 46 SmallPtrSet<const Type *, 4> TypesInProcessing; 47 DenseMap<const Type *, SPIRVType *> ForwardPointerTypes; 48 49 // Number of bits pointers and size_t integers require. 50 const unsigned PointerSize; 51 52 // Add a new OpTypeXXX instruction without checking for duplicates. 53 SPIRVType *createSPIRVType(const Type *Type, MachineIRBuilder &MIRBuilder, 54 SPIRV::AccessQualifier::AccessQualifier AQ = 55 SPIRV::AccessQualifier::ReadWrite, 56 bool EmitIR = true); 57 SPIRVType *findSPIRVType(const Type *Ty, MachineIRBuilder &MIRBuilder, 58 SPIRV::AccessQualifier::AccessQualifier accessQual = 59 SPIRV::AccessQualifier::ReadWrite, 60 bool EmitIR = true); 61 SPIRVType * 62 restOfCreateSPIRVType(const Type *Type, MachineIRBuilder &MIRBuilder, 63 SPIRV::AccessQualifier::AccessQualifier AccessQual, 64 bool EmitIR); 65 66 public: 67 SPIRVGlobalRegistry(unsigned PointerSize); 68 69 MachineFunction *CurMF; 70 71 void add(const Constant *C, MachineFunction *MF, Register R) { 72 DT.add(C, MF, R); 73 } 74 75 void add(const GlobalVariable *GV, MachineFunction *MF, Register R) { 76 DT.add(GV, MF, R); 77 } 78 79 void add(const Function *F, MachineFunction *MF, Register R) { 80 DT.add(F, MF, R); 81 } 82 83 void add(const Argument *Arg, MachineFunction *MF, Register R) { 84 DT.add(Arg, MF, R); 85 } 86 87 Register find(const Constant *C, MachineFunction *MF) { 88 return DT.find(C, MF); 89 } 90 91 Register find(const GlobalVariable *GV, MachineFunction *MF) { 92 return DT.find(GV, MF); 93 } 94 95 Register find(const Function *F, MachineFunction *MF) { 96 return DT.find(F, MF); 97 } 98 99 void buildDepsGraph(std::vector<SPIRV::DTSortableEntry *> &Graph, 100 MachineModuleInfo *MMI = nullptr) { 101 DT.buildDepsGraph(Graph, MMI); 102 } 103 104 // Get or create a SPIR-V type corresponding the given LLVM IR type, 105 // and map it to the given VReg by creating an ASSIGN_TYPE instruction. 106 SPIRVType *assignTypeToVReg(const Type *Type, Register VReg, 107 MachineIRBuilder &MIRBuilder, 108 SPIRV::AccessQualifier::AccessQualifier AQ = 109 SPIRV::AccessQualifier::ReadWrite, 110 bool EmitIR = true); 111 SPIRVType *assignIntTypeToVReg(unsigned BitWidth, Register VReg, 112 MachineInstr &I, const SPIRVInstrInfo &TII); 113 SPIRVType *assignVectTypeToVReg(SPIRVType *BaseType, unsigned NumElements, 114 Register VReg, MachineInstr &I, 115 const SPIRVInstrInfo &TII); 116 117 // In cases where the SPIR-V type is already known, this function can be 118 // used to map it to the given VReg via an ASSIGN_TYPE instruction. 119 void assignSPIRVTypeToVReg(SPIRVType *Type, Register VReg, 120 MachineFunction &MF); 121 122 // Either generate a new OpTypeXXX instruction or return an existing one 123 // corresponding to the given LLVM IR type. 124 // EmitIR controls if we emit GMIR or SPV constants (e.g. for array sizes) 125 // because this method may be called from InstructionSelector and we don't 126 // want to emit extra IR instructions there. 127 SPIRVType *getOrCreateSPIRVType(const Type *Type, 128 MachineIRBuilder &MIRBuilder, 129 SPIRV::AccessQualifier::AccessQualifier AQ = 130 SPIRV::AccessQualifier::ReadWrite, 131 bool EmitIR = true); 132 133 const Type *getTypeForSPIRVType(const SPIRVType *Ty) const { 134 auto Res = SPIRVToLLVMType.find(Ty); 135 assert(Res != SPIRVToLLVMType.end()); 136 return Res->second; 137 } 138 139 // Either generate a new OpTypeXXX instruction or return an existing one 140 // corresponding to the given string containing the name of the builtin type. 141 SPIRVType *getOrCreateSPIRVTypeByName(StringRef TypeStr, 142 MachineIRBuilder &MIRBuilder); 143 144 // Return the SPIR-V type instruction corresponding to the given VReg, or 145 // nullptr if no such type instruction exists. 146 SPIRVType *getSPIRVTypeForVReg(Register VReg) const; 147 148 // Whether the given VReg has a SPIR-V type mapped to it yet. 149 bool hasSPIRVTypeForVReg(Register VReg) const { 150 return getSPIRVTypeForVReg(VReg) != nullptr; 151 } 152 153 // Return the VReg holding the result of the given OpTypeXXX instruction. 154 Register getSPIRVTypeID(const SPIRVType *SpirvType) const; 155 156 void setCurrentFunc(MachineFunction &MF) { CurMF = &MF; } 157 158 // Whether the given VReg has an OpTypeXXX instruction mapped to it with the 159 // given opcode (e.g. OpTypeFloat). 160 bool isScalarOfType(Register VReg, unsigned TypeOpcode) const; 161 162 // Return true if the given VReg's assigned SPIR-V type is either a scalar 163 // matching the given opcode, or a vector with an element type matching that 164 // opcode (e.g. OpTypeBool, or OpTypeVector %x 4, where %x is OpTypeBool). 165 bool isScalarOrVectorOfType(Register VReg, unsigned TypeOpcode) const; 166 167 // For vectors or scalars of ints/floats, return the scalar type's bitwidth. 168 unsigned getScalarOrVectorBitWidth(const SPIRVType *Type) const; 169 170 // For integer vectors or scalars, return whether the integers are signed. 171 bool isScalarOrVectorSigned(const SPIRVType *Type) const; 172 173 // Gets the storage class of the pointer type assigned to this vreg. 174 SPIRV::StorageClass::StorageClass getPointerStorageClass(Register VReg) const; 175 176 // Return the number of bits SPIR-V pointers and size_t variables require. 177 unsigned getPointerSize() const { return PointerSize; } 178 179 private: 180 SPIRVType *getOpTypeBool(MachineIRBuilder &MIRBuilder); 181 182 SPIRVType *getOpTypeInt(uint32_t Width, MachineIRBuilder &MIRBuilder, 183 bool IsSigned = false); 184 185 SPIRVType *getOpTypeFloat(uint32_t Width, MachineIRBuilder &MIRBuilder); 186 187 SPIRVType *getOpTypeVoid(MachineIRBuilder &MIRBuilder); 188 189 SPIRVType *getOpTypeVector(uint32_t NumElems, SPIRVType *ElemType, 190 MachineIRBuilder &MIRBuilder); 191 192 SPIRVType *getOpTypeArray(uint32_t NumElems, SPIRVType *ElemType, 193 MachineIRBuilder &MIRBuilder, bool EmitIR = true); 194 195 SPIRVType *getOpTypeOpaque(const StructType *Ty, 196 MachineIRBuilder &MIRBuilder); 197 198 SPIRVType *getOpTypeStruct(const StructType *Ty, MachineIRBuilder &MIRBuilder, 199 bool EmitIR = true); 200 201 SPIRVType *getOpTypePointer(SPIRV::StorageClass::StorageClass SC, 202 SPIRVType *ElemType, MachineIRBuilder &MIRBuilder, 203 Register Reg); 204 205 SPIRVType *getOpTypeForwardPointer(SPIRV::StorageClass::StorageClass SC, 206 MachineIRBuilder &MIRBuilder); 207 208 SPIRVType *getOpTypeFunction(SPIRVType *RetType, 209 const SmallVectorImpl<SPIRVType *> &ArgTypes, 210 MachineIRBuilder &MIRBuilder); 211 212 SPIRVType * 213 getOrCreateSpecialType(const Type *Ty, MachineIRBuilder &MIRBuilder, 214 SPIRV::AccessQualifier::AccessQualifier AccQual); 215 216 std::tuple<Register, ConstantInt *, bool> getOrCreateConstIntReg( 217 uint64_t Val, SPIRVType *SpvType, MachineIRBuilder *MIRBuilder, 218 MachineInstr *I = nullptr, const SPIRVInstrInfo *TII = nullptr); 219 SPIRVType *finishCreatingSPIRVType(const Type *LLVMTy, SPIRVType *SpirvType); 220 Register getOrCreateIntCompositeOrNull(uint64_t Val, MachineInstr &I, 221 SPIRVType *SpvType, 222 const SPIRVInstrInfo &TII, 223 Constant *CA, unsigned BitWidth, 224 unsigned ElemCnt); 225 Register getOrCreateIntCompositeOrNull(uint64_t Val, 226 MachineIRBuilder &MIRBuilder, 227 SPIRVType *SpvType, bool EmitIR, 228 Constant *CA, unsigned BitWidth, 229 unsigned ElemCnt); 230 231 public: 232 Register buildConstantInt(uint64_t Val, MachineIRBuilder &MIRBuilder, 233 SPIRVType *SpvType = nullptr, bool EmitIR = true); 234 Register getOrCreateConstInt(uint64_t Val, MachineInstr &I, 235 SPIRVType *SpvType, const SPIRVInstrInfo &TII); 236 Register buildConstantFP(APFloat Val, MachineIRBuilder &MIRBuilder, 237 SPIRVType *SpvType = nullptr); 238 Register getOrCreateConsIntVector(uint64_t Val, MachineInstr &I, 239 SPIRVType *SpvType, 240 const SPIRVInstrInfo &TII); 241 Register getOrCreateConsIntArray(uint64_t Val, MachineInstr &I, 242 SPIRVType *SpvType, 243 const SPIRVInstrInfo &TII); 244 Register getOrCreateConsIntVector(uint64_t Val, MachineIRBuilder &MIRBuilder, 245 SPIRVType *SpvType, bool EmitIR = true); 246 Register getOrCreateConsIntArray(uint64_t Val, MachineIRBuilder &MIRBuilder, 247 SPIRVType *SpvType, bool EmitIR = true); 248 Register getOrCreateConstNullPtr(MachineIRBuilder &MIRBuilder, 249 SPIRVType *SpvType); 250 Register buildConstantSampler(Register Res, unsigned AddrMode, unsigned Param, 251 unsigned FilerMode, 252 MachineIRBuilder &MIRBuilder, 253 SPIRVType *SpvType); 254 Register getOrCreateUndef(MachineInstr &I, SPIRVType *SpvType, 255 const SPIRVInstrInfo &TII); 256 Register buildGlobalVariable(Register Reg, SPIRVType *BaseType, 257 StringRef Name, const GlobalValue *GV, 258 SPIRV::StorageClass::StorageClass Storage, 259 const MachineInstr *Init, bool IsConst, 260 bool HasLinkageTy, 261 SPIRV::LinkageType::LinkageType LinkageType, 262 MachineIRBuilder &MIRBuilder, 263 bool IsInstSelector); 264 265 // Convenient helpers for getting types with check for duplicates. 266 SPIRVType *getOrCreateSPIRVIntegerType(unsigned BitWidth, 267 MachineIRBuilder &MIRBuilder); 268 SPIRVType *getOrCreateSPIRVIntegerType(unsigned BitWidth, MachineInstr &I, 269 const SPIRVInstrInfo &TII); 270 SPIRVType *getOrCreateSPIRVBoolType(MachineIRBuilder &MIRBuilder); 271 SPIRVType *getOrCreateSPIRVBoolType(MachineInstr &I, 272 const SPIRVInstrInfo &TII); 273 SPIRVType *getOrCreateSPIRVVectorType(SPIRVType *BaseType, 274 unsigned NumElements, 275 MachineIRBuilder &MIRBuilder); 276 SPIRVType *getOrCreateSPIRVVectorType(SPIRVType *BaseType, 277 unsigned NumElements, MachineInstr &I, 278 const SPIRVInstrInfo &TII); 279 SPIRVType *getOrCreateSPIRVArrayType(SPIRVType *BaseType, 280 unsigned NumElements, MachineInstr &I, 281 const SPIRVInstrInfo &TII); 282 283 SPIRVType *getOrCreateSPIRVPointerType( 284 SPIRVType *BaseType, MachineIRBuilder &MIRBuilder, 285 SPIRV::StorageClass::StorageClass SClass = SPIRV::StorageClass::Function); 286 SPIRVType *getOrCreateSPIRVPointerType( 287 SPIRVType *BaseType, MachineInstr &I, const SPIRVInstrInfo &TII, 288 SPIRV::StorageClass::StorageClass SClass = SPIRV::StorageClass::Function); 289 290 SPIRVType * 291 getOrCreateOpTypeImage(MachineIRBuilder &MIRBuilder, SPIRVType *SampledType, 292 SPIRV::Dim::Dim Dim, uint32_t Depth, uint32_t Arrayed, 293 uint32_t Multisampled, uint32_t Sampled, 294 SPIRV::ImageFormat::ImageFormat ImageFormat, 295 SPIRV::AccessQualifier::AccessQualifier AccQual); 296 297 SPIRVType *getOrCreateOpTypeSampler(MachineIRBuilder &MIRBuilder); 298 299 SPIRVType *getOrCreateOpTypeSampledImage(SPIRVType *ImageType, 300 MachineIRBuilder &MIRBuilder); 301 302 SPIRVType * 303 getOrCreateOpTypePipe(MachineIRBuilder &MIRBuilder, 304 SPIRV::AccessQualifier::AccessQualifier AccQual); 305 SPIRVType *getOrCreateOpTypeDeviceEvent(MachineIRBuilder &MIRBuilder); 306 SPIRVType *getOrCreateOpTypeFunctionWithArgs( 307 const Type *Ty, SPIRVType *RetType, 308 const SmallVectorImpl<SPIRVType *> &ArgTypes, 309 MachineIRBuilder &MIRBuilder); 310 SPIRVType *getOrCreateOpTypeByOpcode(const Type *Ty, 311 MachineIRBuilder &MIRBuilder, 312 unsigned Opcode); 313 }; 314 } // end namespace llvm 315 #endif // LLLVM_LIB_TARGET_SPIRV_SPIRVTYPEMANAGER_H 316