1*700637cbSDimitry Andric //===------------ SPIRVMapping.h - SPIR-V Duplicates Tracker ----*- C++ -*-===//
2*700637cbSDimitry Andric //
3*700637cbSDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4*700637cbSDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
5*700637cbSDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6*700637cbSDimitry Andric //
7*700637cbSDimitry Andric //===----------------------------------------------------------------------===//
8*700637cbSDimitry Andric //
9*700637cbSDimitry Andric // General infrastructure for keeping track of the values that according to
10*700637cbSDimitry Andric // the SPIR-V binary layout should be global to the whole module.
11*700637cbSDimitry Andric //
12*700637cbSDimitry Andric //===----------------------------------------------------------------------===//
13*700637cbSDimitry Andric
14*700637cbSDimitry Andric #ifndef LLVM_LIB_TARGET_SPIRV_SPIRVIRMAPPING_H
15*700637cbSDimitry Andric #define LLVM_LIB_TARGET_SPIRV_SPIRVIRMAPPING_H
16*700637cbSDimitry Andric
17*700637cbSDimitry Andric #include "MCTargetDesc/SPIRVBaseInfo.h"
18*700637cbSDimitry Andric #include "MCTargetDesc/SPIRVMCTargetDesc.h"
19*700637cbSDimitry Andric #include "SPIRVUtils.h"
20*700637cbSDimitry Andric #include "llvm/ADT/DenseMap.h"
21*700637cbSDimitry Andric #include "llvm/ADT/Hashing.h"
22*700637cbSDimitry Andric #include "llvm/CodeGen/GlobalISel/MachineIRBuilder.h"
23*700637cbSDimitry Andric #include "llvm/CodeGen/MachineModuleInfo.h"
24*700637cbSDimitry Andric
25*700637cbSDimitry Andric #include <type_traits>
26*700637cbSDimitry Andric
27*700637cbSDimitry Andric namespace llvm {
28*700637cbSDimitry Andric namespace SPIRV {
29*700637cbSDimitry Andric
to_hash(const MachineInstr * MI)30*700637cbSDimitry Andric inline size_t to_hash(const MachineInstr *MI) {
31*700637cbSDimitry Andric hash_code H = llvm::hash_combine(MI->getOpcode(), MI->getNumOperands());
32*700637cbSDimitry Andric for (unsigned I = MI->getNumDefs(); I < MI->getNumOperands(); ++I) {
33*700637cbSDimitry Andric const MachineOperand &MO = MI->getOperand(I);
34*700637cbSDimitry Andric if (MO.getType() == MachineOperand::MO_CImmediate)
35*700637cbSDimitry Andric H = llvm::hash_combine(H, MO.getType(), MO.getCImm());
36*700637cbSDimitry Andric else if (MO.getType() == MachineOperand::MO_FPImmediate)
37*700637cbSDimitry Andric H = llvm::hash_combine(H, MO.getType(), MO.getFPImm());
38*700637cbSDimitry Andric else
39*700637cbSDimitry Andric H = llvm::hash_combine(H, MO.getType());
40*700637cbSDimitry Andric }
41*700637cbSDimitry Andric return H;
42*700637cbSDimitry Andric }
43*700637cbSDimitry Andric
44*700637cbSDimitry Andric using MIHandle = std::tuple<const MachineInstr *, Register, size_t>;
45*700637cbSDimitry Andric
getMIKey(const MachineInstr * MI)46*700637cbSDimitry Andric inline MIHandle getMIKey(const MachineInstr *MI) {
47*700637cbSDimitry Andric return std::make_tuple(MI, MI->getOperand(0).getReg(), SPIRV::to_hash(MI));
48*700637cbSDimitry Andric }
49*700637cbSDimitry Andric
50*700637cbSDimitry Andric using IRHandle = std::tuple<const void *, unsigned, unsigned>;
51*700637cbSDimitry Andric using IRHandleMF = std::pair<IRHandle, const MachineFunction *>;
52*700637cbSDimitry Andric
getIRHandleMF(IRHandle Handle,const MachineFunction * MF)53*700637cbSDimitry Andric inline IRHandleMF getIRHandleMF(IRHandle Handle, const MachineFunction *MF) {
54*700637cbSDimitry Andric return std::make_pair(Handle, MF);
55*700637cbSDimitry Andric }
56*700637cbSDimitry Andric
57*700637cbSDimitry Andric enum SpecialTypeKind {
58*700637cbSDimitry Andric STK_Empty = 0,
59*700637cbSDimitry Andric STK_Image,
60*700637cbSDimitry Andric STK_SampledImage,
61*700637cbSDimitry Andric STK_Sampler,
62*700637cbSDimitry Andric STK_Pipe,
63*700637cbSDimitry Andric STK_DeviceEvent,
64*700637cbSDimitry Andric STK_ElementPointer,
65*700637cbSDimitry Andric STK_Type,
66*700637cbSDimitry Andric STK_Value,
67*700637cbSDimitry Andric STK_MachineInstr,
68*700637cbSDimitry Andric STK_VkBuffer,
69*700637cbSDimitry Andric STK_ExplictLayoutType,
70*700637cbSDimitry Andric STK_Last = -1
71*700637cbSDimitry Andric };
72*700637cbSDimitry Andric
73*700637cbSDimitry Andric union ImageAttrs {
74*700637cbSDimitry Andric struct BitFlags {
75*700637cbSDimitry Andric unsigned Dim : 3;
76*700637cbSDimitry Andric unsigned Depth : 2;
77*700637cbSDimitry Andric unsigned Arrayed : 1;
78*700637cbSDimitry Andric unsigned MS : 1;
79*700637cbSDimitry Andric unsigned Sampled : 2;
80*700637cbSDimitry Andric unsigned ImageFormat : 6;
81*700637cbSDimitry Andric unsigned AQ : 2;
82*700637cbSDimitry Andric } Flags;
83*700637cbSDimitry Andric unsigned Val;
84*700637cbSDimitry Andric
85*700637cbSDimitry Andric ImageAttrs(unsigned Dim, unsigned Depth, unsigned Arrayed, unsigned MS,
86*700637cbSDimitry Andric unsigned Sampled, unsigned ImageFormat, unsigned AQ = 0) {
87*700637cbSDimitry Andric Val = 0;
88*700637cbSDimitry Andric Flags.Dim = Dim;
89*700637cbSDimitry Andric Flags.Depth = Depth;
90*700637cbSDimitry Andric Flags.Arrayed = Arrayed;
91*700637cbSDimitry Andric Flags.MS = MS;
92*700637cbSDimitry Andric Flags.Sampled = Sampled;
93*700637cbSDimitry Andric Flags.ImageFormat = ImageFormat;
94*700637cbSDimitry Andric Flags.AQ = AQ;
95*700637cbSDimitry Andric }
96*700637cbSDimitry Andric };
97*700637cbSDimitry Andric
98*700637cbSDimitry Andric inline IRHandle irhandle_image(const Type *SampledTy, unsigned Dim,
99*700637cbSDimitry Andric unsigned Depth, unsigned Arrayed, unsigned MS,
100*700637cbSDimitry Andric unsigned Sampled, unsigned ImageFormat,
101*700637cbSDimitry Andric unsigned AQ = 0) {
102*700637cbSDimitry Andric return std::make_tuple(
103*700637cbSDimitry Andric SampledTy,
104*700637cbSDimitry Andric ImageAttrs(Dim, Depth, Arrayed, MS, Sampled, ImageFormat, AQ).Val,
105*700637cbSDimitry Andric SpecialTypeKind::STK_Image);
106*700637cbSDimitry Andric }
107*700637cbSDimitry Andric
irhandle_sampled_image(const Type * SampledTy,const MachineInstr * ImageTy)108*700637cbSDimitry Andric inline IRHandle irhandle_sampled_image(const Type *SampledTy,
109*700637cbSDimitry Andric const MachineInstr *ImageTy) {
110*700637cbSDimitry Andric assert(ImageTy->getOpcode() == SPIRV::OpTypeImage);
111*700637cbSDimitry Andric unsigned AC = AccessQualifier::AccessQualifier::None;
112*700637cbSDimitry Andric if (ImageTy->getNumOperands() > 8)
113*700637cbSDimitry Andric AC = ImageTy->getOperand(8).getImm();
114*700637cbSDimitry Andric return std::make_tuple(
115*700637cbSDimitry Andric SampledTy,
116*700637cbSDimitry Andric ImageAttrs(
117*700637cbSDimitry Andric ImageTy->getOperand(2).getImm(), ImageTy->getOperand(3).getImm(),
118*700637cbSDimitry Andric ImageTy->getOperand(4).getImm(), ImageTy->getOperand(5).getImm(),
119*700637cbSDimitry Andric ImageTy->getOperand(6).getImm(), ImageTy->getOperand(7).getImm(), AC)
120*700637cbSDimitry Andric .Val,
121*700637cbSDimitry Andric SpecialTypeKind::STK_SampledImage);
122*700637cbSDimitry Andric }
123*700637cbSDimitry Andric
irhandle_sampler()124*700637cbSDimitry Andric inline IRHandle irhandle_sampler() {
125*700637cbSDimitry Andric return std::make_tuple(nullptr, 0U, SpecialTypeKind::STK_Sampler);
126*700637cbSDimitry Andric }
127*700637cbSDimitry Andric
irhandle_pipe(uint8_t AQ)128*700637cbSDimitry Andric inline IRHandle irhandle_pipe(uint8_t AQ) {
129*700637cbSDimitry Andric return std::make_tuple(nullptr, AQ, SpecialTypeKind::STK_Pipe);
130*700637cbSDimitry Andric }
131*700637cbSDimitry Andric
irhandle_event()132*700637cbSDimitry Andric inline IRHandle irhandle_event() {
133*700637cbSDimitry Andric return std::make_tuple(nullptr, 0U, SpecialTypeKind::STK_DeviceEvent);
134*700637cbSDimitry Andric }
135*700637cbSDimitry Andric
irhandle_pointee(const Type * ElementType,unsigned AddressSpace)136*700637cbSDimitry Andric inline IRHandle irhandle_pointee(const Type *ElementType,
137*700637cbSDimitry Andric unsigned AddressSpace) {
138*700637cbSDimitry Andric return std::make_tuple(unifyPtrType(ElementType), AddressSpace,
139*700637cbSDimitry Andric SpecialTypeKind::STK_ElementPointer);
140*700637cbSDimitry Andric }
141*700637cbSDimitry Andric
irhandle_ptr(const void * Ptr,unsigned Arg,enum SpecialTypeKind STK)142*700637cbSDimitry Andric inline IRHandle irhandle_ptr(const void *Ptr, unsigned Arg,
143*700637cbSDimitry Andric enum SpecialTypeKind STK) {
144*700637cbSDimitry Andric return std::make_tuple(Ptr, Arg, STK);
145*700637cbSDimitry Andric }
146*700637cbSDimitry Andric
irhandle_vkbuffer(const Type * ElementType,StorageClass::StorageClass SC,bool IsWriteable)147*700637cbSDimitry Andric inline IRHandle irhandle_vkbuffer(const Type *ElementType,
148*700637cbSDimitry Andric StorageClass::StorageClass SC,
149*700637cbSDimitry Andric bool IsWriteable) {
150*700637cbSDimitry Andric return std::make_tuple(ElementType, (SC << 1) | IsWriteable,
151*700637cbSDimitry Andric SpecialTypeKind::STK_VkBuffer);
152*700637cbSDimitry Andric }
153*700637cbSDimitry Andric
irhandle_explict_layout_type(const Type * Ty)154*700637cbSDimitry Andric inline IRHandle irhandle_explict_layout_type(const Type *Ty) {
155*700637cbSDimitry Andric const Type *WrpTy = unifyPtrType(Ty);
156*700637cbSDimitry Andric return irhandle_ptr(WrpTy, Ty->getTypeID(), STK_ExplictLayoutType);
157*700637cbSDimitry Andric }
158*700637cbSDimitry Andric
handle(const Type * Ty)159*700637cbSDimitry Andric inline IRHandle handle(const Type *Ty) {
160*700637cbSDimitry Andric const Type *WrpTy = unifyPtrType(Ty);
161*700637cbSDimitry Andric return irhandle_ptr(WrpTy, Ty->getTypeID(), STK_Type);
162*700637cbSDimitry Andric }
163*700637cbSDimitry Andric
handle(const Value * V)164*700637cbSDimitry Andric inline IRHandle handle(const Value *V) {
165*700637cbSDimitry Andric return irhandle_ptr(V, V->getValueID(), STK_Value);
166*700637cbSDimitry Andric }
167*700637cbSDimitry Andric
handle(const MachineInstr * KeyMI)168*700637cbSDimitry Andric inline IRHandle handle(const MachineInstr *KeyMI) {
169*700637cbSDimitry Andric return irhandle_ptr(KeyMI, SPIRV::to_hash(KeyMI), STK_MachineInstr);
170*700637cbSDimitry Andric }
171*700637cbSDimitry Andric
type_has_layout_decoration(const Type * T)172*700637cbSDimitry Andric inline bool type_has_layout_decoration(const Type *T) {
173*700637cbSDimitry Andric return (isa<StructType>(T) || isa<ArrayType>(T));
174*700637cbSDimitry Andric }
175*700637cbSDimitry Andric
176*700637cbSDimitry Andric } // namespace SPIRV
177*700637cbSDimitry Andric
178*700637cbSDimitry Andric // Bi-directional mappings between LLVM entities and (v-reg, machine function)
179*700637cbSDimitry Andric // pairs support management of unique SPIR-V definitions per machine function
180*700637cbSDimitry Andric // per an LLVM/GlobalISel entity (e.g., Type, Constant, Machine Instruction).
181*700637cbSDimitry Andric class SPIRVIRMapping {
182*700637cbSDimitry Andric DenseMap<SPIRV::IRHandleMF, SPIRV::MIHandle> Vregs;
183*700637cbSDimitry Andric DenseMap<const MachineInstr *, SPIRV::IRHandleMF> Defs;
184*700637cbSDimitry Andric
185*700637cbSDimitry Andric public:
add(SPIRV::IRHandle Handle,const MachineInstr * MI)186*700637cbSDimitry Andric bool add(SPIRV::IRHandle Handle, const MachineInstr *MI) {
187*700637cbSDimitry Andric if (auto DefIt = Defs.find(MI); DefIt != Defs.end()) {
188*700637cbSDimitry Andric auto [ExistHandle, ExistMF] = DefIt->second;
189*700637cbSDimitry Andric if (Handle == ExistHandle && MI->getMF() == ExistMF)
190*700637cbSDimitry Andric return false; // already exists
191*700637cbSDimitry Andric // invalidate the record
192*700637cbSDimitry Andric Vregs.erase(DefIt->second);
193*700637cbSDimitry Andric Defs.erase(DefIt);
194*700637cbSDimitry Andric }
195*700637cbSDimitry Andric SPIRV::IRHandleMF HandleMF = SPIRV::getIRHandleMF(Handle, MI->getMF());
196*700637cbSDimitry Andric SPIRV::MIHandle MIKey = SPIRV::getMIKey(MI);
197*700637cbSDimitry Andric auto It1 = Vregs.try_emplace(HandleMF, MIKey);
198*700637cbSDimitry Andric if (!It1.second) {
199*700637cbSDimitry Andric // there is an expired record that we need to invalidate
200*700637cbSDimitry Andric Defs.erase(std::get<0>(It1.first->second));
201*700637cbSDimitry Andric // update the record
202*700637cbSDimitry Andric It1.first->second = MIKey;
203*700637cbSDimitry Andric }
204*700637cbSDimitry Andric [[maybe_unused]] auto It2 = Defs.try_emplace(MI, HandleMF);
205*700637cbSDimitry Andric assert(It2.second);
206*700637cbSDimitry Andric return true;
207*700637cbSDimitry Andric }
erase(const MachineInstr * MI)208*700637cbSDimitry Andric bool erase(const MachineInstr *MI) {
209*700637cbSDimitry Andric bool Res = false;
210*700637cbSDimitry Andric if (auto It = Defs.find(MI); It != Defs.end()) {
211*700637cbSDimitry Andric Res = Vregs.erase(It->second);
212*700637cbSDimitry Andric Defs.erase(It);
213*700637cbSDimitry Andric }
214*700637cbSDimitry Andric return Res;
215*700637cbSDimitry Andric }
findMI(SPIRV::IRHandle Handle,const MachineFunction * MF)216*700637cbSDimitry Andric const MachineInstr *findMI(SPIRV::IRHandle Handle,
217*700637cbSDimitry Andric const MachineFunction *MF) {
218*700637cbSDimitry Andric SPIRV::IRHandleMF HandleMF = SPIRV::getIRHandleMF(Handle, MF);
219*700637cbSDimitry Andric auto It = Vregs.find(HandleMF);
220*700637cbSDimitry Andric if (It == Vregs.end())
221*700637cbSDimitry Andric return nullptr;
222*700637cbSDimitry Andric auto [MI, Reg, Hash] = It->second;
223*700637cbSDimitry Andric const MachineInstr *Def = MF->getRegInfo().getVRegDef(Reg);
224*700637cbSDimitry Andric if (!Def || Def != MI || SPIRV::to_hash(MI) != Hash) {
225*700637cbSDimitry Andric // there is an expired record that we need to invalidate
226*700637cbSDimitry Andric erase(MI);
227*700637cbSDimitry Andric return nullptr;
228*700637cbSDimitry Andric }
229*700637cbSDimitry Andric assert(Defs.contains(MI) && Defs.find(MI)->second == HandleMF);
230*700637cbSDimitry Andric return MI;
231*700637cbSDimitry Andric }
find(SPIRV::IRHandle Handle,const MachineFunction * MF)232*700637cbSDimitry Andric Register find(SPIRV::IRHandle Handle, const MachineFunction *MF) {
233*700637cbSDimitry Andric const MachineInstr *MI = findMI(Handle, MF);
234*700637cbSDimitry Andric return MI ? MI->getOperand(0).getReg() : Register();
235*700637cbSDimitry Andric }
236*700637cbSDimitry Andric
237*700637cbSDimitry Andric // helpers
add(const Type * PointeeTy,unsigned AddressSpace,const MachineInstr * MI)238*700637cbSDimitry Andric bool add(const Type *PointeeTy, unsigned AddressSpace,
239*700637cbSDimitry Andric const MachineInstr *MI) {
240*700637cbSDimitry Andric return add(SPIRV::irhandle_pointee(PointeeTy, AddressSpace), MI);
241*700637cbSDimitry Andric }
find(const Type * PointeeTy,unsigned AddressSpace,const MachineFunction * MF)242*700637cbSDimitry Andric Register find(const Type *PointeeTy, unsigned AddressSpace,
243*700637cbSDimitry Andric const MachineFunction *MF) {
244*700637cbSDimitry Andric return find(SPIRV::irhandle_pointee(PointeeTy, AddressSpace), MF);
245*700637cbSDimitry Andric }
findMI(const Type * PointeeTy,unsigned AddressSpace,const MachineFunction * MF)246*700637cbSDimitry Andric const MachineInstr *findMI(const Type *PointeeTy, unsigned AddressSpace,
247*700637cbSDimitry Andric const MachineFunction *MF) {
248*700637cbSDimitry Andric return findMI(SPIRV::irhandle_pointee(PointeeTy, AddressSpace), MF);
249*700637cbSDimitry Andric }
250*700637cbSDimitry Andric
add(const Value * V,const MachineInstr * MI)251*700637cbSDimitry Andric bool add(const Value *V, const MachineInstr *MI) {
252*700637cbSDimitry Andric return add(SPIRV::handle(V), MI);
253*700637cbSDimitry Andric }
254*700637cbSDimitry Andric
add(const Type * T,bool RequiresExplicitLayout,const MachineInstr * MI)255*700637cbSDimitry Andric bool add(const Type *T, bool RequiresExplicitLayout, const MachineInstr *MI) {
256*700637cbSDimitry Andric if (RequiresExplicitLayout && SPIRV::type_has_layout_decoration(T)) {
257*700637cbSDimitry Andric return add(SPIRV::irhandle_explict_layout_type(T), MI);
258*700637cbSDimitry Andric }
259*700637cbSDimitry Andric return add(SPIRV::handle(T), MI);
260*700637cbSDimitry Andric }
261*700637cbSDimitry Andric
add(const MachineInstr * Obj,const MachineInstr * MI)262*700637cbSDimitry Andric bool add(const MachineInstr *Obj, const MachineInstr *MI) {
263*700637cbSDimitry Andric return add(SPIRV::handle(Obj), MI);
264*700637cbSDimitry Andric }
265*700637cbSDimitry Andric
find(const Value * V,const MachineFunction * MF)266*700637cbSDimitry Andric Register find(const Value *V, const MachineFunction *MF) {
267*700637cbSDimitry Andric return find(SPIRV::handle(V), MF);
268*700637cbSDimitry Andric }
269*700637cbSDimitry Andric
find(const Type * T,bool RequiresExplicitLayout,const MachineFunction * MF)270*700637cbSDimitry Andric Register find(const Type *T, bool RequiresExplicitLayout,
271*700637cbSDimitry Andric const MachineFunction *MF) {
272*700637cbSDimitry Andric if (RequiresExplicitLayout && SPIRV::type_has_layout_decoration(T))
273*700637cbSDimitry Andric return find(SPIRV::irhandle_explict_layout_type(T), MF);
274*700637cbSDimitry Andric return find(SPIRV::handle(T), MF);
275*700637cbSDimitry Andric }
276*700637cbSDimitry Andric
find(const MachineInstr * MI,const MachineFunction * MF)277*700637cbSDimitry Andric Register find(const MachineInstr *MI, const MachineFunction *MF) {
278*700637cbSDimitry Andric return find(SPIRV::handle(MI), MF);
279*700637cbSDimitry Andric }
280*700637cbSDimitry Andric
findMI(const Value * Obj,const MachineFunction * MF)281*700637cbSDimitry Andric const MachineInstr *findMI(const Value *Obj, const MachineFunction *MF) {
282*700637cbSDimitry Andric return findMI(SPIRV::handle(Obj), MF);
283*700637cbSDimitry Andric }
284*700637cbSDimitry Andric
findMI(const Type * T,bool RequiresExplicitLayout,const MachineFunction * MF)285*700637cbSDimitry Andric const MachineInstr *findMI(const Type *T, bool RequiresExplicitLayout,
286*700637cbSDimitry Andric const MachineFunction *MF) {
287*700637cbSDimitry Andric if (RequiresExplicitLayout && SPIRV::type_has_layout_decoration(T))
288*700637cbSDimitry Andric return findMI(SPIRV::irhandle_explict_layout_type(T), MF);
289*700637cbSDimitry Andric return findMI(SPIRV::handle(T), MF);
290*700637cbSDimitry Andric }
291*700637cbSDimitry Andric
findMI(const MachineInstr * Obj,const MachineFunction * MF)292*700637cbSDimitry Andric const MachineInstr *findMI(const MachineInstr *Obj,
293*700637cbSDimitry Andric const MachineFunction *MF) {
294*700637cbSDimitry Andric return findMI(SPIRV::handle(Obj), MF);
295*700637cbSDimitry Andric }
296*700637cbSDimitry Andric };
297*700637cbSDimitry Andric } // namespace llvm
298*700637cbSDimitry Andric #endif // LLVM_LIB_TARGET_SPIRV_SPIRVIRMAPPING_H
299