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. 39753f127fSDimitry 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. 46753f127fSDimitry Andric bool getIsFunc() const { return Flags.IsFunc; } 47753f127fSDimitry Andric bool getIsGV() const { return Flags.IsGV; } 48753f127fSDimitry Andric void setIsFunc(bool V) { Flags.IsFunc = V; } 49753f127fSDimitry Andric void setIsGV(bool V) { Flags.IsGV = V; } 50753f127fSDimitry Andric 51753f127fSDimitry Andric const SmallVector<DTSortableEntry *, 2> &getDeps() const { return Deps; } 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 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 117*0fca6ea1SDimitry Andric inline SpecialTypeDescriptor make_descr_sampler() { 118*0fca6ea1SDimitry Andric return std::make_tuple(nullptr, 0U, SpecialTypeKind::STK_Sampler); 119bdd1243dSDimitry Andric } 120bdd1243dSDimitry Andric 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 125*0fca6ea1SDimitry Andric inline SpecialTypeDescriptor make_descr_event() { 126*0fca6ea1SDimitry Andric return std::make_tuple(nullptr, 0U, SpecialTypeKind::STK_DeviceEvent); 127bdd1243dSDimitry Andric } 128bdd1243dSDimitry Andric 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: 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 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 176753f127fSDimitry Andric const StorageTy &getAllUses() const { return Storage; } 177753f127fSDimitry Andric 178753f127fSDimitry Andric private: 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 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 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 230753f127fSDimitry Andric void add(const Constant *C, const MachineFunction *MF, Register R) { 231753f127fSDimitry Andric CT.add(C, MF, R); 232753f127fSDimitry Andric } 233753f127fSDimitry Andric 234753f127fSDimitry Andric void add(const GlobalVariable *GV, const MachineFunction *MF, Register R) { 235753f127fSDimitry Andric GT.add(GV, MF, R); 236753f127fSDimitry Andric } 237753f127fSDimitry Andric 238753f127fSDimitry Andric void add(const Function *F, const MachineFunction *MF, Register R) { 239753f127fSDimitry Andric FT.add(F, MF, R); 240753f127fSDimitry Andric } 241753f127fSDimitry Andric 242753f127fSDimitry Andric void add(const Argument *Arg, const MachineFunction *MF, Register R) { 243753f127fSDimitry Andric AT.add(Arg, MF, R); 244753f127fSDimitry Andric } 245753f127fSDimitry Andric 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 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 2555f757f3fSDimitry Andric Register find(const Type *Ty, const MachineFunction *MF) { 256*0fca6ea1SDimitry Andric return TT.find(unifyPtrType(Ty), MF); 2575f757f3fSDimitry Andric } 2585f757f3fSDimitry Andric 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 265753f127fSDimitry Andric Register find(const Constant *C, const MachineFunction *MF) { 266753f127fSDimitry Andric return CT.find(const_cast<Constant *>(C), MF); 267753f127fSDimitry Andric } 268753f127fSDimitry Andric 269753f127fSDimitry Andric Register find(const GlobalVariable *GV, const MachineFunction *MF) { 270753f127fSDimitry Andric return GT.find(const_cast<GlobalVariable *>(GV), MF); 271753f127fSDimitry Andric } 272753f127fSDimitry Andric 273753f127fSDimitry Andric Register find(const Function *F, const MachineFunction *MF) { 274753f127fSDimitry Andric return FT.find(const_cast<Function *>(F), MF); 275753f127fSDimitry Andric } 276753f127fSDimitry Andric 277753f127fSDimitry Andric Register find(const Argument *Arg, const MachineFunction *MF) { 278753f127fSDimitry Andric return AT.find(const_cast<Argument *>(Arg), MF); 279753f127fSDimitry Andric } 280fcaf7f86SDimitry Andric 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 285bdd1243dSDimitry Andric Register find(const SPIRV::SpecialTypeDescriptor &TD, 286bdd1243dSDimitry Andric const MachineFunction *MF) { 287bdd1243dSDimitry Andric return ST.find(TD, MF); 288bdd1243dSDimitry Andric } 289bdd1243dSDimitry Andric 290fcaf7f86SDimitry Andric const SPIRVDuplicatesTracker<Type> *getTypes() { return &TT; } 291753f127fSDimitry Andric }; 292753f127fSDimitry Andric } // namespace llvm 293fcaf7f86SDimitry Andric #endif // LLVM_LIB_TARGET_SPIRV_SPIRVDUPLICATESTRACKER_H 294