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