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 SmallPtrSet<const Type *, 4> TypesInProcessing; 42 DenseMap<const Type *, SPIRVType *> ForwardPointerTypes; 43 44 // Number of bits pointers and size_t integers require. 45 const unsigned PointerSize; 46 47 // Add a new OpTypeXXX instruction without checking for duplicates. 48 SPIRVType * 49 createSPIRVType(const Type *Type, MachineIRBuilder &MIRBuilder, 50 SPIRV::AccessQualifier AQ = SPIRV::AccessQualifier::ReadWrite, 51 bool EmitIR = true); 52 SPIRVType *findSPIRVType( 53 const Type *Ty, MachineIRBuilder &MIRBuilder, 54 SPIRV::AccessQualifier accessQual = SPIRV::AccessQualifier::ReadWrite, 55 bool EmitIR = true); 56 SPIRVType *restOfCreateSPIRVType(const Type *Type, 57 MachineIRBuilder &MIRBuilder, 58 SPIRV::AccessQualifier AccessQual, 59 bool EmitIR); 60 61 public: 62 SPIRVGlobalRegistry(unsigned PointerSize); 63 64 MachineFunction *CurMF; 65 66 void add(const Constant *C, MachineFunction *MF, Register R) { 67 DT.add(C, MF, R); 68 } 69 70 void add(const GlobalVariable *GV, MachineFunction *MF, Register R) { 71 DT.add(GV, MF, R); 72 } 73 74 void add(const Function *F, MachineFunction *MF, Register R) { 75 DT.add(F, MF, R); 76 } 77 78 void add(const Argument *Arg, MachineFunction *MF, Register R) { 79 DT.add(Arg, MF, R); 80 } 81 82 Register find(const Constant *C, MachineFunction *MF) { 83 return DT.find(C, MF); 84 } 85 86 Register find(const GlobalVariable *GV, MachineFunction *MF) { 87 return DT.find(GV, MF); 88 } 89 90 Register find(const Function *F, MachineFunction *MF) { 91 return DT.find(F, MF); 92 } 93 94 void buildDepsGraph(std::vector<SPIRV::DTSortableEntry *> &Graph, 95 MachineModuleInfo *MMI = nullptr) { 96 DT.buildDepsGraph(Graph, MMI); 97 } 98 99 // Get or create a SPIR-V type corresponding the given LLVM IR type, 100 // and map it to the given VReg by creating an ASSIGN_TYPE instruction. 101 SPIRVType *assignTypeToVReg( 102 const Type *Type, Register VReg, MachineIRBuilder &MIRBuilder, 103 SPIRV::AccessQualifier AQ = SPIRV::AccessQualifier::ReadWrite, 104 bool EmitIR = true); 105 SPIRVType *assignIntTypeToVReg(unsigned BitWidth, Register VReg, 106 MachineInstr &I, const SPIRVInstrInfo &TII); 107 SPIRVType *assignVectTypeToVReg(SPIRVType *BaseType, unsigned NumElements, 108 Register VReg, MachineInstr &I, 109 const SPIRVInstrInfo &TII); 110 111 // In cases where the SPIR-V type is already known, this function can be 112 // used to map it to the given VReg via an ASSIGN_TYPE instruction. 113 void assignSPIRVTypeToVReg(SPIRVType *Type, Register VReg, 114 MachineFunction &MF); 115 116 // Either generate a new OpTypeXXX instruction or return an existing one 117 // corresponding to the given LLVM IR type. 118 // EmitIR controls if we emit GMIR or SPV constants (e.g. for array sizes) 119 // because this method may be called from InstructionSelector and we don't 120 // want to emit extra IR instructions there. 121 SPIRVType *getOrCreateSPIRVType( 122 const Type *Type, MachineIRBuilder &MIRBuilder, 123 SPIRV::AccessQualifier AQ = SPIRV::AccessQualifier::ReadWrite, 124 bool EmitIR = true); 125 126 const Type *getTypeForSPIRVType(const SPIRVType *Ty) const { 127 auto Res = SPIRVToLLVMType.find(Ty); 128 assert(Res != SPIRVToLLVMType.end()); 129 return Res->second; 130 } 131 132 // Return the SPIR-V type instruction corresponding to the given VReg, or 133 // nullptr if no such type instruction exists. 134 SPIRVType *getSPIRVTypeForVReg(Register VReg) const; 135 136 // Whether the given VReg has a SPIR-V type mapped to it yet. 137 bool hasSPIRVTypeForVReg(Register VReg) const { 138 return getSPIRVTypeForVReg(VReg) != nullptr; 139 } 140 141 // Return the VReg holding the result of the given OpTypeXXX instruction. 142 Register getSPIRVTypeID(const SPIRVType *SpirvType) const; 143 144 void setCurrentFunc(MachineFunction &MF) { CurMF = &MF; } 145 146 // Whether the given VReg has an OpTypeXXX instruction mapped to it with the 147 // given opcode (e.g. OpTypeFloat). 148 bool isScalarOfType(Register VReg, unsigned TypeOpcode) const; 149 150 // Return true if the given VReg's assigned SPIR-V type is either a scalar 151 // matching the given opcode, or a vector with an element type matching that 152 // opcode (e.g. OpTypeBool, or OpTypeVector %x 4, where %x is OpTypeBool). 153 bool isScalarOrVectorOfType(Register VReg, unsigned TypeOpcode) const; 154 155 // For vectors or scalars of ints/floats, return the scalar type's bitwidth. 156 unsigned getScalarOrVectorBitWidth(const SPIRVType *Type) const; 157 158 // For integer vectors or scalars, return whether the integers are signed. 159 bool isScalarOrVectorSigned(const SPIRVType *Type) const; 160 161 // Gets the storage class of the pointer type assigned to this vreg. 162 SPIRV::StorageClass getPointerStorageClass(Register VReg) const; 163 164 // Return the number of bits SPIR-V pointers and size_t variables require. 165 unsigned getPointerSize() const { return PointerSize; } 166 167 private: 168 SPIRVType *getOpTypeBool(MachineIRBuilder &MIRBuilder); 169 170 SPIRVType *getOpTypeInt(uint32_t Width, MachineIRBuilder &MIRBuilder, 171 bool IsSigned = false); 172 173 SPIRVType *getOpTypeFloat(uint32_t Width, MachineIRBuilder &MIRBuilder); 174 175 SPIRVType *getOpTypeVoid(MachineIRBuilder &MIRBuilder); 176 177 SPIRVType *getOpTypeVector(uint32_t NumElems, SPIRVType *ElemType, 178 MachineIRBuilder &MIRBuilder); 179 180 SPIRVType *getOpTypeArray(uint32_t NumElems, SPIRVType *ElemType, 181 MachineIRBuilder &MIRBuilder, bool EmitIR = true); 182 183 SPIRVType *getOpTypeOpaque(const StructType *Ty, 184 MachineIRBuilder &MIRBuilder); 185 186 SPIRVType *getOpTypeStruct(const StructType *Ty, MachineIRBuilder &MIRBuilder, 187 bool EmitIR = true); 188 189 SPIRVType *getOpTypePointer(SPIRV::StorageClass SC, SPIRVType *ElemType, 190 MachineIRBuilder &MIRBuilder, Register Reg); 191 192 SPIRVType *getOpTypeForwardPointer(SPIRV::StorageClass SC, 193 MachineIRBuilder &MIRBuilder); 194 195 SPIRVType *getOpTypeFunction(SPIRVType *RetType, 196 const SmallVectorImpl<SPIRVType *> &ArgTypes, 197 MachineIRBuilder &MIRBuilder); 198 std::tuple<Register, ConstantInt *, bool> getOrCreateConstIntReg( 199 uint64_t Val, SPIRVType *SpvType, MachineIRBuilder *MIRBuilder, 200 MachineInstr *I = nullptr, const SPIRVInstrInfo *TII = nullptr); 201 SPIRVType *finishCreatingSPIRVType(const Type *LLVMTy, SPIRVType *SpirvType); 202 203 public: 204 Register buildConstantInt(uint64_t Val, MachineIRBuilder &MIRBuilder, 205 SPIRVType *SpvType = nullptr, bool EmitIR = true); 206 Register getOrCreateConstInt(uint64_t Val, MachineInstr &I, 207 SPIRVType *SpvType, const SPIRVInstrInfo &TII); 208 Register buildConstantFP(APFloat Val, MachineIRBuilder &MIRBuilder, 209 SPIRVType *SpvType = nullptr); 210 Register getOrCreateConsIntVector(uint64_t Val, MachineInstr &I, 211 SPIRVType *SpvType, 212 const SPIRVInstrInfo &TII); 213 Register getOrCreateUndef(MachineInstr &I, SPIRVType *SpvType, 214 const SPIRVInstrInfo &TII); 215 Register 216 buildGlobalVariable(Register Reg, SPIRVType *BaseType, StringRef Name, 217 const GlobalValue *GV, SPIRV::StorageClass Storage, 218 const MachineInstr *Init, bool IsConst, bool HasLinkageTy, 219 SPIRV::LinkageType LinkageType, 220 MachineIRBuilder &MIRBuilder, bool IsInstSelector); 221 222 // Convenient helpers for getting types with check for duplicates. 223 SPIRVType *getOrCreateSPIRVIntegerType(unsigned BitWidth, 224 MachineIRBuilder &MIRBuilder); 225 SPIRVType *getOrCreateSPIRVIntegerType(unsigned BitWidth, MachineInstr &I, 226 const SPIRVInstrInfo &TII); 227 SPIRVType *getOrCreateSPIRVBoolType(MachineIRBuilder &MIRBuilder); 228 SPIRVType *getOrCreateSPIRVBoolType(MachineInstr &I, 229 const SPIRVInstrInfo &TII); 230 SPIRVType *getOrCreateSPIRVVectorType(SPIRVType *BaseType, 231 unsigned NumElements, 232 MachineIRBuilder &MIRBuilder); 233 SPIRVType *getOrCreateSPIRVVectorType(SPIRVType *BaseType, 234 unsigned NumElements, MachineInstr &I, 235 const SPIRVInstrInfo &TII); 236 SPIRVType *getOrCreateSPIRVPointerType( 237 SPIRVType *BaseType, MachineIRBuilder &MIRBuilder, 238 SPIRV::StorageClass SClass = SPIRV::StorageClass::Function); 239 SPIRVType *getOrCreateSPIRVPointerType( 240 SPIRVType *BaseType, MachineInstr &I, const SPIRVInstrInfo &TII, 241 SPIRV::StorageClass SClass = SPIRV::StorageClass::Function); 242 SPIRVType *getOrCreateOpTypeFunctionWithArgs( 243 const Type *Ty, SPIRVType *RetType, 244 const SmallVectorImpl<SPIRVType *> &ArgTypes, 245 MachineIRBuilder &MIRBuilder); 246 }; 247 } // end namespace llvm 248 #endif // LLLVM_LIB_TARGET_SPIRV_SPIRVTYPEMANAGER_H 249