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