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 "SPIRVIRMapping.h" |
21 | #include "SPIRVInstrInfo.h" |
22 | #include "llvm/CodeGen/GlobalISel/MachineIRBuilder.h" |
23 | #include "llvm/IR/Constant.h" |
24 | #include "llvm/IR/TypedPointerType.h" |
25 | |
26 | namespace llvm { |
27 | class SPIRVSubtarget; |
28 | using SPIRVType = const MachineInstr; |
29 | using StructOffsetDecorator = std::function<void(Register)>; |
30 | |
31 | class SPIRVGlobalRegistry : public SPIRVIRMapping { |
32 | // Registers holding values which have types associated with them. |
33 | // Initialized upon VReg definition in IRTranslator. |
34 | // Do not confuse this with DuplicatesTracker as DT maps Type* to <MF, Reg> |
35 | // where Reg = OpType... |
36 | // while VRegToTypeMap tracks SPIR-V type assigned to other regs (i.e. not |
37 | // type-declaring ones). |
38 | DenseMap<const MachineFunction *, DenseMap<Register, SPIRVType *>> |
39 | VRegToTypeMap; |
40 | |
41 | DenseMap<SPIRVType *, const Type *> SPIRVToLLVMType; |
42 | |
43 | // map a Function to its definition (as a machine instruction operand) |
44 | DenseMap<const Function *, const MachineOperand *> FunctionToInstr; |
45 | DenseMap<const MachineInstr *, const Function *> FunctionToInstrRev; |
46 | // map function pointer (as a machine instruction operand) to the used |
47 | // Function |
48 | DenseMap<const MachineOperand *, const Function *> InstrToFunction; |
49 | // Maps Functions to their calls (in a form of the machine instruction, |
50 | // OpFunctionCall) that happened before the definition is available |
51 | DenseMap<const Function *, SmallPtrSet<MachineInstr *, 8>> ForwardCalls; |
52 | // map a Function to its original return type before the clone function was |
53 | // created during substitution of aggregate arguments |
54 | // (see `SPIRVPrepareFunctions::removeAggregateTypesFromSignature()`) |
55 | DenseMap<Value *, Type *> MutatedAggRet; |
56 | // map an instruction to its value's attributes (type, name) |
57 | DenseMap<MachineInstr *, std::pair<Type *, std::string>> ValueAttrs; |
58 | |
59 | SmallPtrSet<const Type *, 4> TypesInProcessing; |
60 | DenseMap<const Type *, SPIRVType *> ForwardPointerTypes; |
61 | |
62 | // Stores for each function the last inserted SPIR-V Type. |
63 | // See: SPIRVGlobalRegistry::createOpType. |
64 | DenseMap<const MachineFunction *, MachineInstr *> LastInsertedTypeMap; |
65 | |
66 | // if a function returns a pointer, this is to map it into TypedPointerType |
67 | DenseMap<const Function *, TypedPointerType *> FunResPointerTypes; |
68 | |
69 | // Number of bits pointers and size_t integers require. |
70 | const unsigned PointerSize; |
71 | |
72 | // Holds the maximum ID we have in the module. |
73 | unsigned Bound; |
74 | |
75 | // Maps values associated with untyped pointers into deduced element types of |
76 | // untyped pointers. |
77 | DenseMap<Value *, Type *> DeducedElTys; |
78 | // Maps composite values to deduced types where untyped pointers are replaced |
79 | // with typed ones. |
80 | DenseMap<Value *, Type *> DeducedNestedTys; |
81 | // Maps values to "assign type" calls, thus being a registry of created |
82 | // Intrinsic::spv_assign_ptr_type instructions. |
83 | DenseMap<Value *, CallInst *> AssignPtrTypeInstr; |
84 | |
85 | // Maps OpVariable and OpFunction-related v-regs to its LLVM IR definition. |
86 | DenseMap<std::pair<const MachineFunction *, Register>, const Value *> Reg2GO; |
87 | |
88 | // map of aliasing decorations to aliasing metadata |
89 | std::unordered_map<const MDNode *, MachineInstr *> AliasInstMDMap; |
90 | |
91 | // Add a new OpTypeXXX instruction without checking for duplicates. |
92 | SPIRVType *createSPIRVType(const Type *Type, MachineIRBuilder &MIRBuilder, |
93 | SPIRV::AccessQualifier::AccessQualifier AQ, |
94 | bool ExplicitLayoutRequired, bool EmitIR); |
95 | SPIRVType *findSPIRVType(const Type *Ty, MachineIRBuilder &MIRBuilder, |
96 | SPIRV::AccessQualifier::AccessQualifier accessQual, |
97 | bool ExplicitLayoutRequired, bool EmitIR); |
98 | SPIRVType * |
99 | restOfCreateSPIRVType(const Type *Type, MachineIRBuilder &MIRBuilder, |
100 | SPIRV::AccessQualifier::AccessQualifier AccessQual, |
101 | bool ExplicitLayoutRequired, bool EmitIR); |
102 | |
103 | // Internal function creating the an OpType at the correct position in the |
104 | // function by tweaking the passed "MIRBuilder" insertion point and restoring |
105 | // it to the correct position. "Op" should be the function creating the |
106 | // specific OpType you need, and should return the newly created instruction. |
107 | SPIRVType *createOpType(MachineIRBuilder &MIRBuilder, |
108 | std::function<MachineInstr *(MachineIRBuilder &)> Op); |
109 | |
110 | public: |
111 | SPIRVGlobalRegistry(unsigned PointerSize); |
112 | |
113 | MachineFunction *CurMF; |
114 | |
115 | void setBound(unsigned V) { Bound = V; } |
116 | unsigned getBound() { return Bound; } |
117 | |
118 | void addGlobalObject(const Value *V, const MachineFunction *MF, Register R) { |
119 | Reg2GO[std::make_pair(x&: MF, y&: R)] = V; |
120 | } |
121 | const Value *getGlobalObject(const MachineFunction *MF, Register R) { |
122 | auto It = Reg2GO.find(Val: std::make_pair(x&: MF, y&: R)); |
123 | return It == Reg2GO.end() ? nullptr : It->second; |
124 | } |
125 | |
126 | // Add a record to the map of function return pointer types. |
127 | void addReturnType(const Function *ArgF, TypedPointerType *DerivedTy) { |
128 | FunResPointerTypes[ArgF] = DerivedTy; |
129 | } |
130 | // Find a record in the map of function return pointer types. |
131 | const TypedPointerType *findReturnType(const Function *ArgF) { |
132 | auto It = FunResPointerTypes.find(Val: ArgF); |
133 | return It == FunResPointerTypes.end() ? nullptr : It->second; |
134 | } |
135 | |
136 | // A registry of "assign type" records: |
137 | // - Add a record. |
138 | void addAssignPtrTypeInstr(Value *Val, CallInst *AssignPtrTyCI) { |
139 | AssignPtrTypeInstr[Val] = AssignPtrTyCI; |
140 | } |
141 | // - Find a record. |
142 | CallInst *findAssignPtrTypeInstr(const Value *Val) { |
143 | auto It = AssignPtrTypeInstr.find(Val); |
144 | return It == AssignPtrTypeInstr.end() ? nullptr : It->second; |
145 | } |
146 | // - Find a record and update its key or add a new record, if found. |
147 | void updateIfExistAssignPtrTypeInstr(Value *OldVal, Value *NewVal, |
148 | bool DeleteOld) { |
149 | if (CallInst *CI = findAssignPtrTypeInstr(Val: OldVal)) { |
150 | if (DeleteOld) |
151 | AssignPtrTypeInstr.erase(Val: OldVal); |
152 | AssignPtrTypeInstr[NewVal] = CI; |
153 | } |
154 | } |
155 | |
156 | // A registry of mutated values |
157 | // (see `SPIRVPrepareFunctions::removeAggregateTypesFromSignature()`): |
158 | // - Add a record. |
159 | void addMutated(Value *Val, Type *Ty) { MutatedAggRet[Val] = Ty; } |
160 | // - Find a record. |
161 | Type *findMutated(const Value *Val) { |
162 | auto It = MutatedAggRet.find(Val); |
163 | return It == MutatedAggRet.end() ? nullptr : It->second; |
164 | } |
165 | |
166 | // A registry of value's attributes (type, name) |
167 | // - Add a record. |
168 | void addValueAttrs(MachineInstr *Key, std::pair<Type *, std::string> Val) { |
169 | ValueAttrs[Key] = Val; |
170 | } |
171 | // - Find a record. |
172 | bool findValueAttrs(const MachineInstr *Key, Type *&Ty, StringRef &Name) { |
173 | auto It = ValueAttrs.find(Val: Key); |
174 | if (It == ValueAttrs.end()) |
175 | return false; |
176 | Ty = It->second.first; |
177 | Name = It->second.second; |
178 | return true; |
179 | } |
180 | |
181 | // Deduced element types of untyped pointers and composites: |
182 | // - Add a record to the map of deduced element types. |
183 | void addDeducedElementType(Value *Val, Type *Ty) { DeducedElTys[Val] = Ty; } |
184 | // - Find a record in the map of deduced element types. |
185 | Type *findDeducedElementType(const Value *Val) { |
186 | auto It = DeducedElTys.find(Val); |
187 | return It == DeducedElTys.end() ? nullptr : It->second; |
188 | } |
189 | // - Find a record and update its key or add a new record, if found. |
190 | void updateIfExistDeducedElementType(Value *OldVal, Value *NewVal, |
191 | bool DeleteOld) { |
192 | if (Type *Ty = findDeducedElementType(Val: OldVal)) { |
193 | if (DeleteOld) |
194 | DeducedElTys.erase(Val: OldVal); |
195 | DeducedElTys[NewVal] = Ty; |
196 | } |
197 | } |
198 | // - Add a record to the map of deduced composite types. |
199 | void addDeducedCompositeType(Value *Val, Type *Ty) { |
200 | DeducedNestedTys[Val] = Ty; |
201 | } |
202 | // - Find a record in the map of deduced composite types. |
203 | Type *findDeducedCompositeType(const Value *Val) { |
204 | auto It = DeducedNestedTys.find(Val); |
205 | return It == DeducedNestedTys.end() ? nullptr : It->second; |
206 | } |
207 | // - Find a type of the given Global value |
208 | Type *getDeducedGlobalValueType(const GlobalValue *Global) { |
209 | // we may know element type if it was deduced earlier |
210 | Type *ElementTy = findDeducedElementType(Val: Global); |
211 | if (!ElementTy) { |
212 | // or we may know element type if it's associated with a composite |
213 | // value |
214 | if (Value *GlobalElem = |
215 | Global->getNumOperands() > 0 ? Global->getOperand(i: 0) : nullptr) |
216 | ElementTy = findDeducedCompositeType(Val: GlobalElem); |
217 | } |
218 | return ElementTy ? ElementTy : Global->getValueType(); |
219 | } |
220 | |
221 | // Map a machine operand that represents a use of a function via function |
222 | // pointer to a machine operand that represents the function definition. |
223 | // Return either the register or invalid value, because we have no context for |
224 | // a good diagnostic message in case of unexpectedly missing references. |
225 | const MachineOperand *getFunctionDefinitionByUse(const MachineOperand *Use) { |
226 | auto ResF = InstrToFunction.find(Val: Use); |
227 | if (ResF == InstrToFunction.end()) |
228 | return nullptr; |
229 | auto ResReg = FunctionToInstr.find(Val: ResF->second); |
230 | return ResReg == FunctionToInstr.end() ? nullptr : ResReg->second; |
231 | } |
232 | |
233 | // Map a Function to a machine instruction that represents the function |
234 | // definition. |
235 | const MachineInstr *getFunctionDefinition(const Function *F) { |
236 | if (!F) |
237 | return nullptr; |
238 | auto MOIt = FunctionToInstr.find(Val: F); |
239 | return MOIt == FunctionToInstr.end() ? nullptr : MOIt->second->getParent(); |
240 | } |
241 | |
242 | // Map a Function to a machine instruction that represents the function |
243 | // definition. |
244 | const Function *getFunctionByDefinition(const MachineInstr *MI) { |
245 | if (!MI) |
246 | return nullptr; |
247 | auto FIt = FunctionToInstrRev.find(Val: MI); |
248 | return FIt == FunctionToInstrRev.end() ? nullptr : FIt->second; |
249 | } |
250 | |
251 | // map function pointer (as a machine instruction operand) to the used |
252 | // Function |
253 | void recordFunctionPointer(const MachineOperand *MO, const Function *F) { |
254 | InstrToFunction[MO] = F; |
255 | } |
256 | |
257 | // map a Function to its definition (as a machine instruction) |
258 | void recordFunctionDefinition(const Function *F, const MachineOperand *MO) { |
259 | FunctionToInstr[F] = MO; |
260 | FunctionToInstrRev[MO->getParent()] = F; |
261 | } |
262 | |
263 | // Return true if any OpConstantFunctionPointerINTEL were generated |
264 | bool hasConstFunPtr() { return !InstrToFunction.empty(); } |
265 | |
266 | // Add a record about forward function call. |
267 | void addForwardCall(const Function *F, MachineInstr *MI) { |
268 | ForwardCalls[F].insert(Ptr: MI); |
269 | } |
270 | |
271 | // Map a Function to the vector of machine instructions that represents |
272 | // forward function calls or to nullptr if not found. |
273 | SmallPtrSet<MachineInstr *, 8> *getForwardCalls(const Function *F) { |
274 | auto It = ForwardCalls.find(Val: F); |
275 | return It == ForwardCalls.end() ? nullptr : &It->second; |
276 | } |
277 | |
278 | // Get or create a SPIR-V type corresponding the given LLVM IR type, |
279 | // and map it to the given VReg by creating an ASSIGN_TYPE instruction. |
280 | SPIRVType *assignTypeToVReg(const Type *Type, Register VReg, |
281 | MachineIRBuilder &MIRBuilder, |
282 | SPIRV::AccessQualifier::AccessQualifier AQ, |
283 | bool EmitIR); |
284 | SPIRVType *assignIntTypeToVReg(unsigned BitWidth, Register VReg, |
285 | MachineInstr &I, const SPIRVInstrInfo &TII); |
286 | SPIRVType *assignFloatTypeToVReg(unsigned BitWidth, Register VReg, |
287 | MachineInstr &I, const SPIRVInstrInfo &TII); |
288 | SPIRVType *assignVectTypeToVReg(SPIRVType *BaseType, unsigned NumElements, |
289 | Register VReg, MachineInstr &I, |
290 | const SPIRVInstrInfo &TII); |
291 | |
292 | // In cases where the SPIR-V type is already known, this function can be |
293 | // used to map it to the given VReg via an ASSIGN_TYPE instruction. |
294 | void assignSPIRVTypeToVReg(SPIRVType *Type, Register VReg, |
295 | const MachineFunction &MF); |
296 | |
297 | // Either generate a new OpTypeXXX instruction or return an existing one |
298 | // corresponding to the given LLVM IR type. |
299 | // EmitIR controls if we emit GMIR or SPV constants (e.g. for array sizes) |
300 | // because this method may be called from InstructionSelector and we don't |
301 | // want to emit extra IR instructions there. |
302 | SPIRVType *getOrCreateSPIRVType(const Type *Type, MachineInstr &I, |
303 | SPIRV::AccessQualifier::AccessQualifier AQ, |
304 | bool EmitIR) { |
305 | MachineIRBuilder MIRBuilder(I); |
306 | return getOrCreateSPIRVType(Type, MIRBuilder, AQ, EmitIR); |
307 | } |
308 | |
309 | SPIRVType *getOrCreateSPIRVType(const Type *Type, |
310 | MachineIRBuilder &MIRBuilder, |
311 | SPIRV::AccessQualifier::AccessQualifier AQ, |
312 | bool EmitIR) { |
313 | return getOrCreateSPIRVType(Type, MIRBuilder, AQ, ExplicitLayoutRequired: false, EmitIR); |
314 | } |
315 | |
316 | const Type *getTypeForSPIRVType(const SPIRVType *Ty) const { |
317 | auto Res = SPIRVToLLVMType.find(Val: Ty); |
318 | assert(Res != SPIRVToLLVMType.end()); |
319 | return Res->second; |
320 | } |
321 | |
322 | // Return a pointee's type, or nullptr otherwise. |
323 | SPIRVType *getPointeeType(SPIRVType *PtrType); |
324 | // Return a pointee's type op code, or 0 otherwise. |
325 | unsigned getPointeeTypeOp(Register PtrReg); |
326 | |
327 | // Either generate a new OpTypeXXX instruction or return an existing one |
328 | // corresponding to the given string containing the name of the builtin type. |
329 | // Return nullptr if unable to recognize SPIRV type name from `TypeStr`. |
330 | SPIRVType *getOrCreateSPIRVTypeByName( |
331 | StringRef TypeStr, MachineIRBuilder &MIRBuilder, bool EmitIR, |
332 | SPIRV::StorageClass::StorageClass SC = SPIRV::StorageClass::Function, |
333 | SPIRV::AccessQualifier::AccessQualifier AQ = |
334 | SPIRV::AccessQualifier::ReadWrite); |
335 | |
336 | // Return the SPIR-V type instruction corresponding to the given VReg, or |
337 | // nullptr if no such type instruction exists. The second argument MF |
338 | // allows to search for the association in a context of the machine functions |
339 | // than the current one, without switching between different "current" machine |
340 | // functions. |
341 | SPIRVType *getSPIRVTypeForVReg(Register VReg, |
342 | const MachineFunction *MF = nullptr) const; |
343 | |
344 | // Return the result type of the instruction defining the register. |
345 | SPIRVType *getResultType(Register VReg, MachineFunction *MF = nullptr); |
346 | |
347 | // Whether the given VReg has a SPIR-V type mapped to it yet. |
348 | bool hasSPIRVTypeForVReg(Register VReg) const { |
349 | return getSPIRVTypeForVReg(VReg) != nullptr; |
350 | } |
351 | |
352 | // Return the VReg holding the result of the given OpTypeXXX instruction. |
353 | Register getSPIRVTypeID(const SPIRVType *SpirvType) const; |
354 | |
355 | // Return previous value of the current machine function |
356 | MachineFunction *setCurrentFunc(MachineFunction &MF) { |
357 | MachineFunction *Ret = CurMF; |
358 | CurMF = &MF; |
359 | return Ret; |
360 | } |
361 | |
362 | // Return true if the type is an aggregate type. |
363 | bool isAggregateType(SPIRVType *Type) const { |
364 | return Type && (Type->getOpcode() == SPIRV::OpTypeStruct && |
365 | Type->getOpcode() == SPIRV::OpTypeArray); |
366 | } |
367 | |
368 | // Whether the given VReg has an OpTypeXXX instruction mapped to it with the |
369 | // given opcode (e.g. OpTypeFloat). |
370 | bool isScalarOfType(Register VReg, unsigned TypeOpcode) const; |
371 | |
372 | // Return true if the given VReg's assigned SPIR-V type is either a scalar |
373 | // matching the given opcode, or a vector with an element type matching that |
374 | // opcode (e.g. OpTypeBool, or OpTypeVector %x 4, where %x is OpTypeBool). |
375 | bool isScalarOrVectorOfType(Register VReg, unsigned TypeOpcode) const; |
376 | |
377 | // Returns true if `Type` is a resource type. This could be an image type |
378 | // or a struct for a buffer decorated with the block decoration. |
379 | bool isResourceType(SPIRVType *Type) const; |
380 | |
381 | // Return number of elements in a vector if the argument is associated with |
382 | // a vector type. Return 1 for a scalar type, and 0 for a missing type. |
383 | unsigned getScalarOrVectorComponentCount(Register VReg) const; |
384 | unsigned getScalarOrVectorComponentCount(SPIRVType *Type) const; |
385 | |
386 | // Return the component type in a vector if the argument is associated with |
387 | // a vector type. Returns the argument itself for other types, and nullptr |
388 | // for a missing type. |
389 | SPIRVType *getScalarOrVectorComponentType(Register VReg) const; |
390 | SPIRVType *getScalarOrVectorComponentType(SPIRVType *Type) const; |
391 | |
392 | // For vectors or scalars of booleans, integers and floats, return the scalar |
393 | // type's bitwidth. Otherwise calls llvm_unreachable(). |
394 | unsigned getScalarOrVectorBitWidth(const SPIRVType *Type) const; |
395 | |
396 | // For vectors or scalars of integers and floats, return total bitwidth of the |
397 | // argument. Otherwise returns 0. |
398 | unsigned getNumScalarOrVectorTotalBitWidth(const SPIRVType *Type) const; |
399 | |
400 | // Returns either pointer to integer type, that may be a type of vector |
401 | // elements or an original type, or nullptr if the argument is niether |
402 | // an integer scalar, nor an integer vector |
403 | const SPIRVType *retrieveScalarOrVectorIntType(const SPIRVType *Type) const; |
404 | |
405 | // For integer vectors or scalars, return whether the integers are signed. |
406 | bool isScalarOrVectorSigned(const SPIRVType *Type) const; |
407 | |
408 | // Gets the storage class of the pointer type assigned to this vreg. |
409 | SPIRV::StorageClass::StorageClass getPointerStorageClass(Register VReg) const; |
410 | SPIRV::StorageClass::StorageClass |
411 | getPointerStorageClass(const SPIRVType *Type) const; |
412 | |
413 | // Return the number of bits SPIR-V pointers and size_t variables require. |
414 | unsigned getPointerSize() const { return PointerSize; } |
415 | |
416 | // Returns true if two types are defined and are compatible in a sense of |
417 | // OpBitcast instruction |
418 | bool isBitcastCompatible(const SPIRVType *Type1, |
419 | const SPIRVType *Type2) const; |
420 | |
421 | // Informs about removal of the machine instruction and invalidates data |
422 | // structures referring this instruction. |
423 | void invalidateMachineInstr(MachineInstr *MI); |
424 | |
425 | private: |
426 | SPIRVType *getOpTypeBool(MachineIRBuilder &MIRBuilder); |
427 | |
428 | const Type *adjustIntTypeByWidth(const Type *Ty) const; |
429 | unsigned adjustOpTypeIntWidth(unsigned Width) const; |
430 | |
431 | SPIRVType *getOrCreateSPIRVType(const Type *Type, |
432 | MachineIRBuilder &MIRBuilder, |
433 | SPIRV::AccessQualifier::AccessQualifier AQ, |
434 | bool ExplicitLayoutRequired, bool EmitIR); |
435 | |
436 | SPIRVType *getOpTypeInt(unsigned Width, MachineIRBuilder &MIRBuilder, |
437 | bool IsSigned = false); |
438 | |
439 | SPIRVType *getOpTypeFloat(uint32_t Width, MachineIRBuilder &MIRBuilder); |
440 | |
441 | SPIRVType *getOpTypeVoid(MachineIRBuilder &MIRBuilder); |
442 | |
443 | SPIRVType *getOpTypeVector(uint32_t NumElems, SPIRVType *ElemType, |
444 | MachineIRBuilder &MIRBuilder); |
445 | |
446 | SPIRVType *getOpTypeArray(uint32_t NumElems, SPIRVType *ElemType, |
447 | MachineIRBuilder &MIRBuilder, |
448 | bool ExplicitLayoutRequired, bool EmitIR); |
449 | |
450 | SPIRVType *getOpTypeOpaque(const StructType *Ty, |
451 | MachineIRBuilder &MIRBuilder); |
452 | |
453 | SPIRVType *getOpTypeStruct(const StructType *Ty, MachineIRBuilder &MIRBuilder, |
454 | SPIRV::AccessQualifier::AccessQualifier AccQual, |
455 | StructOffsetDecorator Decorator, bool EmitIR); |
456 | |
457 | SPIRVType *getOpTypePointer(SPIRV::StorageClass::StorageClass SC, |
458 | SPIRVType *ElemType, MachineIRBuilder &MIRBuilder, |
459 | Register Reg); |
460 | |
461 | SPIRVType *getOpTypeForwardPointer(SPIRV::StorageClass::StorageClass SC, |
462 | MachineIRBuilder &MIRBuilder); |
463 | |
464 | SPIRVType *getOpTypeFunction(SPIRVType *RetType, |
465 | const SmallVectorImpl<SPIRVType *> &ArgTypes, |
466 | MachineIRBuilder &MIRBuilder); |
467 | |
468 | SPIRVType * |
469 | getOrCreateSpecialType(const Type *Ty, MachineIRBuilder &MIRBuilder, |
470 | SPIRV::AccessQualifier::AccessQualifier AccQual); |
471 | |
472 | SPIRVType *finishCreatingSPIRVType(const Type *LLVMTy, SPIRVType *SpirvType); |
473 | Register getOrCreateBaseRegister(Constant *Val, MachineInstr &I, |
474 | SPIRVType *SpvType, |
475 | const SPIRVInstrInfo &TII, unsigned BitWidth, |
476 | bool ZeroAsNull); |
477 | Register getOrCreateCompositeOrNull(Constant *Val, MachineInstr &I, |
478 | SPIRVType *SpvType, |
479 | const SPIRVInstrInfo &TII, Constant *CA, |
480 | unsigned BitWidth, unsigned ElemCnt, |
481 | bool ZeroAsNull = true); |
482 | |
483 | Register getOrCreateIntCompositeOrNull(uint64_t Val, |
484 | MachineIRBuilder &MIRBuilder, |
485 | SPIRVType *SpvType, bool EmitIR, |
486 | Constant *CA, unsigned BitWidth, |
487 | unsigned ElemCnt); |
488 | |
489 | // Returns a pointer to a SPIR-V pointer type with the given base type and |
490 | // storage class. It is the responsibility of the caller to make sure the |
491 | // decorations on the base type are valid for the given storage class. For |
492 | // example, it has the correct offset and stride decorations. |
493 | SPIRVType * |
494 | getOrCreateSPIRVPointerTypeInternal(SPIRVType *BaseType, |
495 | MachineIRBuilder &MIRBuilder, |
496 | SPIRV::StorageClass::StorageClass SC); |
497 | |
498 | void addStructOffsetDecorations(Register Reg, StructType *Ty, |
499 | MachineIRBuilder &MIRBuilder); |
500 | void addArrayStrideDecorations(Register Reg, Type *ElementType, |
501 | MachineIRBuilder &MIRBuilder); |
502 | bool hasBlockDecoration(SPIRVType *Type) const; |
503 | |
504 | SPIRVType * |
505 | getOrCreateOpTypeImage(MachineIRBuilder &MIRBuilder, SPIRVType *SampledType, |
506 | SPIRV::Dim::Dim Dim, uint32_t Depth, uint32_t Arrayed, |
507 | uint32_t Multisampled, uint32_t Sampled, |
508 | SPIRV::ImageFormat::ImageFormat ImageFormat, |
509 | SPIRV::AccessQualifier::AccessQualifier AccQual); |
510 | |
511 | public: |
512 | Register buildConstantInt(uint64_t Val, MachineIRBuilder &MIRBuilder, |
513 | SPIRVType *SpvType, bool EmitIR, |
514 | bool ZeroAsNull = true); |
515 | Register getOrCreateConstInt(uint64_t Val, MachineInstr &I, |
516 | SPIRVType *SpvType, const SPIRVInstrInfo &TII, |
517 | bool ZeroAsNull = true); |
518 | Register createConstInt(const ConstantInt *CI, MachineInstr &I, |
519 | SPIRVType *SpvType, const SPIRVInstrInfo &TII, |
520 | bool ZeroAsNull); |
521 | Register getOrCreateConstFP(APFloat Val, MachineInstr &I, SPIRVType *SpvType, |
522 | const SPIRVInstrInfo &TII, |
523 | bool ZeroAsNull = true); |
524 | Register createConstFP(const ConstantFP *CF, MachineInstr &I, |
525 | SPIRVType *SpvType, const SPIRVInstrInfo &TII, |
526 | bool ZeroAsNull); |
527 | Register buildConstantFP(APFloat Val, MachineIRBuilder &MIRBuilder, |
528 | SPIRVType *SpvType = nullptr); |
529 | |
530 | Register getOrCreateConstVector(uint64_t Val, MachineInstr &I, |
531 | SPIRVType *SpvType, const SPIRVInstrInfo &TII, |
532 | bool ZeroAsNull = true); |
533 | Register getOrCreateConstVector(APFloat Val, MachineInstr &I, |
534 | SPIRVType *SpvType, const SPIRVInstrInfo &TII, |
535 | bool ZeroAsNull = true); |
536 | Register getOrCreateConstIntArray(uint64_t Val, size_t Num, MachineInstr &I, |
537 | SPIRVType *SpvType, |
538 | const SPIRVInstrInfo &TII); |
539 | Register getOrCreateConsIntVector(uint64_t Val, MachineIRBuilder &MIRBuilder, |
540 | SPIRVType *SpvType, bool EmitIR); |
541 | Register getOrCreateConstNullPtr(MachineIRBuilder &MIRBuilder, |
542 | SPIRVType *SpvType); |
543 | Register buildConstantSampler(Register Res, unsigned AddrMode, unsigned Param, |
544 | unsigned FilerMode, |
545 | MachineIRBuilder &MIRBuilder); |
546 | Register getOrCreateUndef(MachineInstr &I, SPIRVType *SpvType, |
547 | const SPIRVInstrInfo &TII); |
548 | Register buildGlobalVariable(Register Reg, SPIRVType *BaseType, |
549 | StringRef Name, const GlobalValue *GV, |
550 | SPIRV::StorageClass::StorageClass Storage, |
551 | const MachineInstr *Init, bool IsConst, |
552 | bool HasLinkageTy, |
553 | SPIRV::LinkageType::LinkageType LinkageType, |
554 | MachineIRBuilder &MIRBuilder, |
555 | bool IsInstSelector); |
556 | Register getOrCreateGlobalVariableWithBinding(const SPIRVType *VarType, |
557 | uint32_t Set, uint32_t Binding, |
558 | StringRef Name, |
559 | MachineIRBuilder &MIRBuilder); |
560 | |
561 | // Convenient helpers for getting types with check for duplicates. |
562 | SPIRVType *getOrCreateSPIRVIntegerType(unsigned BitWidth, |
563 | MachineIRBuilder &MIRBuilder); |
564 | SPIRVType *getOrCreateSPIRVIntegerType(unsigned BitWidth, MachineInstr &I, |
565 | const SPIRVInstrInfo &TII); |
566 | SPIRVType *getOrCreateSPIRVType(unsigned BitWidth, MachineInstr &I, |
567 | const SPIRVInstrInfo &TII, |
568 | unsigned SPIRVOPcode, Type *LLVMTy); |
569 | SPIRVType *getOrCreateSPIRVFloatType(unsigned BitWidth, MachineInstr &I, |
570 | const SPIRVInstrInfo &TII); |
571 | SPIRVType *getOrCreateSPIRVBoolType(MachineIRBuilder &MIRBuilder, |
572 | bool EmitIR); |
573 | SPIRVType *getOrCreateSPIRVBoolType(MachineInstr &I, |
574 | const SPIRVInstrInfo &TII); |
575 | SPIRVType *getOrCreateSPIRVVectorType(SPIRVType *BaseType, |
576 | unsigned NumElements, |
577 | MachineIRBuilder &MIRBuilder, |
578 | bool EmitIR); |
579 | SPIRVType *getOrCreateSPIRVVectorType(SPIRVType *BaseType, |
580 | unsigned NumElements, MachineInstr &I, |
581 | const SPIRVInstrInfo &TII); |
582 | |
583 | // Returns a pointer to a SPIR-V pointer type with the given base type and |
584 | // storage class. The base type will be translated to a SPIR-V type, and the |
585 | // appropriate layout decorations will be added to the base type. |
586 | SPIRVType *getOrCreateSPIRVPointerType(const Type *BaseType, |
587 | MachineIRBuilder &MIRBuilder, |
588 | SPIRV::StorageClass::StorageClass SC); |
589 | SPIRVType *getOrCreateSPIRVPointerType(const Type *BaseType, MachineInstr &I, |
590 | SPIRV::StorageClass::StorageClass SC); |
591 | |
592 | // Returns a pointer to a SPIR-V pointer type with the given base type and |
593 | // storage class. It is the responsibility of the caller to make sure the |
594 | // decorations on the base type are valid for the given storage class. For |
595 | // example, it has the correct offset and stride decorations. |
596 | SPIRVType *getOrCreateSPIRVPointerType(SPIRVType *BaseType, |
597 | MachineIRBuilder &MIRBuilder, |
598 | SPIRV::StorageClass::StorageClass SC); |
599 | |
600 | // Returns a pointer to a SPIR-V pointer type that is the same as `PtrType` |
601 | // except the stroage class has been changed to `SC`. It is the responsibility |
602 | // of the caller to be sure that the original and new storage class have the |
603 | // same layout requirements. |
604 | SPIRVType *changePointerStorageClass(SPIRVType *PtrType, |
605 | SPIRV::StorageClass::StorageClass SC, |
606 | MachineInstr &I); |
607 | |
608 | SPIRVType *getOrCreateVulkanBufferType(MachineIRBuilder &MIRBuilder, |
609 | Type *ElemType, |
610 | SPIRV::StorageClass::StorageClass SC, |
611 | bool IsWritable, bool EmitIr = false); |
612 | |
613 | SPIRVType *getOrCreateLayoutType(MachineIRBuilder &MIRBuilder, |
614 | const TargetExtType *T, bool EmitIr = false); |
615 | |
616 | SPIRVType * |
617 | getImageType(const TargetExtType *ExtensionType, |
618 | const SPIRV::AccessQualifier::AccessQualifier Qualifier, |
619 | MachineIRBuilder &MIRBuilder); |
620 | |
621 | SPIRVType *getOrCreateOpTypeSampler(MachineIRBuilder &MIRBuilder); |
622 | |
623 | SPIRVType *getOrCreateOpTypeSampledImage(SPIRVType *ImageType, |
624 | MachineIRBuilder &MIRBuilder); |
625 | SPIRVType *getOrCreateOpTypeCoopMatr(MachineIRBuilder &MIRBuilder, |
626 | const TargetExtType *ExtensionType, |
627 | const SPIRVType *ElemType, |
628 | uint32_t Scope, uint32_t Rows, |
629 | uint32_t Columns, uint32_t Use, |
630 | bool EmitIR); |
631 | SPIRVType * |
632 | getOrCreateOpTypePipe(MachineIRBuilder &MIRBuilder, |
633 | SPIRV::AccessQualifier::AccessQualifier AccQual); |
634 | SPIRVType *getOrCreateOpTypeDeviceEvent(MachineIRBuilder &MIRBuilder); |
635 | SPIRVType *getOrCreateOpTypeFunctionWithArgs( |
636 | const Type *Ty, SPIRVType *RetType, |
637 | const SmallVectorImpl<SPIRVType *> &ArgTypes, |
638 | MachineIRBuilder &MIRBuilder); |
639 | SPIRVType *getOrCreateOpTypeByOpcode(const Type *Ty, |
640 | MachineIRBuilder &MIRBuilder, |
641 | unsigned Opcode); |
642 | |
643 | SPIRVType *getOrCreateUnknownType(const Type *Ty, |
644 | MachineIRBuilder &MIRBuilder, |
645 | unsigned Opcode, |
646 | const ArrayRef<MCOperand> Operands); |
647 | |
648 | const TargetRegisterClass *getRegClass(SPIRVType *SpvType) const; |
649 | LLT getRegType(SPIRVType *SpvType) const; |
650 | |
651 | MachineInstr *getOrAddMemAliasingINTELInst(MachineIRBuilder &MIRBuilder, |
652 | const MDNode *AliasingListMD); |
653 | void buildMemAliasingOpDecorate(Register Reg, MachineIRBuilder &MIRBuilder, |
654 | uint32_t Dec, const MDNode *GVarMD); |
655 | // Replace all uses of a |Old| with |New| updates the global registry type |
656 | // mappings. |
657 | void replaceAllUsesWith(Value *Old, Value *New, bool DeleteOld = true); |
658 | |
659 | void buildAssignType(IRBuilder<> &B, Type *Ty, Value *Arg); |
660 | void buildAssignPtr(IRBuilder<> &B, Type *ElemTy, Value *Arg); |
661 | void updateAssignType(CallInst *AssignCI, Value *Arg, Value *OfType); |
662 | }; |
663 | } // end namespace llvm |
664 | #endif // LLLVM_LIB_TARGET_SPIRV_SPIRVTYPEMANAGER_H |
665 | |