1753f127fSDimitry Andric //===-- SPIRVDuplicatesTracker.h - SPIR-V Duplicates Tracker ----*- C++ -*-===//
2753f127fSDimitry Andric //
3753f127fSDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4753f127fSDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
5753f127fSDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6753f127fSDimitry Andric //
7753f127fSDimitry Andric //===----------------------------------------------------------------------===//
8753f127fSDimitry Andric //
9753f127fSDimitry Andric // General infrastructure for keeping track of the values that according to
10753f127fSDimitry Andric // the SPIR-V binary layout should be global to the whole module.
11753f127fSDimitry Andric //
12753f127fSDimitry Andric //===----------------------------------------------------------------------===//
13753f127fSDimitry Andric
14753f127fSDimitry Andric #ifndef LLVM_LIB_TARGET_SPIRV_SPIRVDUPLICATESTRACKER_H
15753f127fSDimitry Andric #define LLVM_LIB_TARGET_SPIRV_SPIRVDUPLICATESTRACKER_H
16753f127fSDimitry Andric
17753f127fSDimitry Andric #include "MCTargetDesc/SPIRVBaseInfo.h"
18753f127fSDimitry Andric #include "MCTargetDesc/SPIRVMCTargetDesc.h"
19*0fca6ea1SDimitry Andric #include "SPIRVUtils.h"
20753f127fSDimitry Andric #include "llvm/ADT/DenseMap.h"
21753f127fSDimitry Andric #include "llvm/ADT/MapVector.h"
22753f127fSDimitry Andric #include "llvm/CodeGen/GlobalISel/MachineIRBuilder.h"
23753f127fSDimitry Andric #include "llvm/CodeGen/MachineModuleInfo.h"
24753f127fSDimitry Andric
25753f127fSDimitry Andric #include <type_traits>
26753f127fSDimitry Andric
27753f127fSDimitry Andric namespace llvm {
28753f127fSDimitry Andric namespace SPIRV {
29753f127fSDimitry Andric // NOTE: using MapVector instead of DenseMap because it helps getting
30753f127fSDimitry Andric // everything ordered in a stable manner for a price of extra (NumKeys)*PtrSize
31753f127fSDimitry Andric // memory and expensive removals which do not happen anyway.
32753f127fSDimitry Andric class DTSortableEntry : public MapVector<const MachineFunction *, Register> {
33753f127fSDimitry Andric SmallVector<DTSortableEntry *, 2> Deps;
34753f127fSDimitry Andric
35753f127fSDimitry Andric struct FlagsTy {
36753f127fSDimitry Andric unsigned IsFunc : 1;
37753f127fSDimitry Andric unsigned IsGV : 1;
38753f127fSDimitry Andric // NOTE: bit-field default init is a C++20 feature.
FlagsTyFlagsTy39753f127fSDimitry Andric FlagsTy() : IsFunc(0), IsGV(0) {}
40753f127fSDimitry Andric };
41753f127fSDimitry Andric FlagsTy Flags;
42753f127fSDimitry Andric
43753f127fSDimitry Andric public:
44753f127fSDimitry Andric // Common hoisting utility doesn't support function, because their hoisting
45753f127fSDimitry Andric // require hoisting of params as well.
getIsFunc()46753f127fSDimitry Andric bool getIsFunc() const { return Flags.IsFunc; }
getIsGV()47753f127fSDimitry Andric bool getIsGV() const { return Flags.IsGV; }
setIsFunc(bool V)48753f127fSDimitry Andric void setIsFunc(bool V) { Flags.IsFunc = V; }
setIsGV(bool V)49753f127fSDimitry Andric void setIsGV(bool V) { Flags.IsGV = V; }
50753f127fSDimitry Andric
getDeps()51753f127fSDimitry Andric const SmallVector<DTSortableEntry *, 2> &getDeps() const { return Deps; }
addDep(DTSortableEntry * E)52753f127fSDimitry Andric void addDep(DTSortableEntry *E) { Deps.push_back(E); }
53753f127fSDimitry Andric };
54bdd1243dSDimitry Andric
55bdd1243dSDimitry Andric enum SpecialTypeKind {
56bdd1243dSDimitry Andric STK_Empty = 0,
57bdd1243dSDimitry Andric STK_Image,
58bdd1243dSDimitry Andric STK_SampledImage,
59bdd1243dSDimitry Andric STK_Sampler,
60bdd1243dSDimitry Andric STK_Pipe,
61bdd1243dSDimitry Andric STK_DeviceEvent,
625f757f3fSDimitry Andric STK_Pointer,
63bdd1243dSDimitry Andric STK_Last = -1
64bdd1243dSDimitry Andric };
65bdd1243dSDimitry Andric
66*0fca6ea1SDimitry Andric using SpecialTypeDescriptor = std::tuple<const Type *, unsigned, unsigned>;
67bdd1243dSDimitry Andric
68bdd1243dSDimitry Andric union ImageAttrs {
69bdd1243dSDimitry Andric struct BitFlags {
70bdd1243dSDimitry Andric unsigned Dim : 3;
71bdd1243dSDimitry Andric unsigned Depth : 2;
72bdd1243dSDimitry Andric unsigned Arrayed : 1;
73bdd1243dSDimitry Andric unsigned MS : 1;
74bdd1243dSDimitry Andric unsigned Sampled : 2;
75bdd1243dSDimitry Andric unsigned ImageFormat : 6;
76bdd1243dSDimitry Andric unsigned AQ : 2;
77bdd1243dSDimitry Andric } Flags;
78bdd1243dSDimitry Andric unsigned Val;
79*0fca6ea1SDimitry Andric
80*0fca6ea1SDimitry Andric ImageAttrs(unsigned Dim, unsigned Depth, unsigned Arrayed, unsigned MS,
81*0fca6ea1SDimitry Andric unsigned Sampled, unsigned ImageFormat, unsigned AQ = 0) {
82*0fca6ea1SDimitry Andric Val = 0;
83*0fca6ea1SDimitry Andric Flags.Dim = Dim;
84*0fca6ea1SDimitry Andric Flags.Depth = Depth;
85*0fca6ea1SDimitry Andric Flags.Arrayed = Arrayed;
86*0fca6ea1SDimitry Andric Flags.MS = MS;
87*0fca6ea1SDimitry Andric Flags.Sampled = Sampled;
88*0fca6ea1SDimitry Andric Flags.ImageFormat = ImageFormat;
89*0fca6ea1SDimitry Andric Flags.AQ = AQ;
90*0fca6ea1SDimitry Andric }
91bdd1243dSDimitry Andric };
92bdd1243dSDimitry Andric
93*0fca6ea1SDimitry Andric inline SpecialTypeDescriptor
94*0fca6ea1SDimitry Andric make_descr_image(const Type *SampledTy, unsigned Dim, unsigned Depth,
95bdd1243dSDimitry Andric unsigned Arrayed, unsigned MS, unsigned Sampled,
96*0fca6ea1SDimitry Andric unsigned ImageFormat, unsigned AQ = 0) {
97*0fca6ea1SDimitry Andric return std::make_tuple(
98*0fca6ea1SDimitry Andric SampledTy,
99*0fca6ea1SDimitry Andric ImageAttrs(Dim, Depth, Arrayed, MS, Sampled, ImageFormat, AQ).Val,
100*0fca6ea1SDimitry Andric SpecialTypeKind::STK_Image);
101bdd1243dSDimitry Andric }
102bdd1243dSDimitry Andric
103*0fca6ea1SDimitry Andric inline SpecialTypeDescriptor
make_descr_sampled_image(const Type * SampledTy,const MachineInstr * ImageTy)104*0fca6ea1SDimitry Andric make_descr_sampled_image(const Type *SampledTy, const MachineInstr *ImageTy) {
105bdd1243dSDimitry Andric assert(ImageTy->getOpcode() == SPIRV::OpTypeImage);
106*0fca6ea1SDimitry Andric return std::make_tuple(
107*0fca6ea1SDimitry Andric SampledTy,
108*0fca6ea1SDimitry Andric ImageAttrs(
109*0fca6ea1SDimitry Andric ImageTy->getOperand(2).getImm(), ImageTy->getOperand(3).getImm(),
110*0fca6ea1SDimitry Andric ImageTy->getOperand(4).getImm(), ImageTy->getOperand(5).getImm(),
111*0fca6ea1SDimitry Andric ImageTy->getOperand(6).getImm(), ImageTy->getOperand(7).getImm(),
112*0fca6ea1SDimitry Andric ImageTy->getOperand(8).getImm())
113*0fca6ea1SDimitry Andric .Val,
114*0fca6ea1SDimitry Andric SpecialTypeKind::STK_SampledImage);
115bdd1243dSDimitry Andric }
116bdd1243dSDimitry Andric
make_descr_sampler()117*0fca6ea1SDimitry Andric inline SpecialTypeDescriptor make_descr_sampler() {
118*0fca6ea1SDimitry Andric return std::make_tuple(nullptr, 0U, SpecialTypeKind::STK_Sampler);
119bdd1243dSDimitry Andric }
120bdd1243dSDimitry Andric
make_descr_pipe(uint8_t AQ)121*0fca6ea1SDimitry Andric inline SpecialTypeDescriptor make_descr_pipe(uint8_t AQ) {
122*0fca6ea1SDimitry Andric return std::make_tuple(nullptr, AQ, SpecialTypeKind::STK_Pipe);
123bdd1243dSDimitry Andric }
124bdd1243dSDimitry Andric
make_descr_event()125*0fca6ea1SDimitry Andric inline SpecialTypeDescriptor make_descr_event() {
126*0fca6ea1SDimitry Andric return std::make_tuple(nullptr, 0U, SpecialTypeKind::STK_DeviceEvent);
127bdd1243dSDimitry Andric }
128bdd1243dSDimitry Andric
make_descr_pointee(const Type * ElementType,unsigned AddressSpace)129*0fca6ea1SDimitry Andric inline SpecialTypeDescriptor make_descr_pointee(const Type *ElementType,
130*0fca6ea1SDimitry Andric unsigned AddressSpace) {
131*0fca6ea1SDimitry Andric return std::make_tuple(ElementType, AddressSpace,
132*0fca6ea1SDimitry Andric SpecialTypeKind::STK_Pointer);
133bdd1243dSDimitry Andric }
134753f127fSDimitry Andric } // namespace SPIRV
135753f127fSDimitry Andric
136753f127fSDimitry Andric template <typename KeyTy> class SPIRVDuplicatesTrackerBase {
137753f127fSDimitry Andric public:
138753f127fSDimitry Andric // NOTE: using MapVector instead of DenseMap helps getting everything ordered
139753f127fSDimitry Andric // in a stable manner for a price of extra (NumKeys)*PtrSize memory and
140753f127fSDimitry Andric // expensive removals which don't happen anyway.
141753f127fSDimitry Andric using StorageTy = MapVector<KeyTy, SPIRV::DTSortableEntry>;
142753f127fSDimitry Andric
143753f127fSDimitry Andric private:
144753f127fSDimitry Andric StorageTy Storage;
145753f127fSDimitry Andric
146753f127fSDimitry Andric public:
add(KeyTy V,const MachineFunction * MF,Register R)147753f127fSDimitry Andric void add(KeyTy V, const MachineFunction *MF, Register R) {
148753f127fSDimitry Andric if (find(V, MF).isValid())
149753f127fSDimitry Andric return;
150753f127fSDimitry Andric
151753f127fSDimitry Andric Storage[V][MF] = R;
152753f127fSDimitry Andric if (std::is_same<Function,
153753f127fSDimitry Andric typename std::remove_const<
154753f127fSDimitry Andric typename std::remove_pointer<KeyTy>::type>::type>() ||
155753f127fSDimitry Andric std::is_same<Argument,
156753f127fSDimitry Andric typename std::remove_const<
157753f127fSDimitry Andric typename std::remove_pointer<KeyTy>::type>::type>())
158753f127fSDimitry Andric Storage[V].setIsFunc(true);
159753f127fSDimitry Andric if (std::is_same<GlobalVariable,
160753f127fSDimitry Andric typename std::remove_const<
161753f127fSDimitry Andric typename std::remove_pointer<KeyTy>::type>::type>())
162753f127fSDimitry Andric Storage[V].setIsGV(true);
163753f127fSDimitry Andric }
164753f127fSDimitry Andric
find(KeyTy V,const MachineFunction * MF)165753f127fSDimitry Andric Register find(KeyTy V, const MachineFunction *MF) const {
166753f127fSDimitry Andric auto iter = Storage.find(V);
167753f127fSDimitry Andric if (iter != Storage.end()) {
168753f127fSDimitry Andric auto Map = iter->second;
169753f127fSDimitry Andric auto iter2 = Map.find(MF);
170753f127fSDimitry Andric if (iter2 != Map.end())
171753f127fSDimitry Andric return iter2->second;
172753f127fSDimitry Andric }
173753f127fSDimitry Andric return Register();
174753f127fSDimitry Andric }
175753f127fSDimitry Andric
getAllUses()176753f127fSDimitry Andric const StorageTy &getAllUses() const { return Storage; }
177753f127fSDimitry Andric
178753f127fSDimitry Andric private:
getAllUses()179753f127fSDimitry Andric StorageTy &getAllUses() { return Storage; }
180753f127fSDimitry Andric
181753f127fSDimitry Andric // The friend class needs to have access to the internal storage
182753f127fSDimitry Andric // to be able to build dependency graph, can't declare only one
183753f127fSDimitry Andric // function a 'friend' due to the incomplete declaration at this point
184753f127fSDimitry Andric // and mutual dependency problems.
185753f127fSDimitry Andric friend class SPIRVGeneralDuplicatesTracker;
186753f127fSDimitry Andric };
187753f127fSDimitry Andric
188753f127fSDimitry Andric template <typename T>
189753f127fSDimitry Andric class SPIRVDuplicatesTracker : public SPIRVDuplicatesTrackerBase<const T *> {};
190753f127fSDimitry Andric
191bdd1243dSDimitry Andric template <>
192bdd1243dSDimitry Andric class SPIRVDuplicatesTracker<SPIRV::SpecialTypeDescriptor>
193bdd1243dSDimitry Andric : public SPIRVDuplicatesTrackerBase<SPIRV::SpecialTypeDescriptor> {};
194bdd1243dSDimitry Andric
195753f127fSDimitry Andric class SPIRVGeneralDuplicatesTracker {
196753f127fSDimitry Andric SPIRVDuplicatesTracker<Type> TT;
197753f127fSDimitry Andric SPIRVDuplicatesTracker<Constant> CT;
198753f127fSDimitry Andric SPIRVDuplicatesTracker<GlobalVariable> GT;
199753f127fSDimitry Andric SPIRVDuplicatesTracker<Function> FT;
200753f127fSDimitry Andric SPIRVDuplicatesTracker<Argument> AT;
201*0fca6ea1SDimitry Andric SPIRVDuplicatesTracker<MachineInstr> MT;
202bdd1243dSDimitry Andric SPIRVDuplicatesTracker<SPIRV::SpecialTypeDescriptor> ST;
203753f127fSDimitry Andric
204753f127fSDimitry Andric // NOTE: using MOs instead of regs to get rid of MF dependency to be able
205753f127fSDimitry Andric // to use flat data structure.
206753f127fSDimitry Andric // NOTE: replacing DenseMap with MapVector doesn't affect overall correctness
207753f127fSDimitry Andric // but makes LITs more stable, should prefer DenseMap still due to
208753f127fSDimitry Andric // significant perf difference.
209753f127fSDimitry Andric using SPIRVReg2EntryTy =
210753f127fSDimitry Andric MapVector<MachineOperand *, SPIRV::DTSortableEntry *>;
211753f127fSDimitry Andric
212753f127fSDimitry Andric template <typename T>
213753f127fSDimitry Andric void prebuildReg2Entry(SPIRVDuplicatesTracker<T> &DT,
214753f127fSDimitry Andric SPIRVReg2EntryTy &Reg2Entry);
215753f127fSDimitry Andric
216753f127fSDimitry Andric public:
217753f127fSDimitry Andric void buildDepsGraph(std::vector<SPIRV::DTSortableEntry *> &Graph,
218753f127fSDimitry Andric MachineModuleInfo *MMI);
219753f127fSDimitry Andric
add(const Type * Ty,const MachineFunction * MF,Register R)2205f757f3fSDimitry Andric void add(const Type *Ty, const MachineFunction *MF, Register R) {
221*0fca6ea1SDimitry Andric TT.add(unifyPtrType(Ty), MF, R);
2225f757f3fSDimitry Andric }
2235f757f3fSDimitry Andric
add(const Type * PointeeTy,unsigned AddressSpace,const MachineFunction * MF,Register R)224*0fca6ea1SDimitry Andric void add(const Type *PointeeTy, unsigned AddressSpace,
2255f757f3fSDimitry Andric const MachineFunction *MF, Register R) {
226*0fca6ea1SDimitry Andric ST.add(SPIRV::make_descr_pointee(unifyPtrType(PointeeTy), AddressSpace), MF,
2275f757f3fSDimitry Andric R);
228753f127fSDimitry Andric }
229753f127fSDimitry Andric
add(const Constant * C,const MachineFunction * MF,Register R)230753f127fSDimitry Andric void add(const Constant *C, const MachineFunction *MF, Register R) {
231753f127fSDimitry Andric CT.add(C, MF, R);
232753f127fSDimitry Andric }
233753f127fSDimitry Andric
add(const GlobalVariable * GV,const MachineFunction * MF,Register R)234753f127fSDimitry Andric void add(const GlobalVariable *GV, const MachineFunction *MF, Register R) {
235753f127fSDimitry Andric GT.add(GV, MF, R);
236753f127fSDimitry Andric }
237753f127fSDimitry Andric
add(const Function * F,const MachineFunction * MF,Register R)238753f127fSDimitry Andric void add(const Function *F, const MachineFunction *MF, Register R) {
239753f127fSDimitry Andric FT.add(F, MF, R);
240753f127fSDimitry Andric }
241753f127fSDimitry Andric
add(const Argument * Arg,const MachineFunction * MF,Register R)242753f127fSDimitry Andric void add(const Argument *Arg, const MachineFunction *MF, Register R) {
243753f127fSDimitry Andric AT.add(Arg, MF, R);
244753f127fSDimitry Andric }
245753f127fSDimitry Andric
add(const MachineInstr * MI,const MachineFunction * MF,Register R)246*0fca6ea1SDimitry Andric void add(const MachineInstr *MI, const MachineFunction *MF, Register R) {
247*0fca6ea1SDimitry Andric MT.add(MI, MF, R);
248*0fca6ea1SDimitry Andric }
249*0fca6ea1SDimitry Andric
add(const SPIRV::SpecialTypeDescriptor & TD,const MachineFunction * MF,Register R)250bdd1243dSDimitry Andric void add(const SPIRV::SpecialTypeDescriptor &TD, const MachineFunction *MF,
251bdd1243dSDimitry Andric Register R) {
252bdd1243dSDimitry Andric ST.add(TD, MF, R);
253bdd1243dSDimitry Andric }
254bdd1243dSDimitry Andric
find(const Type * Ty,const MachineFunction * MF)2555f757f3fSDimitry Andric Register find(const Type *Ty, const MachineFunction *MF) {
256*0fca6ea1SDimitry Andric return TT.find(unifyPtrType(Ty), MF);
2575f757f3fSDimitry Andric }
2585f757f3fSDimitry Andric
find(const Type * PointeeTy,unsigned AddressSpace,const MachineFunction * MF)259*0fca6ea1SDimitry Andric Register find(const Type *PointeeTy, unsigned AddressSpace,
2605f757f3fSDimitry Andric const MachineFunction *MF) {
2615f757f3fSDimitry Andric return ST.find(
262*0fca6ea1SDimitry Andric SPIRV::make_descr_pointee(unifyPtrType(PointeeTy), AddressSpace), MF);
263753f127fSDimitry Andric }
264753f127fSDimitry Andric
find(const Constant * C,const MachineFunction * MF)265753f127fSDimitry Andric Register find(const Constant *C, const MachineFunction *MF) {
266753f127fSDimitry Andric return CT.find(const_cast<Constant *>(C), MF);
267753f127fSDimitry Andric }
268753f127fSDimitry Andric
find(const GlobalVariable * GV,const MachineFunction * MF)269753f127fSDimitry Andric Register find(const GlobalVariable *GV, const MachineFunction *MF) {
270753f127fSDimitry Andric return GT.find(const_cast<GlobalVariable *>(GV), MF);
271753f127fSDimitry Andric }
272753f127fSDimitry Andric
find(const Function * F,const MachineFunction * MF)273753f127fSDimitry Andric Register find(const Function *F, const MachineFunction *MF) {
274753f127fSDimitry Andric return FT.find(const_cast<Function *>(F), MF);
275753f127fSDimitry Andric }
276753f127fSDimitry Andric
find(const Argument * Arg,const MachineFunction * MF)277753f127fSDimitry Andric Register find(const Argument *Arg, const MachineFunction *MF) {
278753f127fSDimitry Andric return AT.find(const_cast<Argument *>(Arg), MF);
279753f127fSDimitry Andric }
280fcaf7f86SDimitry Andric
find(const MachineInstr * MI,const MachineFunction * MF)281*0fca6ea1SDimitry Andric Register find(const MachineInstr *MI, const MachineFunction *MF) {
282*0fca6ea1SDimitry Andric return MT.find(const_cast<MachineInstr *>(MI), MF);
283*0fca6ea1SDimitry Andric }
284*0fca6ea1SDimitry Andric
find(const SPIRV::SpecialTypeDescriptor & TD,const MachineFunction * MF)285bdd1243dSDimitry Andric Register find(const SPIRV::SpecialTypeDescriptor &TD,
286bdd1243dSDimitry Andric const MachineFunction *MF) {
287bdd1243dSDimitry Andric return ST.find(TD, MF);
288bdd1243dSDimitry Andric }
289bdd1243dSDimitry Andric
getTypes()290fcaf7f86SDimitry Andric const SPIRVDuplicatesTracker<Type> *getTypes() { return &TT; }
291753f127fSDimitry Andric };
292753f127fSDimitry Andric } // namespace llvm
293fcaf7f86SDimitry Andric #endif // LLVM_LIB_TARGET_SPIRV_SPIRVDUPLICATESTRACKER_H
294