| //===-- 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 <type_traits> | |
| 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<const MachineFunction *, Register> { | |
| SmallVector<DTSortableEntry *, 2> 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<DTSortableEntry *, 2> &getDeps() const { return Deps; } | |
| void addDep(DTSortableEntry *E) { Deps.push_back(E); } | |
| }; | |
| struct SpecialTypeDescriptor { | |
| enum SpecialTypeKind { | |
| STK_Empty = 0, | |
| STK_Image, | |
| STK_SampledImage, | |
| STK_Sampler, | |
| STK_Pipe, | |
| STK_DeviceEvent, | |
| STK_Last = -1 | |
| }; | |
| SpecialTypeKind Kind; | |
| unsigned Hash; | |
| SpecialTypeDescriptor() = delete; | |
| SpecialTypeDescriptor(SpecialTypeKind K) : Kind(K) { Hash = Kind; } | |
| unsigned getHash() const { return Hash; } | |
| virtual ~SpecialTypeDescriptor() {} | |
| }; | |
| struct ImageTypeDescriptor : public SpecialTypeDescriptor { | |
| union ImageAttrs { | |
| struct BitFlags { | |
| unsigned Dim : 3; | |
| unsigned Depth : 2; | |
| unsigned Arrayed : 1; | |
| unsigned MS : 1; | |
| unsigned Sampled : 2; | |
| unsigned ImageFormat : 6; | |
| unsigned AQ : 2; | |
| } Flags; | |
| unsigned Val; | |
| }; | |
| ImageTypeDescriptor(const Type *SampledTy, unsigned Dim, unsigned Depth, | |
| unsigned Arrayed, unsigned MS, unsigned Sampled, | |
| unsigned ImageFormat, unsigned AQ = 0) | |
| : SpecialTypeDescriptor(SpecialTypeKind::STK_Image) { | |
| ImageAttrs Attrs; | |
| Attrs.Val = 0; | |
| Attrs.Flags.Dim = Dim; | |
| Attrs.Flags.Depth = Depth; | |
| Attrs.Flags.Arrayed = Arrayed; | |
| Attrs.Flags.MS = MS; | |
| Attrs.Flags.Sampled = Sampled; | |
| Attrs.Flags.ImageFormat = ImageFormat; | |
| Attrs.Flags.AQ = AQ; | |
| Hash = (DenseMapInfo<Type *>().getHashValue(SampledTy) & 0xffff) ^ | |
| ((Attrs.Val << 8) | Kind); | |
| } | |
| static bool classof(const SpecialTypeDescriptor *TD) { | |
| return TD->Kind == SpecialTypeKind::STK_Image; | |
| } | |
| }; | |
| struct SampledImageTypeDescriptor : public SpecialTypeDescriptor { | |
| SampledImageTypeDescriptor(const Type *SampledTy, const MachineInstr *ImageTy) | |
| : SpecialTypeDescriptor(SpecialTypeKind::STK_SampledImage) { | |
| assert(ImageTy->getOpcode() == SPIRV::OpTypeImage); | |
| ImageTypeDescriptor TD( | |
| SampledTy, ImageTy->getOperand(2).getImm(), | |
| ImageTy->getOperand(3).getImm(), ImageTy->getOperand(4).getImm(), | |
| ImageTy->getOperand(5).getImm(), ImageTy->getOperand(6).getImm(), | |
| ImageTy->getOperand(7).getImm(), ImageTy->getOperand(8).getImm()); | |
| Hash = TD.getHash() ^ Kind; | |
| } | |
| static bool classof(const SpecialTypeDescriptor *TD) { | |
| return TD->Kind == SpecialTypeKind::STK_SampledImage; | |
| } | |
| }; | |
| struct SamplerTypeDescriptor : public SpecialTypeDescriptor { | |
| SamplerTypeDescriptor() | |
| : SpecialTypeDescriptor(SpecialTypeKind::STK_Sampler) { | |
| Hash = Kind; | |
| } | |
| static bool classof(const SpecialTypeDescriptor *TD) { | |
| return TD->Kind == SpecialTypeKind::STK_Sampler; | |
| } | |
| }; | |
| struct PipeTypeDescriptor : public SpecialTypeDescriptor { | |
| PipeTypeDescriptor(uint8_t AQ) | |
| : SpecialTypeDescriptor(SpecialTypeKind::STK_Pipe) { | |
| Hash = (AQ << 8) | Kind; | |
| } | |
| static bool classof(const SpecialTypeDescriptor *TD) { | |
| return TD->Kind == SpecialTypeKind::STK_Pipe; | |
| } | |
| }; | |
| struct DeviceEventTypeDescriptor : public SpecialTypeDescriptor { | |
| DeviceEventTypeDescriptor() | |
| : SpecialTypeDescriptor(SpecialTypeKind::STK_DeviceEvent) { | |
| Hash = Kind; | |
| } | |
| static bool classof(const SpecialTypeDescriptor *TD) { | |
| return TD->Kind == SpecialTypeKind::STK_DeviceEvent; | |
| } | |
| }; | |
| } // namespace SPIRV | |
| template <> struct DenseMapInfo<SPIRV::SpecialTypeDescriptor> { | |
| static inline SPIRV::SpecialTypeDescriptor getEmptyKey() { | |
| return SPIRV::SpecialTypeDescriptor( | |
| SPIRV::SpecialTypeDescriptor::STK_Empty); | |
| } | |
| static inline SPIRV::SpecialTypeDescriptor getTombstoneKey() { | |
| return SPIRV::SpecialTypeDescriptor(SPIRV::SpecialTypeDescriptor::STK_Last); | |
| } | |
| static unsigned getHashValue(SPIRV::SpecialTypeDescriptor Val) { | |
| return Val.getHash(); | |
| } | |
| static bool isEqual(SPIRV::SpecialTypeDescriptor LHS, | |
| SPIRV::SpecialTypeDescriptor RHS) { | |
| return getHashValue(LHS) == getHashValue(RHS); | |
| } | |
| }; | |
| template <typename KeyTy> 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<KeyTy, SPIRV::DTSortableEntry>; | |
| 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<Function, | |
| typename std::remove_const< | |
| typename std::remove_pointer<KeyTy>::type>::type>() || | |
| std::is_same<Argument, | |
| typename std::remove_const< | |
| typename std::remove_pointer<KeyTy>::type>::type>()) | |
| Storage[V].setIsFunc(true); | |
| if (std::is_same<GlobalVariable, | |
| typename std::remove_const< | |
| typename std::remove_pointer<KeyTy>::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 <typename T> | |
| class SPIRVDuplicatesTracker : public SPIRVDuplicatesTrackerBase<const T *> {}; | |
| template <> | |
| class SPIRVDuplicatesTracker<SPIRV::SpecialTypeDescriptor> | |
| : public SPIRVDuplicatesTrackerBase<SPIRV::SpecialTypeDescriptor> {}; | |
| class SPIRVGeneralDuplicatesTracker { | |
| SPIRVDuplicatesTracker<Type> TT; | |
| SPIRVDuplicatesTracker<Constant> CT; | |
| SPIRVDuplicatesTracker<GlobalVariable> GT; | |
| SPIRVDuplicatesTracker<Function> FT; | |
| SPIRVDuplicatesTracker<Argument> AT; | |
| SPIRVDuplicatesTracker<SPIRV::SpecialTypeDescriptor> ST; | |
| // 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<MachineOperand *, SPIRV::DTSortableEntry *>; | |
| template <typename T> | |
| void prebuildReg2Entry(SPIRVDuplicatesTracker<T> &DT, | |
| SPIRVReg2EntryTy &Reg2Entry); | |
| public: | |
| void buildDepsGraph(std::vector<SPIRV::DTSortableEntry *> &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); | |
| } | |
| void add(const SPIRV::SpecialTypeDescriptor &TD, const MachineFunction *MF, | |
| Register R) { | |
| ST.add(TD, MF, R); | |
| } | |
| Register find(const Type *T, const MachineFunction *MF) { | |
| return TT.find(const_cast<Type *>(T), MF); | |
| } | |
| Register find(const Constant *C, const MachineFunction *MF) { | |
| return CT.find(const_cast<Constant *>(C), MF); | |
| } | |
| Register find(const GlobalVariable *GV, const MachineFunction *MF) { | |
| return GT.find(const_cast<GlobalVariable *>(GV), MF); | |
| } | |
| Register find(const Function *F, const MachineFunction *MF) { | |
| return FT.find(const_cast<Function *>(F), MF); | |
| } | |
| Register find(const Argument *Arg, const MachineFunction *MF) { | |
| return AT.find(const_cast<Argument *>(Arg), MF); | |
| } | |
| Register find(const SPIRV::SpecialTypeDescriptor &TD, | |
| const MachineFunction *MF) { | |
| return ST.find(TD, MF); | |
| } | |
| const SPIRVDuplicatesTracker<Type> *getTypes() { return &TT; } | |
| }; | |
| } // namespace llvm | |
| #endif // LLVM_LIB_TARGET_SPIRV_SPIRVDUPLICATESTRACKER_H |