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