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