1 //===-- SPIRVGlobalRegistry.cpp - 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 // This file contains the implementation of the SPIRVGlobalRegistry class, 10 // which is used to maintain rich type information required for SPIR-V even 11 // after lowering from LLVM IR to GMIR. It can convert an llvm::Type into 12 // an OpTypeXXX instruction, and map it to a virtual register. Also it builds 13 // and supports consistency of constants and global variables. 14 // 15 //===----------------------------------------------------------------------===// 16 17 #include "SPIRVGlobalRegistry.h" 18 #include "SPIRV.h" 19 #include "SPIRVSubtarget.h" 20 #include "SPIRVTargetMachine.h" 21 #include "SPIRVUtils.h" 22 23 using namespace llvm; 24 SPIRVGlobalRegistry::SPIRVGlobalRegistry(unsigned PointerSize) 25 : PointerSize(PointerSize) {} 26 27 SPIRVType *SPIRVGlobalRegistry::assignTypeToVReg( 28 const Type *Type, Register VReg, MachineIRBuilder &MIRBuilder, 29 SPIRV::AccessQualifier AccessQual, bool EmitIR) { 30 31 SPIRVType *SpirvType = 32 getOrCreateSPIRVType(Type, MIRBuilder, AccessQual, EmitIR); 33 assignSPIRVTypeToVReg(SpirvType, VReg, MIRBuilder.getMF()); 34 return SpirvType; 35 } 36 37 void SPIRVGlobalRegistry::assignSPIRVTypeToVReg(SPIRVType *SpirvType, 38 Register VReg, 39 MachineFunction &MF) { 40 VRegToTypeMap[&MF][VReg] = SpirvType; 41 } 42 43 static Register createTypeVReg(MachineIRBuilder &MIRBuilder) { 44 auto &MRI = MIRBuilder.getMF().getRegInfo(); 45 auto Res = MRI.createGenericVirtualRegister(LLT::scalar(32)); 46 MRI.setRegClass(Res, &SPIRV::TYPERegClass); 47 return Res; 48 } 49 50 static Register createTypeVReg(MachineRegisterInfo &MRI) { 51 auto Res = MRI.createGenericVirtualRegister(LLT::scalar(32)); 52 MRI.setRegClass(Res, &SPIRV::TYPERegClass); 53 return Res; 54 } 55 56 SPIRVType *SPIRVGlobalRegistry::getOpTypeBool(MachineIRBuilder &MIRBuilder) { 57 return MIRBuilder.buildInstr(SPIRV::OpTypeBool) 58 .addDef(createTypeVReg(MIRBuilder)); 59 } 60 61 SPIRVType *SPIRVGlobalRegistry::getOpTypeInt(uint32_t Width, 62 MachineIRBuilder &MIRBuilder, 63 bool IsSigned) { 64 auto MIB = MIRBuilder.buildInstr(SPIRV::OpTypeInt) 65 .addDef(createTypeVReg(MIRBuilder)) 66 .addImm(Width) 67 .addImm(IsSigned ? 1 : 0); 68 return MIB; 69 } 70 71 SPIRVType *SPIRVGlobalRegistry::getOpTypeFloat(uint32_t Width, 72 MachineIRBuilder &MIRBuilder) { 73 auto MIB = MIRBuilder.buildInstr(SPIRV::OpTypeFloat) 74 .addDef(createTypeVReg(MIRBuilder)) 75 .addImm(Width); 76 return MIB; 77 } 78 79 SPIRVType *SPIRVGlobalRegistry::getOpTypeVoid(MachineIRBuilder &MIRBuilder) { 80 return MIRBuilder.buildInstr(SPIRV::OpTypeVoid) 81 .addDef(createTypeVReg(MIRBuilder)); 82 } 83 84 SPIRVType *SPIRVGlobalRegistry::getOpTypeVector(uint32_t NumElems, 85 SPIRVType *ElemType, 86 MachineIRBuilder &MIRBuilder) { 87 auto EleOpc = ElemType->getOpcode(); 88 assert((EleOpc == SPIRV::OpTypeInt || EleOpc == SPIRV::OpTypeFloat || 89 EleOpc == SPIRV::OpTypeBool) && 90 "Invalid vector element type"); 91 92 auto MIB = MIRBuilder.buildInstr(SPIRV::OpTypeVector) 93 .addDef(createTypeVReg(MIRBuilder)) 94 .addUse(getSPIRVTypeID(ElemType)) 95 .addImm(NumElems); 96 return MIB; 97 } 98 99 Register SPIRVGlobalRegistry::buildConstantInt(uint64_t Val, 100 MachineIRBuilder &MIRBuilder, 101 SPIRVType *SpvType, 102 bool EmitIR) { 103 auto &MF = MIRBuilder.getMF(); 104 Register Res; 105 const IntegerType *LLVMIntTy; 106 if (SpvType) 107 LLVMIntTy = cast<IntegerType>(getTypeForSPIRVType(SpvType)); 108 else 109 LLVMIntTy = IntegerType::getInt32Ty(MF.getFunction().getContext()); 110 // Find a constant in DT or build a new one. 111 const auto ConstInt = 112 ConstantInt::get(const_cast<IntegerType *>(LLVMIntTy), Val); 113 unsigned BitWidth = SpvType ? getScalarOrVectorBitWidth(SpvType) : 32; 114 Res = MF.getRegInfo().createGenericVirtualRegister(LLT::scalar(BitWidth)); 115 assignTypeToVReg(LLVMIntTy, Res, MIRBuilder); 116 if (EmitIR) 117 MIRBuilder.buildConstant(Res, *ConstInt); 118 else 119 MIRBuilder.buildInstr(SPIRV::OpConstantI) 120 .addDef(Res) 121 .addImm(ConstInt->getSExtValue()); 122 return Res; 123 } 124 125 Register SPIRVGlobalRegistry::buildConstantFP(APFloat Val, 126 MachineIRBuilder &MIRBuilder, 127 SPIRVType *SpvType) { 128 auto &MF = MIRBuilder.getMF(); 129 Register Res; 130 const Type *LLVMFPTy; 131 if (SpvType) { 132 LLVMFPTy = getTypeForSPIRVType(SpvType); 133 assert(LLVMFPTy->isFloatingPointTy()); 134 } else { 135 LLVMFPTy = IntegerType::getFloatTy(MF.getFunction().getContext()); 136 } 137 // Find a constant in DT or build a new one. 138 const auto ConstFP = ConstantFP::get(LLVMFPTy->getContext(), Val); 139 unsigned BitWidth = SpvType ? getScalarOrVectorBitWidth(SpvType) : 32; 140 Res = MF.getRegInfo().createGenericVirtualRegister(LLT::scalar(BitWidth)); 141 assignTypeToVReg(LLVMFPTy, Res, MIRBuilder); 142 MIRBuilder.buildFConstant(Res, *ConstFP); 143 return Res; 144 } 145 146 Register SPIRVGlobalRegistry::buildGlobalVariable( 147 Register ResVReg, SPIRVType *BaseType, StringRef Name, 148 const GlobalValue *GV, SPIRV::StorageClass Storage, 149 const MachineInstr *Init, bool IsConst, bool HasLinkageTy, 150 SPIRV::LinkageType LinkageType, MachineIRBuilder &MIRBuilder, 151 bool IsInstSelector) { 152 const GlobalVariable *GVar = nullptr; 153 if (GV) 154 GVar = cast<const GlobalVariable>(GV); 155 else { 156 // If GV is not passed explicitly, use the name to find or construct 157 // the global variable. 158 Module *M = MIRBuilder.getMF().getFunction().getParent(); 159 GVar = M->getGlobalVariable(Name); 160 if (GVar == nullptr) { 161 const Type *Ty = getTypeForSPIRVType(BaseType); // TODO: check type. 162 GVar = new GlobalVariable(*M, const_cast<Type *>(Ty), false, 163 GlobalValue::ExternalLinkage, nullptr, 164 Twine(Name)); 165 } 166 GV = GVar; 167 } 168 Register Reg; 169 auto MIB = MIRBuilder.buildInstr(SPIRV::OpVariable) 170 .addDef(ResVReg) 171 .addUse(getSPIRVTypeID(BaseType)) 172 .addImm(static_cast<uint32_t>(Storage)); 173 174 if (Init != 0) { 175 MIB.addUse(Init->getOperand(0).getReg()); 176 } 177 178 // ISel may introduce a new register on this step, so we need to add it to 179 // DT and correct its type avoiding fails on the next stage. 180 if (IsInstSelector) { 181 const auto &Subtarget = CurMF->getSubtarget(); 182 constrainSelectedInstRegOperands(*MIB, *Subtarget.getInstrInfo(), 183 *Subtarget.getRegisterInfo(), 184 *Subtarget.getRegBankInfo()); 185 } 186 Reg = MIB->getOperand(0).getReg(); 187 188 // Set to Reg the same type as ResVReg has. 189 auto MRI = MIRBuilder.getMRI(); 190 assert(MRI->getType(ResVReg).isPointer() && "Pointer type is expected"); 191 if (Reg != ResVReg) { 192 LLT RegLLTy = LLT::pointer(MRI->getType(ResVReg).getAddressSpace(), 32); 193 MRI->setType(Reg, RegLLTy); 194 assignSPIRVTypeToVReg(BaseType, Reg, MIRBuilder.getMF()); 195 } 196 197 // If it's a global variable with name, output OpName for it. 198 if (GVar && GVar->hasName()) 199 buildOpName(Reg, GVar->getName(), MIRBuilder); 200 201 // Output decorations for the GV. 202 // TODO: maybe move to GenerateDecorations pass. 203 if (IsConst) 204 buildOpDecorate(Reg, MIRBuilder, SPIRV::Decoration::Constant, {}); 205 206 if (GVar && GVar->getAlign().valueOrOne().value() != 1) 207 buildOpDecorate( 208 Reg, MIRBuilder, SPIRV::Decoration::Alignment, 209 {static_cast<uint32_t>(GVar->getAlign().valueOrOne().value())}); 210 211 if (HasLinkageTy) 212 buildOpDecorate(Reg, MIRBuilder, SPIRV::Decoration::LinkageAttributes, 213 {static_cast<uint32_t>(LinkageType)}, Name); 214 return Reg; 215 } 216 217 SPIRVType *SPIRVGlobalRegistry::getOpTypeArray(uint32_t NumElems, 218 SPIRVType *ElemType, 219 MachineIRBuilder &MIRBuilder, 220 bool EmitIR) { 221 assert((ElemType->getOpcode() != SPIRV::OpTypeVoid) && 222 "Invalid array element type"); 223 Register NumElementsVReg = 224 buildConstantInt(NumElems, MIRBuilder, nullptr, EmitIR); 225 auto MIB = MIRBuilder.buildInstr(SPIRV::OpTypeArray) 226 .addDef(createTypeVReg(MIRBuilder)) 227 .addUse(getSPIRVTypeID(ElemType)) 228 .addUse(NumElementsVReg); 229 return MIB; 230 } 231 232 SPIRVType *SPIRVGlobalRegistry::getOpTypePointer(SPIRV::StorageClass SC, 233 SPIRVType *ElemType, 234 MachineIRBuilder &MIRBuilder) { 235 auto MIB = MIRBuilder.buildInstr(SPIRV::OpTypePointer) 236 .addDef(createTypeVReg(MIRBuilder)) 237 .addImm(static_cast<uint32_t>(SC)) 238 .addUse(getSPIRVTypeID(ElemType)); 239 return MIB; 240 } 241 242 SPIRVType *SPIRVGlobalRegistry::getOpTypeFunction( 243 SPIRVType *RetType, const SmallVectorImpl<SPIRVType *> &ArgTypes, 244 MachineIRBuilder &MIRBuilder) { 245 auto MIB = MIRBuilder.buildInstr(SPIRV::OpTypeFunction) 246 .addDef(createTypeVReg(MIRBuilder)) 247 .addUse(getSPIRVTypeID(RetType)); 248 for (const SPIRVType *ArgType : ArgTypes) 249 MIB.addUse(getSPIRVTypeID(ArgType)); 250 return MIB; 251 } 252 253 SPIRVType *SPIRVGlobalRegistry::createSPIRVType(const Type *Ty, 254 MachineIRBuilder &MIRBuilder, 255 SPIRV::AccessQualifier AccQual, 256 bool EmitIR) { 257 if (auto IType = dyn_cast<IntegerType>(Ty)) { 258 const unsigned Width = IType->getBitWidth(); 259 return Width == 1 ? getOpTypeBool(MIRBuilder) 260 : getOpTypeInt(Width, MIRBuilder, false); 261 } 262 if (Ty->isFloatingPointTy()) 263 return getOpTypeFloat(Ty->getPrimitiveSizeInBits(), MIRBuilder); 264 if (Ty->isVoidTy()) 265 return getOpTypeVoid(MIRBuilder); 266 if (Ty->isVectorTy()) { 267 auto El = getOrCreateSPIRVType(cast<FixedVectorType>(Ty)->getElementType(), 268 MIRBuilder); 269 return getOpTypeVector(cast<FixedVectorType>(Ty)->getNumElements(), El, 270 MIRBuilder); 271 } 272 if (Ty->isArrayTy()) { 273 auto *El = getOrCreateSPIRVType(Ty->getArrayElementType(), MIRBuilder); 274 return getOpTypeArray(Ty->getArrayNumElements(), El, MIRBuilder, EmitIR); 275 } 276 assert(!isa<StructType>(Ty) && "Unsupported StructType"); 277 if (auto FType = dyn_cast<FunctionType>(Ty)) { 278 SPIRVType *RetTy = getOrCreateSPIRVType(FType->getReturnType(), MIRBuilder); 279 SmallVector<SPIRVType *, 4> ParamTypes; 280 for (const auto &t : FType->params()) { 281 ParamTypes.push_back(getOrCreateSPIRVType(t, MIRBuilder)); 282 } 283 return getOpTypeFunction(RetTy, ParamTypes, MIRBuilder); 284 } 285 if (auto PType = dyn_cast<PointerType>(Ty)) { 286 SPIRVType *SpvElementType; 287 // At the moment, all opaque pointers correspond to i8 element type. 288 // TODO: change the implementation once opaque pointers are supported 289 // in the SPIR-V specification. 290 if (PType->isOpaque()) { 291 SpvElementType = getOrCreateSPIRVIntegerType(8, MIRBuilder); 292 } else { 293 Type *ElemType = PType->getNonOpaquePointerElementType(); 294 // TODO: support OpenCL and SPIRV builtins like image2d_t that are passed 295 // as pointers, but should be treated as custom types like OpTypeImage. 296 assert(!isa<StructType>(ElemType) && "Unsupported StructType pointer"); 297 298 // Otherwise, treat it as a regular pointer type. 299 SpvElementType = getOrCreateSPIRVType( 300 ElemType, MIRBuilder, SPIRV::AccessQualifier::ReadWrite, EmitIR); 301 } 302 auto SC = addressSpaceToStorageClass(PType->getAddressSpace()); 303 return getOpTypePointer(SC, SpvElementType, MIRBuilder); 304 } 305 llvm_unreachable("Unable to convert LLVM type to SPIRVType"); 306 } 307 308 SPIRVType *SPIRVGlobalRegistry::getSPIRVTypeForVReg(Register VReg) const { 309 auto t = VRegToTypeMap.find(CurMF); 310 if (t != VRegToTypeMap.end()) { 311 auto tt = t->second.find(VReg); 312 if (tt != t->second.end()) 313 return tt->second; 314 } 315 return nullptr; 316 } 317 318 SPIRVType *SPIRVGlobalRegistry::getOrCreateSPIRVType( 319 const Type *Type, MachineIRBuilder &MIRBuilder, 320 SPIRV::AccessQualifier AccessQual, bool EmitIR) { 321 SPIRVType *SpirvType = createSPIRVType(Type, MIRBuilder, AccessQual, EmitIR); 322 VRegToTypeMap[&MIRBuilder.getMF()][getSPIRVTypeID(SpirvType)] = SpirvType; 323 SPIRVToLLVMType[SpirvType] = Type; 324 return SpirvType; 325 } 326 327 bool SPIRVGlobalRegistry::isScalarOfType(Register VReg, 328 unsigned TypeOpcode) const { 329 SPIRVType *Type = getSPIRVTypeForVReg(VReg); 330 assert(Type && "isScalarOfType VReg has no type assigned"); 331 return Type->getOpcode() == TypeOpcode; 332 } 333 334 bool SPIRVGlobalRegistry::isScalarOrVectorOfType(Register VReg, 335 unsigned TypeOpcode) const { 336 SPIRVType *Type = getSPIRVTypeForVReg(VReg); 337 assert(Type && "isScalarOrVectorOfType VReg has no type assigned"); 338 if (Type->getOpcode() == TypeOpcode) 339 return true; 340 if (Type->getOpcode() == SPIRV::OpTypeVector) { 341 Register ScalarTypeVReg = Type->getOperand(1).getReg(); 342 SPIRVType *ScalarType = getSPIRVTypeForVReg(ScalarTypeVReg); 343 return ScalarType->getOpcode() == TypeOpcode; 344 } 345 return false; 346 } 347 348 unsigned 349 SPIRVGlobalRegistry::getScalarOrVectorBitWidth(const SPIRVType *Type) const { 350 assert(Type && "Invalid Type pointer"); 351 if (Type->getOpcode() == SPIRV::OpTypeVector) { 352 auto EleTypeReg = Type->getOperand(1).getReg(); 353 Type = getSPIRVTypeForVReg(EleTypeReg); 354 } 355 if (Type->getOpcode() == SPIRV::OpTypeInt || 356 Type->getOpcode() == SPIRV::OpTypeFloat) 357 return Type->getOperand(1).getImm(); 358 if (Type->getOpcode() == SPIRV::OpTypeBool) 359 return 1; 360 llvm_unreachable("Attempting to get bit width of non-integer/float type."); 361 } 362 363 bool SPIRVGlobalRegistry::isScalarOrVectorSigned(const SPIRVType *Type) const { 364 assert(Type && "Invalid Type pointer"); 365 if (Type->getOpcode() == SPIRV::OpTypeVector) { 366 auto EleTypeReg = Type->getOperand(1).getReg(); 367 Type = getSPIRVTypeForVReg(EleTypeReg); 368 } 369 if (Type->getOpcode() == SPIRV::OpTypeInt) 370 return Type->getOperand(2).getImm() != 0; 371 llvm_unreachable("Attempting to get sign of non-integer type."); 372 } 373 374 SPIRV::StorageClass 375 SPIRVGlobalRegistry::getPointerStorageClass(Register VReg) const { 376 SPIRVType *Type = getSPIRVTypeForVReg(VReg); 377 assert(Type && Type->getOpcode() == SPIRV::OpTypePointer && 378 Type->getOperand(1).isImm() && "Pointer type is expected"); 379 return static_cast<SPIRV::StorageClass>(Type->getOperand(1).getImm()); 380 } 381 382 SPIRVType * 383 SPIRVGlobalRegistry::getOrCreateSPIRVIntegerType(unsigned BitWidth, 384 MachineIRBuilder &MIRBuilder) { 385 return getOrCreateSPIRVType( 386 IntegerType::get(MIRBuilder.getMF().getFunction().getContext(), BitWidth), 387 MIRBuilder); 388 } 389 390 SPIRVType *SPIRVGlobalRegistry::restOfCreateSPIRVType(Type *LLVMTy, 391 MachineInstrBuilder MIB) { 392 SPIRVType *SpirvType = MIB; 393 VRegToTypeMap[CurMF][getSPIRVTypeID(SpirvType)] = SpirvType; 394 SPIRVToLLVMType[SpirvType] = LLVMTy; 395 return SpirvType; 396 } 397 398 SPIRVType *SPIRVGlobalRegistry::getOrCreateSPIRVIntegerType( 399 unsigned BitWidth, MachineInstr &I, const SPIRVInstrInfo &TII) { 400 Type *LLVMTy = IntegerType::get(CurMF->getFunction().getContext(), BitWidth); 401 MachineBasicBlock &BB = *I.getParent(); 402 auto MIB = BuildMI(BB, I, I.getDebugLoc(), TII.get(SPIRV::OpTypeInt)) 403 .addDef(createTypeVReg(CurMF->getRegInfo())) 404 .addImm(BitWidth) 405 .addImm(0); 406 return restOfCreateSPIRVType(LLVMTy, MIB); 407 } 408 409 SPIRVType * 410 SPIRVGlobalRegistry::getOrCreateSPIRVBoolType(MachineIRBuilder &MIRBuilder) { 411 return getOrCreateSPIRVType( 412 IntegerType::get(MIRBuilder.getMF().getFunction().getContext(), 1), 413 MIRBuilder); 414 } 415 416 SPIRVType *SPIRVGlobalRegistry::getOrCreateSPIRVVectorType( 417 SPIRVType *BaseType, unsigned NumElements, MachineIRBuilder &MIRBuilder) { 418 return getOrCreateSPIRVType( 419 FixedVectorType::get(const_cast<Type *>(getTypeForSPIRVType(BaseType)), 420 NumElements), 421 MIRBuilder); 422 } 423 424 SPIRVType *SPIRVGlobalRegistry::getOrCreateSPIRVVectorType( 425 SPIRVType *BaseType, unsigned NumElements, MachineInstr &I, 426 const SPIRVInstrInfo &TII) { 427 Type *LLVMTy = FixedVectorType::get( 428 const_cast<Type *>(getTypeForSPIRVType(BaseType)), NumElements); 429 MachineBasicBlock &BB = *I.getParent(); 430 auto MIB = BuildMI(BB, I, I.getDebugLoc(), TII.get(SPIRV::OpTypeVector)) 431 .addDef(createTypeVReg(CurMF->getRegInfo())) 432 .addUse(getSPIRVTypeID(BaseType)) 433 .addImm(NumElements); 434 return restOfCreateSPIRVType(LLVMTy, MIB); 435 } 436 437 SPIRVType * 438 SPIRVGlobalRegistry::getOrCreateSPIRVPointerType(SPIRVType *BaseType, 439 MachineIRBuilder &MIRBuilder, 440 SPIRV::StorageClass SClass) { 441 return getOrCreateSPIRVType( 442 PointerType::get(const_cast<Type *>(getTypeForSPIRVType(BaseType)), 443 storageClassToAddressSpace(SClass)), 444 MIRBuilder); 445 } 446 447 SPIRVType *SPIRVGlobalRegistry::getOrCreateSPIRVPointerType( 448 SPIRVType *BaseType, MachineInstr &I, const SPIRVInstrInfo &TII, 449 SPIRV::StorageClass SC) { 450 Type *LLVMTy = 451 PointerType::get(const_cast<Type *>(getTypeForSPIRVType(BaseType)), 452 storageClassToAddressSpace(SC)); 453 MachineBasicBlock &BB = *I.getParent(); 454 auto MIB = BuildMI(BB, I, I.getDebugLoc(), TII.get(SPIRV::OpTypePointer)) 455 .addDef(createTypeVReg(CurMF->getRegInfo())) 456 .addImm(static_cast<uint32_t>(SC)) 457 .addUse(getSPIRVTypeID(BaseType)); 458 return restOfCreateSPIRVType(LLVMTy, MIB); 459 } 460