//===-- SPIRVDuplicatesTracker.h - SPIR-V Duplicates Tracker ----*- C++ -*-===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // //===----------------------------------------------------------------------===// // // General infrastructure for keeping track of the values that according to // the SPIR-V binary layout should be global to the whole module. // //===----------------------------------------------------------------------===// #ifndef LLVM_LIB_TARGET_SPIRV_SPIRVDUPLICATESTRACKER_H #define LLVM_LIB_TARGET_SPIRV_SPIRVDUPLICATESTRACKER_H #include "MCTargetDesc/SPIRVBaseInfo.h" #include "MCTargetDesc/SPIRVMCTargetDesc.h" #include "llvm/ADT/DenseMap.h" #include "llvm/ADT/MapVector.h" #include "llvm/CodeGen/GlobalISel/MachineIRBuilder.h" #include "llvm/CodeGen/MachineModuleInfo.h" #include namespace llvm { namespace SPIRV { // NOTE: using MapVector instead of DenseMap because it helps getting // everything ordered in a stable manner for a price of extra (NumKeys)*PtrSize // memory and expensive removals which do not happen anyway. class DTSortableEntry : public MapVector { SmallVector Deps; struct FlagsTy { unsigned IsFunc : 1; unsigned IsGV : 1; // NOTE: bit-field default init is a C++20 feature. FlagsTy() : IsFunc(0), IsGV(0) {} }; FlagsTy Flags; public: // Common hoisting utility doesn't support function, because their hoisting // require hoisting of params as well. bool getIsFunc() const { return Flags.IsFunc; } bool getIsGV() const { return Flags.IsGV; } void setIsFunc(bool V) { Flags.IsFunc = V; } void setIsGV(bool V) { Flags.IsGV = V; } const SmallVector &getDeps() const { return Deps; } void addDep(DTSortableEntry *E) { Deps.push_back(E); } }; } // namespace SPIRV template class SPIRVDuplicatesTrackerBase { public: // NOTE: using MapVector instead of DenseMap helps getting everything ordered // in a stable manner for a price of extra (NumKeys)*PtrSize memory and // expensive removals which don't happen anyway. using StorageTy = MapVector; private: StorageTy Storage; public: void add(KeyTy V, const MachineFunction *MF, Register R) { if (find(V, MF).isValid()) return; Storage[V][MF] = R; if (std::is_same::type>::type>() || std::is_same::type>::type>()) Storage[V].setIsFunc(true); if (std::is_same::type>::type>()) Storage[V].setIsGV(true); } Register find(KeyTy V, const MachineFunction *MF) const { auto iter = Storage.find(V); if (iter != Storage.end()) { auto Map = iter->second; auto iter2 = Map.find(MF); if (iter2 != Map.end()) return iter2->second; } return Register(); } const StorageTy &getAllUses() const { return Storage; } private: StorageTy &getAllUses() { return Storage; } // The friend class needs to have access to the internal storage // to be able to build dependency graph, can't declare only one // function a 'friend' due to the incomplete declaration at this point // and mutual dependency problems. friend class SPIRVGeneralDuplicatesTracker; }; template class SPIRVDuplicatesTracker : public SPIRVDuplicatesTrackerBase {}; class SPIRVGeneralDuplicatesTracker { SPIRVDuplicatesTracker TT; SPIRVDuplicatesTracker CT; SPIRVDuplicatesTracker GT; SPIRVDuplicatesTracker FT; SPIRVDuplicatesTracker AT; // NOTE: using MOs instead of regs to get rid of MF dependency to be able // to use flat data structure. // NOTE: replacing DenseMap with MapVector doesn't affect overall correctness // but makes LITs more stable, should prefer DenseMap still due to // significant perf difference. using SPIRVReg2EntryTy = MapVector; template void prebuildReg2Entry(SPIRVDuplicatesTracker &DT, SPIRVReg2EntryTy &Reg2Entry); public: void buildDepsGraph(std::vector &Graph, MachineModuleInfo *MMI); void add(const Type *T, const MachineFunction *MF, Register R) { TT.add(T, MF, R); } void add(const Constant *C, const MachineFunction *MF, Register R) { CT.add(C, MF, R); } void add(const GlobalVariable *GV, const MachineFunction *MF, Register R) { GT.add(GV, MF, R); } void add(const Function *F, const MachineFunction *MF, Register R) { FT.add(F, MF, R); } void add(const Argument *Arg, const MachineFunction *MF, Register R) { AT.add(Arg, MF, R); } Register find(const Type *T, const MachineFunction *MF) { return TT.find(const_cast(T), MF); } Register find(const Constant *C, const MachineFunction *MF) { return CT.find(const_cast(C), MF); } Register find(const GlobalVariable *GV, const MachineFunction *MF) { return GT.find(const_cast(GV), MF); } Register find(const Function *F, const MachineFunction *MF) { return FT.find(const_cast(F), MF); } Register find(const Argument *Arg, const MachineFunction *MF) { return AT.find(const_cast(Arg), MF); } const SPIRVDuplicatesTracker *getTypes() { return &TT; } }; } // namespace llvm #endif // LLVM_LIB_TARGET_SPIRV_SPIRVDUPLICATESTRACKER_H