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