319 lines
10 KiB
C++
319 lines
10 KiB
C++
//===-- 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
|