xref: /freebsd-src/contrib/llvm-project/llvm/lib/Target/SPIRV/SPIRVGlobalRegistry.h (revision 0fca6ea1d4eea4c934cfff25ac9ee8ad6fe95583)
181ad6265SDimitry Andric //===-- SPIRVGlobalRegistry.h - SPIR-V Global Registry ----------*- C++ -*-===//
281ad6265SDimitry Andric //
381ad6265SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
481ad6265SDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
581ad6265SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
681ad6265SDimitry Andric //
781ad6265SDimitry Andric //===----------------------------------------------------------------------===//
881ad6265SDimitry Andric //
981ad6265SDimitry Andric // SPIRVGlobalRegistry is used to maintain rich type information required for
1081ad6265SDimitry Andric // SPIR-V even after lowering from LLVM IR to GMIR. It can convert an llvm::Type
1181ad6265SDimitry Andric // into an OpTypeXXX instruction, and map it to a virtual register. Also it
1281ad6265SDimitry Andric // builds and supports consistency of constants and global variables.
1381ad6265SDimitry Andric //
1481ad6265SDimitry Andric //===----------------------------------------------------------------------===//
1581ad6265SDimitry Andric 
1681ad6265SDimitry Andric #ifndef LLVM_LIB_TARGET_SPIRV_SPIRVTYPEMANAGER_H
1781ad6265SDimitry Andric #define LLVM_LIB_TARGET_SPIRV_SPIRVTYPEMANAGER_H
1881ad6265SDimitry Andric 
1981ad6265SDimitry Andric #include "MCTargetDesc/SPIRVBaseInfo.h"
20753f127fSDimitry Andric #include "SPIRVDuplicatesTracker.h"
2181ad6265SDimitry Andric #include "SPIRVInstrInfo.h"
2281ad6265SDimitry Andric #include "llvm/CodeGen/GlobalISel/MachineIRBuilder.h"
23*0fca6ea1SDimitry Andric #include "llvm/IR/Constant.h"
24*0fca6ea1SDimitry Andric #include "llvm/IR/TypedPointerType.h"
2581ad6265SDimitry Andric 
2681ad6265SDimitry Andric namespace llvm {
27*0fca6ea1SDimitry Andric class SPIRVSubtarget;
2881ad6265SDimitry Andric using SPIRVType = const MachineInstr;
2981ad6265SDimitry Andric 
3081ad6265SDimitry Andric class SPIRVGlobalRegistry {
3181ad6265SDimitry Andric   // Registers holding values which have types associated with them.
3281ad6265SDimitry Andric   // Initialized upon VReg definition in IRTranslator.
3381ad6265SDimitry Andric   // Do not confuse this with DuplicatesTracker as DT maps Type* to <MF, Reg>
3481ad6265SDimitry Andric   // where Reg = OpType...
3581ad6265SDimitry Andric   // while VRegToTypeMap tracks SPIR-V type assigned to other regs (i.e. not
36fcaf7f86SDimitry Andric   // type-declaring ones).
37753f127fSDimitry Andric   DenseMap<const MachineFunction *, DenseMap<Register, SPIRVType *>>
38753f127fSDimitry Andric       VRegToTypeMap;
39753f127fSDimitry Andric 
40*0fca6ea1SDimitry Andric   // Map LLVM Type* to <MF, Reg>
41753f127fSDimitry Andric   SPIRVGeneralDuplicatesTracker DT;
4281ad6265SDimitry Andric 
4381ad6265SDimitry Andric   DenseMap<SPIRVType *, const Type *> SPIRVToLLVMType;
4481ad6265SDimitry Andric 
45*0fca6ea1SDimitry Andric   // map a Function to its definition (as a machine instruction operand)
46*0fca6ea1SDimitry Andric   DenseMap<const Function *, const MachineOperand *> FunctionToInstr;
47*0fca6ea1SDimitry Andric   DenseMap<const MachineInstr *, const Function *> FunctionToInstrRev;
48*0fca6ea1SDimitry Andric   // map function pointer (as a machine instruction operand) to the used
49*0fca6ea1SDimitry Andric   // Function
50*0fca6ea1SDimitry Andric   DenseMap<const MachineOperand *, const Function *> InstrToFunction;
51*0fca6ea1SDimitry Andric   // Maps Functions to their calls (in a form of the machine instruction,
52*0fca6ea1SDimitry Andric   // OpFunctionCall) that happened before the definition is available
53*0fca6ea1SDimitry Andric   DenseMap<const Function *, SmallPtrSet<MachineInstr *, 8>> ForwardCalls;
54*0fca6ea1SDimitry Andric   // map a Function to its original return type before the clone function was
55*0fca6ea1SDimitry Andric   // created during substitution of aggregate arguments
56*0fca6ea1SDimitry Andric   // (see `SPIRVPrepareFunctions::removeAggregateTypesFromSignature()`)
57*0fca6ea1SDimitry Andric   DenseMap<Value *, Type *> MutatedAggRet;
58*0fca6ea1SDimitry Andric 
59bdd1243dSDimitry Andric   // Look for an equivalent of the newType in the map. Return the equivalent
60bdd1243dSDimitry Andric   // if it's found, otherwise insert newType to the map and return the type.
61bdd1243dSDimitry Andric   const MachineInstr *checkSpecialInstr(const SPIRV::SpecialTypeDescriptor &TD,
62bdd1243dSDimitry Andric                                         MachineIRBuilder &MIRBuilder);
63bdd1243dSDimitry Andric 
64fcaf7f86SDimitry Andric   SmallPtrSet<const Type *, 4> TypesInProcessing;
65fcaf7f86SDimitry Andric   DenseMap<const Type *, SPIRVType *> ForwardPointerTypes;
66fcaf7f86SDimitry Andric 
67*0fca6ea1SDimitry Andric   // if a function returns a pointer, this is to map it into TypedPointerType
68*0fca6ea1SDimitry Andric   DenseMap<const Function *, TypedPointerType *> FunResPointerTypes;
69*0fca6ea1SDimitry Andric 
7081ad6265SDimitry Andric   // Number of bits pointers and size_t integers require.
7181ad6265SDimitry Andric   const unsigned PointerSize;
7281ad6265SDimitry Andric 
73*0fca6ea1SDimitry Andric   // Holds the maximum ID we have in the module.
74*0fca6ea1SDimitry Andric   unsigned Bound;
75*0fca6ea1SDimitry Andric 
76*0fca6ea1SDimitry Andric   // Maps values associated with untyped pointers into deduced element types of
77*0fca6ea1SDimitry Andric   // untyped pointers.
78*0fca6ea1SDimitry Andric   DenseMap<Value *, Type *> DeducedElTys;
79*0fca6ea1SDimitry Andric   // Maps composite values to deduced types where untyped pointers are replaced
80*0fca6ea1SDimitry Andric   // with typed ones.
81*0fca6ea1SDimitry Andric   DenseMap<Value *, Type *> DeducedNestedTys;
82*0fca6ea1SDimitry Andric   // Maps values to "assign type" calls, thus being a registry of created
83*0fca6ea1SDimitry Andric   // Intrinsic::spv_assign_ptr_type instructions.
84*0fca6ea1SDimitry Andric   DenseMap<Value *, CallInst *> AssignPtrTypeInstr;
85*0fca6ea1SDimitry Andric 
8681ad6265SDimitry Andric   // Add a new OpTypeXXX instruction without checking for duplicates.
87bdd1243dSDimitry Andric   SPIRVType *createSPIRVType(const Type *Type, MachineIRBuilder &MIRBuilder,
88bdd1243dSDimitry Andric                              SPIRV::AccessQualifier::AccessQualifier AQ =
89bdd1243dSDimitry Andric                                  SPIRV::AccessQualifier::ReadWrite,
90bdd1243dSDimitry Andric                              bool EmitIR = true);
91bdd1243dSDimitry Andric   SPIRVType *findSPIRVType(const Type *Ty, MachineIRBuilder &MIRBuilder,
92bdd1243dSDimitry Andric                            SPIRV::AccessQualifier::AccessQualifier accessQual =
93bdd1243dSDimitry Andric                                SPIRV::AccessQualifier::ReadWrite,
94bdd1243dSDimitry Andric                            bool EmitIR = true);
9581ad6265SDimitry Andric   SPIRVType *
96bdd1243dSDimitry Andric   restOfCreateSPIRVType(const Type *Type, MachineIRBuilder &MIRBuilder,
97bdd1243dSDimitry Andric                         SPIRV::AccessQualifier::AccessQualifier AccessQual,
98fcaf7f86SDimitry Andric                         bool EmitIR);
9981ad6265SDimitry Andric 
10081ad6265SDimitry Andric public:
10181ad6265SDimitry Andric   SPIRVGlobalRegistry(unsigned PointerSize);
10281ad6265SDimitry Andric 
10381ad6265SDimitry Andric   MachineFunction *CurMF;
10481ad6265SDimitry Andric 
105753f127fSDimitry Andric   void add(const Constant *C, MachineFunction *MF, Register R) {
106753f127fSDimitry Andric     DT.add(C, MF, R);
107753f127fSDimitry Andric   }
108753f127fSDimitry Andric 
109753f127fSDimitry Andric   void add(const GlobalVariable *GV, MachineFunction *MF, Register R) {
110753f127fSDimitry Andric     DT.add(GV, MF, R);
111753f127fSDimitry Andric   }
112753f127fSDimitry Andric 
113753f127fSDimitry Andric   void add(const Function *F, MachineFunction *MF, Register R) {
114753f127fSDimitry Andric     DT.add(F, MF, R);
115753f127fSDimitry Andric   }
116753f127fSDimitry Andric 
117753f127fSDimitry Andric   void add(const Argument *Arg, MachineFunction *MF, Register R) {
118753f127fSDimitry Andric     DT.add(Arg, MF, R);
119753f127fSDimitry Andric   }
120753f127fSDimitry Andric 
121*0fca6ea1SDimitry Andric   void add(const MachineInstr *MI, MachineFunction *MF, Register R) {
122*0fca6ea1SDimitry Andric     DT.add(MI, MF, R);
123*0fca6ea1SDimitry Andric   }
124*0fca6ea1SDimitry Andric 
125*0fca6ea1SDimitry Andric   Register find(const MachineInstr *MI, MachineFunction *MF) {
126*0fca6ea1SDimitry Andric     return DT.find(MI, MF);
127*0fca6ea1SDimitry Andric   }
128*0fca6ea1SDimitry Andric 
129753f127fSDimitry Andric   Register find(const Constant *C, MachineFunction *MF) {
130753f127fSDimitry Andric     return DT.find(C, MF);
131753f127fSDimitry Andric   }
132753f127fSDimitry Andric 
133753f127fSDimitry Andric   Register find(const GlobalVariable *GV, MachineFunction *MF) {
134753f127fSDimitry Andric     return DT.find(GV, MF);
135753f127fSDimitry Andric   }
136753f127fSDimitry Andric 
137753f127fSDimitry Andric   Register find(const Function *F, MachineFunction *MF) {
138753f127fSDimitry Andric     return DT.find(F, MF);
139753f127fSDimitry Andric   }
140753f127fSDimitry Andric 
141753f127fSDimitry Andric   void buildDepsGraph(std::vector<SPIRV::DTSortableEntry *> &Graph,
142753f127fSDimitry Andric                       MachineModuleInfo *MMI = nullptr) {
143753f127fSDimitry Andric     DT.buildDepsGraph(Graph, MMI);
144753f127fSDimitry Andric   }
145753f127fSDimitry Andric 
146*0fca6ea1SDimitry Andric   void setBound(unsigned V) { Bound = V; }
147*0fca6ea1SDimitry Andric   unsigned getBound() { return Bound; }
148*0fca6ea1SDimitry Andric 
149*0fca6ea1SDimitry Andric   // Add a record to the map of function return pointer types.
150*0fca6ea1SDimitry Andric   void addReturnType(const Function *ArgF, TypedPointerType *DerivedTy) {
151*0fca6ea1SDimitry Andric     FunResPointerTypes[ArgF] = DerivedTy;
152*0fca6ea1SDimitry Andric   }
153*0fca6ea1SDimitry Andric   // Find a record in the map of function return pointer types.
154*0fca6ea1SDimitry Andric   const TypedPointerType *findReturnType(const Function *ArgF) {
155*0fca6ea1SDimitry Andric     auto It = FunResPointerTypes.find(ArgF);
156*0fca6ea1SDimitry Andric     return It == FunResPointerTypes.end() ? nullptr : It->second;
157*0fca6ea1SDimitry Andric   }
158*0fca6ea1SDimitry Andric 
159*0fca6ea1SDimitry Andric   // A registry of "assign type" records:
160*0fca6ea1SDimitry Andric   // - Add a record.
161*0fca6ea1SDimitry Andric   void addAssignPtrTypeInstr(Value *Val, CallInst *AssignPtrTyCI) {
162*0fca6ea1SDimitry Andric     AssignPtrTypeInstr[Val] = AssignPtrTyCI;
163*0fca6ea1SDimitry Andric   }
164*0fca6ea1SDimitry Andric   // - Find a record.
165*0fca6ea1SDimitry Andric   CallInst *findAssignPtrTypeInstr(const Value *Val) {
166*0fca6ea1SDimitry Andric     auto It = AssignPtrTypeInstr.find(Val);
167*0fca6ea1SDimitry Andric     return It == AssignPtrTypeInstr.end() ? nullptr : It->second;
168*0fca6ea1SDimitry Andric   }
169*0fca6ea1SDimitry Andric 
170*0fca6ea1SDimitry Andric   // A registry of mutated values
171*0fca6ea1SDimitry Andric   // (see `SPIRVPrepareFunctions::removeAggregateTypesFromSignature()`):
172*0fca6ea1SDimitry Andric   // - Add a record.
173*0fca6ea1SDimitry Andric   void addMutated(Value *Val, Type *Ty) { MutatedAggRet[Val] = Ty; }
174*0fca6ea1SDimitry Andric   // - Find a record.
175*0fca6ea1SDimitry Andric   Type *findMutated(const Value *Val) {
176*0fca6ea1SDimitry Andric     auto It = MutatedAggRet.find(Val);
177*0fca6ea1SDimitry Andric     return It == MutatedAggRet.end() ? nullptr : It->second;
178*0fca6ea1SDimitry Andric   }
179*0fca6ea1SDimitry Andric 
180*0fca6ea1SDimitry Andric   // Deduced element types of untyped pointers and composites:
181*0fca6ea1SDimitry Andric   // - Add a record to the map of deduced element types.
182*0fca6ea1SDimitry Andric   void addDeducedElementType(Value *Val, Type *Ty) { DeducedElTys[Val] = Ty; }
183*0fca6ea1SDimitry Andric   // - Find a record in the map of deduced element types.
184*0fca6ea1SDimitry Andric   Type *findDeducedElementType(const Value *Val) {
185*0fca6ea1SDimitry Andric     auto It = DeducedElTys.find(Val);
186*0fca6ea1SDimitry Andric     return It == DeducedElTys.end() ? nullptr : It->second;
187*0fca6ea1SDimitry Andric   }
188*0fca6ea1SDimitry Andric   // - Add a record to the map of deduced composite types.
189*0fca6ea1SDimitry Andric   void addDeducedCompositeType(Value *Val, Type *Ty) {
190*0fca6ea1SDimitry Andric     DeducedNestedTys[Val] = Ty;
191*0fca6ea1SDimitry Andric   }
192*0fca6ea1SDimitry Andric   // - Find a record in the map of deduced composite types.
193*0fca6ea1SDimitry Andric   Type *findDeducedCompositeType(const Value *Val) {
194*0fca6ea1SDimitry Andric     auto It = DeducedNestedTys.find(Val);
195*0fca6ea1SDimitry Andric     return It == DeducedNestedTys.end() ? nullptr : It->second;
196*0fca6ea1SDimitry Andric   }
197*0fca6ea1SDimitry Andric   // - Find a type of the given Global value
198*0fca6ea1SDimitry Andric   Type *getDeducedGlobalValueType(const GlobalValue *Global) {
199*0fca6ea1SDimitry Andric     // we may know element type if it was deduced earlier
200*0fca6ea1SDimitry Andric     Type *ElementTy = findDeducedElementType(Global);
201*0fca6ea1SDimitry Andric     if (!ElementTy) {
202*0fca6ea1SDimitry Andric       // or we may know element type if it's associated with a composite
203*0fca6ea1SDimitry Andric       // value
204*0fca6ea1SDimitry Andric       if (Value *GlobalElem =
205*0fca6ea1SDimitry Andric               Global->getNumOperands() > 0 ? Global->getOperand(0) : nullptr)
206*0fca6ea1SDimitry Andric         ElementTy = findDeducedCompositeType(GlobalElem);
207*0fca6ea1SDimitry Andric     }
208*0fca6ea1SDimitry Andric     return ElementTy ? ElementTy : Global->getValueType();
209*0fca6ea1SDimitry Andric   }
210*0fca6ea1SDimitry Andric 
211*0fca6ea1SDimitry Andric   // Map a machine operand that represents a use of a function via function
212*0fca6ea1SDimitry Andric   // pointer to a machine operand that represents the function definition.
213*0fca6ea1SDimitry Andric   // Return either the register or invalid value, because we have no context for
214*0fca6ea1SDimitry Andric   // a good diagnostic message in case of unexpectedly missing references.
215*0fca6ea1SDimitry Andric   const MachineOperand *getFunctionDefinitionByUse(const MachineOperand *Use) {
216*0fca6ea1SDimitry Andric     auto ResF = InstrToFunction.find(Use);
217*0fca6ea1SDimitry Andric     if (ResF == InstrToFunction.end())
218*0fca6ea1SDimitry Andric       return nullptr;
219*0fca6ea1SDimitry Andric     auto ResReg = FunctionToInstr.find(ResF->second);
220*0fca6ea1SDimitry Andric     return ResReg == FunctionToInstr.end() ? nullptr : ResReg->second;
221*0fca6ea1SDimitry Andric   }
222*0fca6ea1SDimitry Andric 
223*0fca6ea1SDimitry Andric   // Map a Function to a machine instruction that represents the function
224*0fca6ea1SDimitry Andric   // definition.
225*0fca6ea1SDimitry Andric   const MachineInstr *getFunctionDefinition(const Function *F) {
226*0fca6ea1SDimitry Andric     if (!F)
227*0fca6ea1SDimitry Andric       return nullptr;
228*0fca6ea1SDimitry Andric     auto MOIt = FunctionToInstr.find(F);
229*0fca6ea1SDimitry Andric     return MOIt == FunctionToInstr.end() ? nullptr : MOIt->second->getParent();
230*0fca6ea1SDimitry Andric   }
231*0fca6ea1SDimitry Andric 
232*0fca6ea1SDimitry Andric   // Map a Function to a machine instruction that represents the function
233*0fca6ea1SDimitry Andric   // definition.
234*0fca6ea1SDimitry Andric   const Function *getFunctionByDefinition(const MachineInstr *MI) {
235*0fca6ea1SDimitry Andric     if (!MI)
236*0fca6ea1SDimitry Andric       return nullptr;
237*0fca6ea1SDimitry Andric     auto FIt = FunctionToInstrRev.find(MI);
238*0fca6ea1SDimitry Andric     return FIt == FunctionToInstrRev.end() ? nullptr : FIt->second;
239*0fca6ea1SDimitry Andric   }
240*0fca6ea1SDimitry Andric 
241*0fca6ea1SDimitry Andric   // map function pointer (as a machine instruction operand) to the used
242*0fca6ea1SDimitry Andric   // Function
243*0fca6ea1SDimitry Andric   void recordFunctionPointer(const MachineOperand *MO, const Function *F) {
244*0fca6ea1SDimitry Andric     InstrToFunction[MO] = F;
245*0fca6ea1SDimitry Andric   }
246*0fca6ea1SDimitry Andric 
247*0fca6ea1SDimitry Andric   // map a Function to its definition (as a machine instruction)
248*0fca6ea1SDimitry Andric   void recordFunctionDefinition(const Function *F, const MachineOperand *MO) {
249*0fca6ea1SDimitry Andric     FunctionToInstr[F] = MO;
250*0fca6ea1SDimitry Andric     FunctionToInstrRev[MO->getParent()] = F;
251*0fca6ea1SDimitry Andric   }
252*0fca6ea1SDimitry Andric 
253*0fca6ea1SDimitry Andric   // Return true if any OpConstantFunctionPointerINTEL were generated
254*0fca6ea1SDimitry Andric   bool hasConstFunPtr() { return !InstrToFunction.empty(); }
255*0fca6ea1SDimitry Andric 
256*0fca6ea1SDimitry Andric   // Add a record about forward function call.
257*0fca6ea1SDimitry Andric   void addForwardCall(const Function *F, MachineInstr *MI) {
258*0fca6ea1SDimitry Andric     auto It = ForwardCalls.find(F);
259*0fca6ea1SDimitry Andric     if (It == ForwardCalls.end())
260*0fca6ea1SDimitry Andric       ForwardCalls[F] = {MI};
261*0fca6ea1SDimitry Andric     else
262*0fca6ea1SDimitry Andric       It->second.insert(MI);
263*0fca6ea1SDimitry Andric   }
264*0fca6ea1SDimitry Andric 
265*0fca6ea1SDimitry Andric   // Map a Function to the vector of machine instructions that represents
266*0fca6ea1SDimitry Andric   // forward function calls or to nullptr if not found.
267*0fca6ea1SDimitry Andric   SmallPtrSet<MachineInstr *, 8> *getForwardCalls(const Function *F) {
268*0fca6ea1SDimitry Andric     auto It = ForwardCalls.find(F);
269*0fca6ea1SDimitry Andric     return It == ForwardCalls.end() ? nullptr : &It->second;
270*0fca6ea1SDimitry Andric   }
271*0fca6ea1SDimitry Andric 
27281ad6265SDimitry Andric   // Get or create a SPIR-V type corresponding the given LLVM IR type,
27381ad6265SDimitry Andric   // and map it to the given VReg by creating an ASSIGN_TYPE instruction.
274bdd1243dSDimitry Andric   SPIRVType *assignTypeToVReg(const Type *Type, Register VReg,
275bdd1243dSDimitry Andric                               MachineIRBuilder &MIRBuilder,
276bdd1243dSDimitry Andric                               SPIRV::AccessQualifier::AccessQualifier AQ =
277bdd1243dSDimitry Andric                                   SPIRV::AccessQualifier::ReadWrite,
27881ad6265SDimitry Andric                               bool EmitIR = true);
279fcaf7f86SDimitry Andric   SPIRVType *assignIntTypeToVReg(unsigned BitWidth, Register VReg,
280fcaf7f86SDimitry Andric                                  MachineInstr &I, const SPIRVInstrInfo &TII);
281*0fca6ea1SDimitry Andric   SPIRVType *assignFloatTypeToVReg(unsigned BitWidth, Register VReg,
282*0fca6ea1SDimitry Andric                                    MachineInstr &I, const SPIRVInstrInfo &TII);
283fcaf7f86SDimitry Andric   SPIRVType *assignVectTypeToVReg(SPIRVType *BaseType, unsigned NumElements,
284fcaf7f86SDimitry Andric                                   Register VReg, MachineInstr &I,
285fcaf7f86SDimitry Andric                                   const SPIRVInstrInfo &TII);
28681ad6265SDimitry Andric 
28781ad6265SDimitry Andric   // In cases where the SPIR-V type is already known, this function can be
28881ad6265SDimitry Andric   // used to map it to the given VReg via an ASSIGN_TYPE instruction.
28981ad6265SDimitry Andric   void assignSPIRVTypeToVReg(SPIRVType *Type, Register VReg,
29081ad6265SDimitry Andric                              MachineFunction &MF);
29181ad6265SDimitry Andric 
29281ad6265SDimitry Andric   // Either generate a new OpTypeXXX instruction or return an existing one
29381ad6265SDimitry Andric   // corresponding to the given LLVM IR type.
29481ad6265SDimitry Andric   // EmitIR controls if we emit GMIR or SPV constants (e.g. for array sizes)
29581ad6265SDimitry Andric   // because this method may be called from InstructionSelector and we don't
29681ad6265SDimitry Andric   // want to emit extra IR instructions there.
297bdd1243dSDimitry Andric   SPIRVType *getOrCreateSPIRVType(const Type *Type,
298bdd1243dSDimitry Andric                                   MachineIRBuilder &MIRBuilder,
299bdd1243dSDimitry Andric                                   SPIRV::AccessQualifier::AccessQualifier AQ =
300bdd1243dSDimitry Andric                                       SPIRV::AccessQualifier::ReadWrite,
30181ad6265SDimitry Andric                                   bool EmitIR = true);
30281ad6265SDimitry Andric 
30381ad6265SDimitry Andric   const Type *getTypeForSPIRVType(const SPIRVType *Ty) const {
30481ad6265SDimitry Andric     auto Res = SPIRVToLLVMType.find(Ty);
30581ad6265SDimitry Andric     assert(Res != SPIRVToLLVMType.end());
30681ad6265SDimitry Andric     return Res->second;
30781ad6265SDimitry Andric   }
30881ad6265SDimitry Andric 
309*0fca6ea1SDimitry Andric   // Return a pointee's type, or nullptr otherwise.
310*0fca6ea1SDimitry Andric   SPIRVType *getPointeeType(SPIRVType *PtrType);
311*0fca6ea1SDimitry Andric   // Return a pointee's type op code, or 0 otherwise.
312*0fca6ea1SDimitry Andric   unsigned getPointeeTypeOp(Register PtrReg);
313*0fca6ea1SDimitry Andric 
314bdd1243dSDimitry Andric   // Either generate a new OpTypeXXX instruction or return an existing one
315bdd1243dSDimitry Andric   // corresponding to the given string containing the name of the builtin type.
316*0fca6ea1SDimitry Andric   // Return nullptr if unable to recognize SPIRV type name from `TypeStr`.
3175f757f3fSDimitry Andric   SPIRVType *getOrCreateSPIRVTypeByName(
3185f757f3fSDimitry Andric       StringRef TypeStr, MachineIRBuilder &MIRBuilder,
3195f757f3fSDimitry Andric       SPIRV::StorageClass::StorageClass SC = SPIRV::StorageClass::Function,
3205f757f3fSDimitry Andric       SPIRV::AccessQualifier::AccessQualifier AQ =
3215f757f3fSDimitry Andric           SPIRV::AccessQualifier::ReadWrite);
322bdd1243dSDimitry Andric 
32381ad6265SDimitry Andric   // Return the SPIR-V type instruction corresponding to the given VReg, or
324*0fca6ea1SDimitry Andric   // nullptr if no such type instruction exists. The second argument MF
325*0fca6ea1SDimitry Andric   // allows to search for the association in a context of the machine functions
326*0fca6ea1SDimitry Andric   // than the current one, without switching between different "current" machine
327*0fca6ea1SDimitry Andric   // functions.
328*0fca6ea1SDimitry Andric   SPIRVType *getSPIRVTypeForVReg(Register VReg,
329*0fca6ea1SDimitry Andric                                  const MachineFunction *MF = nullptr) const;
33081ad6265SDimitry Andric 
33181ad6265SDimitry Andric   // Whether the given VReg has a SPIR-V type mapped to it yet.
33281ad6265SDimitry Andric   bool hasSPIRVTypeForVReg(Register VReg) const {
33381ad6265SDimitry Andric     return getSPIRVTypeForVReg(VReg) != nullptr;
33481ad6265SDimitry Andric   }
33581ad6265SDimitry Andric 
33681ad6265SDimitry Andric   // Return the VReg holding the result of the given OpTypeXXX instruction.
337fcaf7f86SDimitry Andric   Register getSPIRVTypeID(const SPIRVType *SpirvType) const;
33881ad6265SDimitry Andric 
339*0fca6ea1SDimitry Andric   // Return previous value of the current machine function
340*0fca6ea1SDimitry Andric   MachineFunction *setCurrentFunc(MachineFunction &MF) {
341*0fca6ea1SDimitry Andric     MachineFunction *Ret = CurMF;
342*0fca6ea1SDimitry Andric     CurMF = &MF;
343*0fca6ea1SDimitry Andric     return Ret;
344*0fca6ea1SDimitry Andric   }
345*0fca6ea1SDimitry Andric 
346*0fca6ea1SDimitry Andric   // Return true if the type is an aggregate type.
347*0fca6ea1SDimitry Andric   bool isAggregateType(SPIRVType *Type) const {
348*0fca6ea1SDimitry Andric     return Type && (Type->getOpcode() == SPIRV::OpTypeStruct &&
349*0fca6ea1SDimitry Andric                     Type->getOpcode() == SPIRV::OpTypeArray);
350*0fca6ea1SDimitry Andric   }
35181ad6265SDimitry Andric 
35281ad6265SDimitry Andric   // Whether the given VReg has an OpTypeXXX instruction mapped to it with the
35381ad6265SDimitry Andric   // given opcode (e.g. OpTypeFloat).
35481ad6265SDimitry Andric   bool isScalarOfType(Register VReg, unsigned TypeOpcode) const;
35581ad6265SDimitry Andric 
35681ad6265SDimitry Andric   // Return true if the given VReg's assigned SPIR-V type is either a scalar
35781ad6265SDimitry Andric   // matching the given opcode, or a vector with an element type matching that
35881ad6265SDimitry Andric   // opcode (e.g. OpTypeBool, or OpTypeVector %x 4, where %x is OpTypeBool).
35981ad6265SDimitry Andric   bool isScalarOrVectorOfType(Register VReg, unsigned TypeOpcode) const;
36081ad6265SDimitry Andric 
361*0fca6ea1SDimitry Andric   // Return number of elements in a vector if the argument is associated with
362*0fca6ea1SDimitry Andric   // a vector type. Return 1 for a scalar type, and 0 for a missing type.
363*0fca6ea1SDimitry Andric   unsigned getScalarOrVectorComponentCount(Register VReg) const;
364*0fca6ea1SDimitry Andric   unsigned getScalarOrVectorComponentCount(SPIRVType *Type) const;
365*0fca6ea1SDimitry Andric 
366*0fca6ea1SDimitry Andric   // For vectors or scalars of booleans, integers and floats, return the scalar
367*0fca6ea1SDimitry Andric   // type's bitwidth. Otherwise calls llvm_unreachable().
36881ad6265SDimitry Andric   unsigned getScalarOrVectorBitWidth(const SPIRVType *Type) const;
36981ad6265SDimitry Andric 
370*0fca6ea1SDimitry Andric   // For vectors or scalars of integers and floats, return total bitwidth of the
371*0fca6ea1SDimitry Andric   // argument. Otherwise returns 0.
372*0fca6ea1SDimitry Andric   unsigned getNumScalarOrVectorTotalBitWidth(const SPIRVType *Type) const;
373*0fca6ea1SDimitry Andric 
374*0fca6ea1SDimitry Andric   // Returns either pointer to integer type, that may be a type of vector
375*0fca6ea1SDimitry Andric   // elements or an original type, or nullptr if the argument is niether
376*0fca6ea1SDimitry Andric   // an integer scalar, nor an integer vector
377*0fca6ea1SDimitry Andric   const SPIRVType *retrieveScalarOrVectorIntType(const SPIRVType *Type) const;
378*0fca6ea1SDimitry Andric 
37981ad6265SDimitry Andric   // For integer vectors or scalars, return whether the integers are signed.
38081ad6265SDimitry Andric   bool isScalarOrVectorSigned(const SPIRVType *Type) const;
38181ad6265SDimitry Andric 
38281ad6265SDimitry Andric   // Gets the storage class of the pointer type assigned to this vreg.
383bdd1243dSDimitry Andric   SPIRV::StorageClass::StorageClass getPointerStorageClass(Register VReg) const;
38481ad6265SDimitry Andric 
38581ad6265SDimitry Andric   // Return the number of bits SPIR-V pointers and size_t variables require.
38681ad6265SDimitry Andric   unsigned getPointerSize() const { return PointerSize; }
38781ad6265SDimitry Andric 
388*0fca6ea1SDimitry Andric   // Returns true if two types are defined and are compatible in a sense of
389*0fca6ea1SDimitry Andric   // OpBitcast instruction
390*0fca6ea1SDimitry Andric   bool isBitcastCompatible(const SPIRVType *Type1,
391*0fca6ea1SDimitry Andric                            const SPIRVType *Type2) const;
392*0fca6ea1SDimitry Andric 
39381ad6265SDimitry Andric private:
39481ad6265SDimitry Andric   SPIRVType *getOpTypeBool(MachineIRBuilder &MIRBuilder);
39581ad6265SDimitry Andric 
396*0fca6ea1SDimitry Andric   const Type *adjustIntTypeByWidth(const Type *Ty) const;
397*0fca6ea1SDimitry Andric   unsigned adjustOpTypeIntWidth(unsigned Width) const;
398*0fca6ea1SDimitry Andric 
399*0fca6ea1SDimitry Andric   SPIRVType *getOpTypeInt(unsigned Width, MachineIRBuilder &MIRBuilder,
40081ad6265SDimitry Andric                           bool IsSigned = false);
40181ad6265SDimitry Andric 
40281ad6265SDimitry Andric   SPIRVType *getOpTypeFloat(uint32_t Width, MachineIRBuilder &MIRBuilder);
40381ad6265SDimitry Andric 
40481ad6265SDimitry Andric   SPIRVType *getOpTypeVoid(MachineIRBuilder &MIRBuilder);
40581ad6265SDimitry Andric 
40681ad6265SDimitry Andric   SPIRVType *getOpTypeVector(uint32_t NumElems, SPIRVType *ElemType,
40781ad6265SDimitry Andric                              MachineIRBuilder &MIRBuilder);
40881ad6265SDimitry Andric 
40981ad6265SDimitry Andric   SPIRVType *getOpTypeArray(uint32_t NumElems, SPIRVType *ElemType,
41081ad6265SDimitry Andric                             MachineIRBuilder &MIRBuilder, bool EmitIR = true);
41181ad6265SDimitry Andric 
412fcaf7f86SDimitry Andric   SPIRVType *getOpTypeOpaque(const StructType *Ty,
413fcaf7f86SDimitry Andric                              MachineIRBuilder &MIRBuilder);
414fcaf7f86SDimitry Andric 
415fcaf7f86SDimitry Andric   SPIRVType *getOpTypeStruct(const StructType *Ty, MachineIRBuilder &MIRBuilder,
416fcaf7f86SDimitry Andric                              bool EmitIR = true);
417fcaf7f86SDimitry Andric 
418bdd1243dSDimitry Andric   SPIRVType *getOpTypePointer(SPIRV::StorageClass::StorageClass SC,
419bdd1243dSDimitry Andric                               SPIRVType *ElemType, MachineIRBuilder &MIRBuilder,
420bdd1243dSDimitry Andric                               Register Reg);
421fcaf7f86SDimitry Andric 
422bdd1243dSDimitry Andric   SPIRVType *getOpTypeForwardPointer(SPIRV::StorageClass::StorageClass SC,
42381ad6265SDimitry Andric                                      MachineIRBuilder &MIRBuilder);
42481ad6265SDimitry Andric 
42581ad6265SDimitry Andric   SPIRVType *getOpTypeFunction(SPIRVType *RetType,
42681ad6265SDimitry Andric                                const SmallVectorImpl<SPIRVType *> &ArgTypes,
42781ad6265SDimitry Andric                                MachineIRBuilder &MIRBuilder);
428bdd1243dSDimitry Andric 
429bdd1243dSDimitry Andric   SPIRVType *
430bdd1243dSDimitry Andric   getOrCreateSpecialType(const Type *Ty, MachineIRBuilder &MIRBuilder,
431bdd1243dSDimitry Andric                          SPIRV::AccessQualifier::AccessQualifier AccQual);
432bdd1243dSDimitry Andric 
433fcaf7f86SDimitry Andric   std::tuple<Register, ConstantInt *, bool> getOrCreateConstIntReg(
434fcaf7f86SDimitry Andric       uint64_t Val, SPIRVType *SpvType, MachineIRBuilder *MIRBuilder,
435fcaf7f86SDimitry Andric       MachineInstr *I = nullptr, const SPIRVInstrInfo *TII = nullptr);
436*0fca6ea1SDimitry Andric   std::tuple<Register, ConstantFP *, bool, unsigned> getOrCreateConstFloatReg(
437*0fca6ea1SDimitry Andric       APFloat Val, SPIRVType *SpvType, MachineIRBuilder *MIRBuilder,
438*0fca6ea1SDimitry Andric       MachineInstr *I = nullptr, const SPIRVInstrInfo *TII = nullptr);
439fcaf7f86SDimitry Andric   SPIRVType *finishCreatingSPIRVType(const Type *LLVMTy, SPIRVType *SpirvType);
440*0fca6ea1SDimitry Andric   Register getOrCreateBaseRegister(Constant *Val, MachineInstr &I,
441bdd1243dSDimitry Andric                                    SPIRVType *SpvType,
442bdd1243dSDimitry Andric                                    const SPIRVInstrInfo &TII,
443*0fca6ea1SDimitry Andric                                    unsigned BitWidth);
444*0fca6ea1SDimitry Andric   Register getOrCreateCompositeOrNull(Constant *Val, MachineInstr &I,
445*0fca6ea1SDimitry Andric                                       SPIRVType *SpvType,
446*0fca6ea1SDimitry Andric                                       const SPIRVInstrInfo &TII, Constant *CA,
447*0fca6ea1SDimitry Andric                                       unsigned BitWidth, unsigned ElemCnt,
448*0fca6ea1SDimitry Andric                                       bool ZeroAsNull = true);
449*0fca6ea1SDimitry Andric 
450bdd1243dSDimitry Andric   Register getOrCreateIntCompositeOrNull(uint64_t Val,
451bdd1243dSDimitry Andric                                          MachineIRBuilder &MIRBuilder,
452bdd1243dSDimitry Andric                                          SPIRVType *SpvType, bool EmitIR,
453bdd1243dSDimitry Andric                                          Constant *CA, unsigned BitWidth,
454bdd1243dSDimitry Andric                                          unsigned ElemCnt);
45581ad6265SDimitry Andric 
45681ad6265SDimitry Andric public:
45781ad6265SDimitry Andric   Register buildConstantInt(uint64_t Val, MachineIRBuilder &MIRBuilder,
45881ad6265SDimitry Andric                             SPIRVType *SpvType = nullptr, bool EmitIR = true);
459fcaf7f86SDimitry Andric   Register getOrCreateConstInt(uint64_t Val, MachineInstr &I,
460*0fca6ea1SDimitry Andric                                SPIRVType *SpvType, const SPIRVInstrInfo &TII,
461*0fca6ea1SDimitry Andric                                bool ZeroAsNull = true);
462*0fca6ea1SDimitry Andric   Register getOrCreateConstFP(APFloat Val, MachineInstr &I, SPIRVType *SpvType,
463*0fca6ea1SDimitry Andric                               const SPIRVInstrInfo &TII,
464*0fca6ea1SDimitry Andric                               bool ZeroAsNull = true);
46581ad6265SDimitry Andric   Register buildConstantFP(APFloat Val, MachineIRBuilder &MIRBuilder,
46681ad6265SDimitry Andric                            SPIRVType *SpvType = nullptr);
467*0fca6ea1SDimitry Andric 
468*0fca6ea1SDimitry Andric   Register getOrCreateConstVector(uint64_t Val, MachineInstr &I,
469*0fca6ea1SDimitry Andric                                   SPIRVType *SpvType, const SPIRVInstrInfo &TII,
470*0fca6ea1SDimitry Andric                                   bool ZeroAsNull = true);
471*0fca6ea1SDimitry Andric   Register getOrCreateConstVector(APFloat Val, MachineInstr &I,
472*0fca6ea1SDimitry Andric                                   SPIRVType *SpvType, const SPIRVInstrInfo &TII,
473*0fca6ea1SDimitry Andric                                   bool ZeroAsNull = true);
474*0fca6ea1SDimitry Andric   Register getOrCreateConstIntArray(uint64_t Val, size_t Num, MachineInstr &I,
475bdd1243dSDimitry Andric                                     SPIRVType *SpvType,
476bdd1243dSDimitry Andric                                     const SPIRVInstrInfo &TII);
477bdd1243dSDimitry Andric   Register getOrCreateConsIntVector(uint64_t Val, MachineIRBuilder &MIRBuilder,
478bdd1243dSDimitry Andric                                     SPIRVType *SpvType, bool EmitIR = true);
479bdd1243dSDimitry Andric   Register getOrCreateConstNullPtr(MachineIRBuilder &MIRBuilder,
480bdd1243dSDimitry Andric                                    SPIRVType *SpvType);
481bdd1243dSDimitry Andric   Register buildConstantSampler(Register Res, unsigned AddrMode, unsigned Param,
482bdd1243dSDimitry Andric                                 unsigned FilerMode,
483bdd1243dSDimitry Andric                                 MachineIRBuilder &MIRBuilder,
484bdd1243dSDimitry Andric                                 SPIRVType *SpvType);
485fcaf7f86SDimitry Andric   Register getOrCreateUndef(MachineInstr &I, SPIRVType *SpvType,
486fcaf7f86SDimitry Andric                             const SPIRVInstrInfo &TII);
487bdd1243dSDimitry Andric   Register buildGlobalVariable(Register Reg, SPIRVType *BaseType,
488bdd1243dSDimitry Andric                                StringRef Name, const GlobalValue *GV,
489bdd1243dSDimitry Andric                                SPIRV::StorageClass::StorageClass Storage,
490bdd1243dSDimitry Andric                                const MachineInstr *Init, bool IsConst,
491bdd1243dSDimitry Andric                                bool HasLinkageTy,
492bdd1243dSDimitry Andric                                SPIRV::LinkageType::LinkageType LinkageType,
493bdd1243dSDimitry Andric                                MachineIRBuilder &MIRBuilder,
494bdd1243dSDimitry Andric                                bool IsInstSelector);
49581ad6265SDimitry Andric 
49681ad6265SDimitry Andric   // Convenient helpers for getting types with check for duplicates.
49781ad6265SDimitry Andric   SPIRVType *getOrCreateSPIRVIntegerType(unsigned BitWidth,
49881ad6265SDimitry Andric                                          MachineIRBuilder &MIRBuilder);
49981ad6265SDimitry Andric   SPIRVType *getOrCreateSPIRVIntegerType(unsigned BitWidth, MachineInstr &I,
50081ad6265SDimitry Andric                                          const SPIRVInstrInfo &TII);
501*0fca6ea1SDimitry Andric   SPIRVType *getOrCreateSPIRVType(unsigned BitWidth, MachineInstr &I,
502*0fca6ea1SDimitry Andric                                   const SPIRVInstrInfo &TII,
503*0fca6ea1SDimitry Andric                                   unsigned SPIRVOPcode, Type *LLVMTy);
504*0fca6ea1SDimitry Andric   SPIRVType *getOrCreateSPIRVFloatType(unsigned BitWidth, MachineInstr &I,
505*0fca6ea1SDimitry Andric                                        const SPIRVInstrInfo &TII);
50681ad6265SDimitry Andric   SPIRVType *getOrCreateSPIRVBoolType(MachineIRBuilder &MIRBuilder);
507fcaf7f86SDimitry Andric   SPIRVType *getOrCreateSPIRVBoolType(MachineInstr &I,
508fcaf7f86SDimitry Andric                                       const SPIRVInstrInfo &TII);
50981ad6265SDimitry Andric   SPIRVType *getOrCreateSPIRVVectorType(SPIRVType *BaseType,
51081ad6265SDimitry Andric                                         unsigned NumElements,
51181ad6265SDimitry Andric                                         MachineIRBuilder &MIRBuilder);
51281ad6265SDimitry Andric   SPIRVType *getOrCreateSPIRVVectorType(SPIRVType *BaseType,
51381ad6265SDimitry Andric                                         unsigned NumElements, MachineInstr &I,
51481ad6265SDimitry Andric                                         const SPIRVInstrInfo &TII);
515bdd1243dSDimitry Andric   SPIRVType *getOrCreateSPIRVArrayType(SPIRVType *BaseType,
516bdd1243dSDimitry Andric                                        unsigned NumElements, MachineInstr &I,
517bdd1243dSDimitry Andric                                        const SPIRVInstrInfo &TII);
518bdd1243dSDimitry Andric 
51981ad6265SDimitry Andric   SPIRVType *getOrCreateSPIRVPointerType(
52081ad6265SDimitry Andric       SPIRVType *BaseType, MachineIRBuilder &MIRBuilder,
521bdd1243dSDimitry Andric       SPIRV::StorageClass::StorageClass SClass = SPIRV::StorageClass::Function);
52281ad6265SDimitry Andric   SPIRVType *getOrCreateSPIRVPointerType(
52381ad6265SDimitry Andric       SPIRVType *BaseType, MachineInstr &I, const SPIRVInstrInfo &TII,
524bdd1243dSDimitry Andric       SPIRV::StorageClass::StorageClass SClass = SPIRV::StorageClass::Function);
525bdd1243dSDimitry Andric 
526bdd1243dSDimitry Andric   SPIRVType *
527bdd1243dSDimitry Andric   getOrCreateOpTypeImage(MachineIRBuilder &MIRBuilder, SPIRVType *SampledType,
528bdd1243dSDimitry Andric                          SPIRV::Dim::Dim Dim, uint32_t Depth, uint32_t Arrayed,
529bdd1243dSDimitry Andric                          uint32_t Multisampled, uint32_t Sampled,
530bdd1243dSDimitry Andric                          SPIRV::ImageFormat::ImageFormat ImageFormat,
531bdd1243dSDimitry Andric                          SPIRV::AccessQualifier::AccessQualifier AccQual);
532bdd1243dSDimitry Andric 
533bdd1243dSDimitry Andric   SPIRVType *getOrCreateOpTypeSampler(MachineIRBuilder &MIRBuilder);
534bdd1243dSDimitry Andric 
535bdd1243dSDimitry Andric   SPIRVType *getOrCreateOpTypeSampledImage(SPIRVType *ImageType,
536bdd1243dSDimitry Andric                                            MachineIRBuilder &MIRBuilder);
537*0fca6ea1SDimitry Andric   SPIRVType *getOrCreateOpTypeCoopMatr(MachineIRBuilder &MIRBuilder,
538*0fca6ea1SDimitry Andric                                        const TargetExtType *ExtensionType,
539*0fca6ea1SDimitry Andric                                        const SPIRVType *ElemType,
540*0fca6ea1SDimitry Andric                                        uint32_t Scope, uint32_t Rows,
541*0fca6ea1SDimitry Andric                                        uint32_t Columns, uint32_t Use);
542bdd1243dSDimitry Andric   SPIRVType *
543bdd1243dSDimitry Andric   getOrCreateOpTypePipe(MachineIRBuilder &MIRBuilder,
544bdd1243dSDimitry Andric                         SPIRV::AccessQualifier::AccessQualifier AccQual);
545bdd1243dSDimitry Andric   SPIRVType *getOrCreateOpTypeDeviceEvent(MachineIRBuilder &MIRBuilder);
546fcaf7f86SDimitry Andric   SPIRVType *getOrCreateOpTypeFunctionWithArgs(
547fcaf7f86SDimitry Andric       const Type *Ty, SPIRVType *RetType,
548fcaf7f86SDimitry Andric       const SmallVectorImpl<SPIRVType *> &ArgTypes,
549fcaf7f86SDimitry Andric       MachineIRBuilder &MIRBuilder);
550bdd1243dSDimitry Andric   SPIRVType *getOrCreateOpTypeByOpcode(const Type *Ty,
551bdd1243dSDimitry Andric                                        MachineIRBuilder &MIRBuilder,
552bdd1243dSDimitry Andric                                        unsigned Opcode);
55381ad6265SDimitry Andric };
55481ad6265SDimitry Andric } // end namespace llvm
55581ad6265SDimitry Andric #endif // LLLVM_LIB_TARGET_SPIRV_SPIRVTYPEMANAGER_H
556