LLVM 22.0.0git
SPIRVIRMapping.h
Go to the documentation of this file.
1//===------------ SPIRVMapping.h - SPIR-V Duplicates Tracker ----*- 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// General infrastructure for keeping track of the values that according to
10// the SPIR-V binary layout should be global to the whole module.
11//
12//===----------------------------------------------------------------------===//
13
14#ifndef LLVM_LIB_TARGET_SPIRV_SPIRVIRMAPPING_H
15#define LLVM_LIB_TARGET_SPIRV_SPIRVIRMAPPING_H
16
19#include "SPIRVUtils.h"
20#include "llvm/ADT/DenseMap.h"
21#include "llvm/ADT/Hashing.h"
24
25#include <type_traits>
26
27namespace llvm {
28namespace SPIRV {
29
30inline size_t to_hash(const MachineInstr *MI) {
31 hash_code H = llvm::hash_combine(MI->getOpcode(), MI->getNumOperands());
32 for (unsigned I = MI->getNumDefs(); I < MI->getNumOperands(); ++I) {
33 const MachineOperand &MO = MI->getOperand(I);
35 H = llvm::hash_combine(H, MO.getType(), MO.getCImm());
37 H = llvm::hash_combine(H, MO.getType(), MO.getFPImm());
38 else
40 }
41 return H;
42}
43
44using MIHandle = std::tuple<const MachineInstr *, Register, size_t>;
45
47 return std::make_tuple(MI, MI->getOperand(0).getReg(), SPIRV::to_hash(MI));
48}
49
50using IRHandle = std::tuple<const void *, unsigned, unsigned>;
51using IRHandleMF = std::pair<IRHandle, const MachineFunction *>;
52
54 return std::make_pair(Handle, MF);
55}
56
70 STK_Last = -1
71};
72
74 struct BitFlags {
75 unsigned Dim : 3;
76 unsigned Depth : 2;
77 unsigned Arrayed : 1;
78 unsigned MS : 1;
79 unsigned Sampled : 2;
80 unsigned ImageFormat : 6;
81 unsigned AQ : 2;
83 unsigned Val;
84
85 ImageAttrs(unsigned Dim, unsigned Depth, unsigned Arrayed, unsigned MS,
86 unsigned Sampled, unsigned ImageFormat, unsigned AQ = 0) {
87 Val = 0;
88 Flags.Dim = Dim;
90 Flags.Arrayed = Arrayed;
91 Flags.MS = MS;
92 Flags.Sampled = Sampled;
93 Flags.ImageFormat = ImageFormat;
94 Flags.AQ = AQ;
95 }
96};
97
98inline IRHandle irhandle_image(const Type *SampledTy, unsigned Dim,
99 unsigned Depth, unsigned Arrayed, unsigned MS,
100 unsigned Sampled, unsigned ImageFormat,
101 unsigned AQ = 0) {
102 return std::make_tuple(
103 SampledTy,
104 ImageAttrs(Dim, Depth, Arrayed, MS, Sampled, ImageFormat, AQ).Val,
106}
107
108inline IRHandle irhandle_sampled_image(const Type *SampledTy,
109 const MachineInstr *ImageTy) {
110 assert(ImageTy->getOpcode() == SPIRV::OpTypeImage);
111 unsigned AC = AccessQualifier::AccessQualifier::None;
112 if (ImageTy->getNumOperands() > 8)
113 AC = ImageTy->getOperand(8).getImm();
114 return std::make_tuple(
115 SampledTy,
117 ImageTy->getOperand(2).getImm(), ImageTy->getOperand(3).getImm(),
118 ImageTy->getOperand(4).getImm(), ImageTy->getOperand(5).getImm(),
119 ImageTy->getOperand(6).getImm(), ImageTy->getOperand(7).getImm(), AC)
120 .Val,
122}
123
125 return std::make_tuple(nullptr, 0U, SpecialTypeKind::STK_Sampler);
126}
127
129 return std::make_tuple(nullptr, AQ, SpecialTypeKind::STK_Pipe);
130}
131
133 return std::make_tuple(nullptr, 0U, SpecialTypeKind::STK_DeviceEvent);
134}
135
136inline IRHandle irhandle_pointee(const Type *ElementType,
137 unsigned AddressSpace) {
138 return std::make_tuple(unifyPtrType(ElementType), AddressSpace,
140}
141
142inline IRHandle irhandle_ptr(const void *Ptr, unsigned Arg,
143 enum SpecialTypeKind STK) {
144 return std::make_tuple(Ptr, Arg, STK);
145}
146
147inline IRHandle irhandle_vkbuffer(const Type *ElementType,
148 StorageClass::StorageClass SC,
149 bool IsWriteable) {
150 return std::make_tuple(ElementType, (SC << 1) | IsWriteable,
152}
153
155 const Type *WrpTy = unifyPtrType(Ty);
156 return irhandle_ptr(WrpTy, Ty->getTypeID(), STK_ExplictLayoutType);
157}
158
159inline IRHandle handle(const Type *Ty) {
160 const Type *WrpTy = unifyPtrType(Ty);
161 return irhandle_ptr(WrpTy, Ty->getTypeID(), STK_Type);
162}
163
164inline IRHandle handle(const Value *V) {
165 return irhandle_ptr(V, V->getValueID(), STK_Value);
166}
167
168inline IRHandle handle(const MachineInstr *KeyMI) {
169 return irhandle_ptr(KeyMI, SPIRV::to_hash(KeyMI), STK_MachineInstr);
170}
171
172inline bool type_has_layout_decoration(const Type *T) {
173 return (isa<StructType>(T) || isa<ArrayType>(T));
174}
175
176} // namespace SPIRV
177
178// Bi-directional mappings between LLVM entities and (v-reg, machine function)
179// pairs support management of unique SPIR-V definitions per machine function
180// per an LLVM/GlobalISel entity (e.g., Type, Constant, Machine Instruction).
184
185public:
186 bool add(SPIRV::IRHandle Handle, const MachineInstr *MI) {
187 if (auto DefIt = Defs.find(MI); DefIt != Defs.end()) {
188 auto [ExistHandle, ExistMF] = DefIt->second;
189 if (Handle == ExistHandle && MI->getMF() == ExistMF)
190 return false; // already exists
191 // invalidate the record
192 Vregs.erase(DefIt->second);
193 Defs.erase(DefIt);
194 }
195 SPIRV::IRHandleMF HandleMF = SPIRV::getIRHandleMF(Handle, MI->getMF());
197 auto It1 = Vregs.try_emplace(HandleMF, MIKey);
198 if (!It1.second) {
199 // there is an expired record that we need to invalidate
200 Defs.erase(std::get<0>(It1.first->second));
201 // update the record
202 It1.first->second = MIKey;
203 }
204 [[maybe_unused]] auto It2 = Defs.try_emplace(MI, HandleMF);
205 assert(It2.second);
206 return true;
207 }
208 bool erase(const MachineInstr *MI) {
209 bool Res = false;
210 if (auto It = Defs.find(MI); It != Defs.end()) {
211 Res = Vregs.erase(It->second);
212 Defs.erase(It);
213 }
214 return Res;
215 }
217 const MachineFunction *MF) {
218 SPIRV::IRHandleMF HandleMF = SPIRV::getIRHandleMF(Handle, MF);
219 auto It = Vregs.find(HandleMF);
220 if (It == Vregs.end())
221 return nullptr;
222 auto [MI, Reg, Hash] = It->second;
223 const MachineInstr *Def = MF->getRegInfo().getVRegDef(Reg);
224 if (!Def || Def != MI || SPIRV::to_hash(MI) != Hash) {
225 // there is an expired record that we need to invalidate
226 erase(MI);
227 return nullptr;
228 }
229 assert(Defs.contains(MI) && Defs.find(MI)->second == HandleMF);
230 return MI;
231 }
233 const MachineInstr *MI = findMI(Handle, MF);
234 return MI ? MI->getOperand(0).getReg() : Register();
235 }
236
237 // helpers
238 bool add(const Type *PointeeTy, unsigned AddressSpace,
239 const MachineInstr *MI) {
240 return add(SPIRV::irhandle_pointee(PointeeTy, AddressSpace), MI);
241 }
242 Register find(const Type *PointeeTy, unsigned AddressSpace,
243 const MachineFunction *MF) {
244 return find(SPIRV::irhandle_pointee(PointeeTy, AddressSpace), MF);
245 }
246 const MachineInstr *findMI(const Type *PointeeTy, unsigned AddressSpace,
247 const MachineFunction *MF) {
248 return findMI(SPIRV::irhandle_pointee(PointeeTy, AddressSpace), MF);
249 }
250
251 bool add(const Value *V, const MachineInstr *MI) {
252 return add(SPIRV::handle(V), MI);
253 }
254
255 bool add(const Type *T, bool RequiresExplicitLayout, const MachineInstr *MI) {
256 if (RequiresExplicitLayout && SPIRV::type_has_layout_decoration(T)) {
258 }
259 return add(SPIRV::handle(T), MI);
260 }
261
262 bool add(const MachineInstr *Obj, const MachineInstr *MI) {
263 return add(SPIRV::handle(Obj), MI);
264 }
265
266 Register find(const Value *V, const MachineFunction *MF) {
267 return find(SPIRV::handle(V), MF);
268 }
269
270 Register find(const Type *T, bool RequiresExplicitLayout,
271 const MachineFunction *MF) {
272 if (RequiresExplicitLayout && SPIRV::type_has_layout_decoration(T))
274 return find(SPIRV::handle(T), MF);
275 }
276
278 return find(SPIRV::handle(MI), MF);
279 }
280
281 const MachineInstr *findMI(const Value *Obj, const MachineFunction *MF) {
282 return findMI(SPIRV::handle(Obj), MF);
283 }
284
285 const MachineInstr *findMI(const Type *T, bool RequiresExplicitLayout,
286 const MachineFunction *MF) {
287 if (RequiresExplicitLayout && SPIRV::type_has_layout_decoration(T))
289 return findMI(SPIRV::handle(T), MF);
290 }
291
293 const MachineFunction *MF) {
294 return findMI(SPIRV::handle(Obj), MF);
295 }
296};
297} // namespace llvm
298#endif // LLVM_LIB_TARGET_SPIRV_SPIRVIRMAPPING_H
assert(UImm &&(UImm !=~static_cast< T >(0)) &&"Invalid immediate!")
This file defines the DenseMap class.
IRTranslator LLVM IR MI
#define I(x, y, z)
Definition: MD5.cpp:58
#define H(x, y, z)
Definition: MD5.cpp:57
This file declares the MachineIRBuilder class.
Register Reg
spirv structurize SPIRV
iterator find(const_arg_type_t< KeyT > Val)
Definition: DenseMap.h:177
std::pair< iterator, bool > try_emplace(KeyT &&Key, Ts &&...Args)
Definition: DenseMap.h:245
bool erase(const KeyT &Val)
Definition: DenseMap.h:319
iterator end()
Definition: DenseMap.h:87
bool contains(const_arg_type_t< KeyT > Val) const
Return true if the specified key is in the map, false otherwise.
Definition: DenseMap.h:168
MachineRegisterInfo & getRegInfo()
getRegInfo - Return information about the registers currently in use.
Representation of each machine instruction.
Definition: MachineInstr.h:72
unsigned getOpcode() const
Returns the opcode of this MachineInstr.
Definition: MachineInstr.h:587
unsigned getNumOperands() const
Retuns the total number of operands.
Definition: MachineInstr.h:590
const MachineOperand & getOperand(unsigned i) const
Definition: MachineInstr.h:595
MachineOperand class - Representation of each machine instruction operand.
const ConstantInt * getCImm() const
int64_t getImm() const
MachineOperandType getType() const
getType - Returns the MachineOperandType for this operand.
const ConstantFP * getFPImm() const
@ MO_CImmediate
Immediate >64bit operand.
@ MO_FPImmediate
Floating-point immediate operand.
LLVM_ABI MachineInstr * getVRegDef(Register Reg) const
getVRegDef - Return the machine instr that defines the specified virtual register or null if none is ...
Wrapper class representing virtual and physical registers.
Definition: Register.h:19
const MachineInstr * findMI(const Type *PointeeTy, unsigned AddressSpace, const MachineFunction *MF)
const MachineInstr * findMI(const Type *T, bool RequiresExplicitLayout, const MachineFunction *MF)
const MachineInstr * findMI(const MachineInstr *Obj, const MachineFunction *MF)
const MachineInstr * findMI(SPIRV::IRHandle Handle, const MachineFunction *MF)
bool add(const Value *V, const MachineInstr *MI)
Register find(const Value *V, const MachineFunction *MF)
Register find(const Type *T, bool RequiresExplicitLayout, const MachineFunction *MF)
bool add(const Type *PointeeTy, unsigned AddressSpace, const MachineInstr *MI)
bool erase(const MachineInstr *MI)
bool add(SPIRV::IRHandle Handle, const MachineInstr *MI)
const MachineInstr * findMI(const Value *Obj, const MachineFunction *MF)
Register find(SPIRV::IRHandle Handle, const MachineFunction *MF)
Register find(const MachineInstr *MI, const MachineFunction *MF)
Register find(const Type *PointeeTy, unsigned AddressSpace, const MachineFunction *MF)
bool add(const MachineInstr *Obj, const MachineInstr *MI)
bool add(const Type *T, bool RequiresExplicitLayout, const MachineInstr *MI)
The instances of the Type class are immutable: once they are created, they are never changed.
Definition: Type.h:45
TypeID getTypeID() const
Return the type id for the type.
Definition: Type.h:136
LLVM Value Representation.
Definition: Value.h:75
An opaque object representing a hash code.
Definition: Hashing.h:76
IRHandle handle(const Type *Ty)
bool type_has_layout_decoration(const Type *T)
IRHandle irhandle_sampled_image(const Type *SampledTy, const MachineInstr *ImageTy)
size_t to_hash(const MachineInstr *MI)
std::pair< IRHandle, const MachineFunction * > IRHandleMF
IRHandle irhandle_pointee(const Type *ElementType, unsigned AddressSpace)
std::tuple< const void *, unsigned, unsigned > IRHandle
std::tuple< const MachineInstr *, Register, size_t > MIHandle
IRHandleMF getIRHandleMF(IRHandle Handle, const MachineFunction *MF)
IRHandle irhandle_vkbuffer(const Type *ElementType, StorageClass::StorageClass SC, bool IsWriteable)
IRHandle irhandle_sampler()
IRHandle irhandle_event()
MIHandle getMIKey(const MachineInstr *MI)
IRHandle irhandle_pipe(uint8_t AQ)
IRHandle irhandle_explict_layout_type(const Type *Ty)
IRHandle irhandle_ptr(const void *Ptr, unsigned Arg, enum SpecialTypeKind STK)
IRHandle irhandle_image(const Type *SampledTy, unsigned Dim, unsigned Depth, unsigned Arrayed, unsigned MS, unsigned Sampled, unsigned ImageFormat, unsigned AQ=0)
This is an optimization pass for GlobalISel generic memory operations.
Definition: AddressRanges.h:18
const Type * unifyPtrType(const Type *Ty)
Definition: SPIRVUtils.h:412
hash_code hash_combine(const Ts &...args)
Combine values into a single hash_code.
Definition: Hashing.h:595
struct llvm::SPIRV::ImageAttrs::BitFlags Flags
ImageAttrs(unsigned Dim, unsigned Depth, unsigned Arrayed, unsigned MS, unsigned Sampled, unsigned ImageFormat, unsigned AQ=0)