Files
gps/tools/local/circt/include/llvm/Analysis/DXILResource.h
T
2026-07-12 11:01:51 +03:00

729 lines
24 KiB
C++

//===- DXILResource.h - Representations of DXIL resources -------*- 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
//
//===----------------------------------------------------------------------===//
#ifndef LLVM_ANALYSIS_DXILRESOURCE_H
#define LLVM_ANALYSIS_DXILRESOURCE_H
#include "llvm/ADT/MapVector.h"
#include "llvm/ADT/SmallVector.h"
#include "llvm/ADT/StringRef.h"
#include "llvm/Frontend/HLSL/HLSLBinding.h"
#include "llvm/IR/DerivedTypes.h"
#include "llvm/IR/GlobalVariable.h"
#include "llvm/IR/PassManager.h"
#include "llvm/Pass.h"
#include "llvm/Support/Alignment.h"
#include "llvm/Support/Compiler.h"
#include "llvm/Support/DXILABI.h"
#include <cstdint>
namespace llvm {
class CallInst;
class DataLayout;
class LLVMContext;
class MDTuple;
class Value;
class DXILResourceTypeMap;
namespace dxil {
// Returns the resource name from dx_resource_handlefrombinding or
// dx_resource_handlefromimplicitbinding call
LLVM_ABI StringRef getResourceNameFromBindingCall(CallInst *CI);
/// The dx.RawBuffer target extension type
///
/// `target("dx.RawBuffer", Type, IsWriteable, IsROV)`
class RawBufferExtType : public TargetExtType {
public:
RawBufferExtType() = delete;
RawBufferExtType(const RawBufferExtType &) = delete;
RawBufferExtType &operator=(const RawBufferExtType &) = delete;
bool isStructured() const {
// TODO: We need to be more prescriptive here, but since there's some debate
// over whether byte address buffer should have a void type or an i8 type,
// accept either for now.
Type *Ty = getTypeParameter(0);
return !Ty->isVoidTy() && !Ty->isIntegerTy(8);
}
Type *getResourceType() const {
return isStructured() ? getTypeParameter(0) : nullptr;
}
bool isWriteable() const { return getIntParameter(0); }
bool isROV() const { return getIntParameter(1); }
static bool classof(const TargetExtType *T) {
return T->getName() == "dx.RawBuffer";
}
static bool classof(const Type *T) {
return isa<TargetExtType>(T) && classof(cast<TargetExtType>(T));
}
};
/// The dx.TypedBuffer target extension type
///
/// `target("dx.TypedBuffer", Type, IsWriteable, IsROV, IsSigned)`
class TypedBufferExtType : public TargetExtType {
public:
TypedBufferExtType() = delete;
TypedBufferExtType(const TypedBufferExtType &) = delete;
TypedBufferExtType &operator=(const TypedBufferExtType &) = delete;
Type *getResourceType() const { return getTypeParameter(0); }
bool isWriteable() const { return getIntParameter(0); }
bool isROV() const { return getIntParameter(1); }
bool isSigned() const { return getIntParameter(2); }
static bool classof(const TargetExtType *T) {
return T->getName() == "dx.TypedBuffer";
}
static bool classof(const Type *T) {
return isa<TargetExtType>(T) && classof(cast<TargetExtType>(T));
}
};
/// The dx.Texture target extension type
///
/// `target("dx.Texture", Type, IsWriteable, IsROV, IsSigned, Dimension)`
class TextureExtType : public TargetExtType {
public:
TextureExtType() = delete;
TextureExtType(const TextureExtType &) = delete;
TextureExtType &operator=(const TextureExtType &) = delete;
Type *getResourceType() const { return getTypeParameter(0); }
bool isWriteable() const { return getIntParameter(0); }
bool isROV() const { return getIntParameter(1); }
bool isSigned() const { return getIntParameter(2); }
dxil::ResourceKind getDimension() const {
return static_cast<dxil::ResourceKind>(getIntParameter(3));
}
static bool classof(const TargetExtType *T) {
return T->getName() == "dx.Texture";
}
static bool classof(const Type *T) {
return isa<TargetExtType>(T) && classof(cast<TargetExtType>(T));
}
};
/// The dx.MSTexture target extension type
///
/// `target("dx.MSTexture", Type, IsWriteable, Samples, IsSigned, Dimension)`
class MSTextureExtType : public TargetExtType {
public:
MSTextureExtType() = delete;
MSTextureExtType(const MSTextureExtType &) = delete;
MSTextureExtType &operator=(const MSTextureExtType &) = delete;
Type *getResourceType() const { return getTypeParameter(0); }
bool isWriteable() const { return getIntParameter(0); }
uint32_t getSampleCount() const { return getIntParameter(1); }
bool isSigned() const { return getIntParameter(2); }
dxil::ResourceKind getDimension() const {
return static_cast<dxil::ResourceKind>(getIntParameter(3));
}
static bool classof(const TargetExtType *T) {
return T->getName() == "dx.MSTexture";
}
static bool classof(const Type *T) {
return isa<TargetExtType>(T) && classof(cast<TargetExtType>(T));
}
};
/// The dx.FeedbackTexture target extension type
///
/// `target("dx.FeedbackTexture", FeedbackType, Dimension)`
class FeedbackTextureExtType : public TargetExtType {
public:
FeedbackTextureExtType() = delete;
FeedbackTextureExtType(const FeedbackTextureExtType &) = delete;
FeedbackTextureExtType &operator=(const FeedbackTextureExtType &) = delete;
dxil::SamplerFeedbackType getFeedbackType() const {
return static_cast<dxil::SamplerFeedbackType>(getIntParameter(0));
}
dxil::ResourceKind getDimension() const {
return static_cast<dxil::ResourceKind>(getIntParameter(1));
}
static bool classof(const TargetExtType *T) {
return T->getName() == "dx.FeedbackTexture";
}
static bool classof(const Type *T) {
return isa<TargetExtType>(T) && classof(cast<TargetExtType>(T));
}
};
/// The dx.CBuffer target extension type
///
/// `target("dx.CBuffer", <Type>, ...)`
class CBufferExtType : public TargetExtType {
public:
CBufferExtType() = delete;
CBufferExtType(const CBufferExtType &) = delete;
CBufferExtType &operator=(const CBufferExtType &) = delete;
Type *getResourceType() const { return getTypeParameter(0); }
static bool classof(const TargetExtType *T) {
return T->getName() == "dx.CBuffer";
}
static bool classof(const Type *T) {
return isa<TargetExtType>(T) && classof(cast<TargetExtType>(T));
}
};
/// The dx.Sampler target extension type
///
/// `target("dx.Sampler", SamplerType)`
class SamplerExtType : public TargetExtType {
public:
SamplerExtType() = delete;
SamplerExtType(const SamplerExtType &) = delete;
SamplerExtType &operator=(const SamplerExtType &) = delete;
dxil::SamplerType getSamplerType() const {
return static_cast<dxil::SamplerType>(getIntParameter(0));
}
static bool classof(const TargetExtType *T) {
return T->getName() == "dx.Sampler";
}
static bool classof(const Type *T) {
return isa<TargetExtType>(T) && classof(cast<TargetExtType>(T));
}
};
class AnyResourceExtType : public TargetExtType {
public:
AnyResourceExtType() = delete;
AnyResourceExtType(const AnyResourceExtType &) = delete;
AnyResourceExtType &operator=(const AnyResourceExtType &) = delete;
Type *getResourceType() const {
// Sampler and feedback resources do not have an underlying type.
if (isa<SamplerExtType>(this) || isa<FeedbackTextureExtType>(this))
return nullptr;
// All other resources store the type in a parameter.
return getTypeParameter(0);
}
static bool classof(const TargetExtType *T) {
return isa<RawBufferExtType>(T) || isa<TypedBufferExtType>(T) ||
isa<TextureExtType>(T) || isa<MSTextureExtType>(T) ||
isa<FeedbackTextureExtType>(T) || isa<CBufferExtType>(T) ||
isa<SamplerExtType>(T);
}
static bool classof(const Type *T) {
return isa<TargetExtType>(T) && classof(cast<TargetExtType>(T));
}
};
/// The dx.Layout target extension type
///
/// `target("dx.Layout", <Type>, <size>, [offsets...])`
class LayoutExtType : public TargetExtType {
public:
LayoutExtType() = delete;
LayoutExtType(const LayoutExtType &) = delete;
LayoutExtType &operator=(const LayoutExtType &) = delete;
Type *getWrappedType() const { return getTypeParameter(0); }
uint32_t getSize() const { return getIntParameter(0); }
uint32_t getOffsetOfElement(int I) const { return getIntParameter(I + 1); }
static bool classof(const TargetExtType *T) {
return T->getName() == "dx.Layout";
}
static bool classof(const Type *T) {
return isa<TargetExtType>(T) && classof(cast<TargetExtType>(T));
}
};
/// The dx.Padding target extension type
///
/// `target("dx.Padding", NumBytes)`
class PaddingExtType : public TargetExtType {
public:
PaddingExtType() = delete;
PaddingExtType(const PaddingExtType &) = delete;
PaddingExtType &operator=(const PaddingExtType &) = delete;
unsigned getNumBytes() const { return getIntParameter(0); }
static bool classof(const TargetExtType *T) {
return T->getName() == "dx.Padding";
}
static bool classof(const Type *T) {
return isa<TargetExtType>(T) && classof(cast<TargetExtType>(T));
}
};
//===----------------------------------------------------------------------===//
class ResourceTypeInfo {
public:
struct UAVInfo {
bool IsROV;
bool operator==(const UAVInfo &RHS) const { return IsROV == RHS.IsROV; }
bool operator!=(const UAVInfo &RHS) const { return !(*this == RHS); }
bool operator<(const UAVInfo &RHS) const { return IsROV < RHS.IsROV; }
};
struct StructInfo {
uint32_t Stride;
// Note: we store an integer here rather than using `MaybeAlign` because in
// GCC 7 MaybeAlign isn't trivial so having one in this union would delete
// our move constructor.
// See https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2018/p0602r4.html
uint32_t AlignLog2;
bool operator==(const StructInfo &RHS) const {
return std::tie(Stride, AlignLog2) == std::tie(RHS.Stride, RHS.AlignLog2);
}
bool operator!=(const StructInfo &RHS) const { return !(*this == RHS); }
bool operator<(const StructInfo &RHS) const {
return std::tie(Stride, AlignLog2) < std::tie(RHS.Stride, RHS.AlignLog2);
}
};
struct TypedInfo {
dxil::ElementType ElementTy;
dxil::ElementType DXILStorageTy;
uint32_t ElementCount;
bool operator==(const TypedInfo &RHS) const {
return std::tie(ElementTy, ElementCount) ==
std::tie(RHS.ElementTy, RHS.ElementCount);
}
bool operator!=(const TypedInfo &RHS) const { return !(*this == RHS); }
bool operator<(const TypedInfo &RHS) const {
return std::tie(ElementTy, ElementCount) <
std::tie(RHS.ElementTy, RHS.ElementCount);
}
};
private:
TargetExtType *HandleTy;
dxil::ResourceClass RC;
dxil::ResourceKind Kind;
public:
LLVM_ABI ResourceTypeInfo(TargetExtType *HandleTy,
const dxil::ResourceClass RC,
const dxil::ResourceKind Kind);
ResourceTypeInfo(TargetExtType *HandleTy)
: ResourceTypeInfo(HandleTy, {}, dxil::ResourceKind::Invalid) {}
TargetExtType *getHandleTy() const { return HandleTy; }
LLVM_ABI StructType *createElementStruct(StringRef CBufferName = "");
// Conditions to check before accessing specific views.
LLVM_ABI bool isUAV() const;
LLVM_ABI bool isCBuffer() const;
LLVM_ABI bool isSampler() const;
LLVM_ABI bool isStruct() const;
LLVM_ABI bool isTyped() const;
LLVM_ABI bool isFeedback() const;
LLVM_ABI bool isMultiSample() const;
// Views into the type.
LLVM_ABI UAVInfo getUAV() const;
LLVM_ABI uint32_t getCBufferSize(const DataLayout &DL) const;
LLVM_ABI dxil::SamplerType getSamplerType() const;
LLVM_ABI StructInfo getStruct(const DataLayout &DL) const;
LLVM_ABI TypedInfo getTyped() const;
LLVM_ABI dxil::SamplerFeedbackType getFeedbackType() const;
LLVM_ABI uint32_t getMultiSampleCount() const;
dxil::ResourceClass getResourceClass() const { return RC; }
dxil::ResourceKind getResourceKind() const { return Kind; }
LLVM_ABI bool operator==(const ResourceTypeInfo &RHS) const;
bool operator!=(const ResourceTypeInfo &RHS) const { return !(*this == RHS); }
LLVM_ABI bool operator<(const ResourceTypeInfo &RHS) const;
LLVM_ABI void print(raw_ostream &OS, const DataLayout &DL) const;
};
//===----------------------------------------------------------------------===//
enum class ResourceCounterDirection {
Increment,
Decrement,
Unknown,
Invalid,
};
class ResourceInfo {
public:
struct ResourceBinding {
uint32_t RecordID;
uint32_t Space;
uint32_t LowerBound;
uint32_t Size;
bool operator==(const ResourceBinding &RHS) const {
return std::tie(RecordID, Space, LowerBound, Size) ==
std::tie(RHS.RecordID, RHS.Space, RHS.LowerBound, RHS.Size);
}
bool operator!=(const ResourceBinding &RHS) const {
return !(*this == RHS);
}
bool operator<(const ResourceBinding &RHS) const {
// a size of 0 indicates unbounded. Accounting for when the size is 0
// guarantees a well ordered results.
const bool LHSIsUnbounded = Size == 0;
const bool RHSIsUnbounded = RHS.Size == 0;
return std::tie(RecordID, Space, LowerBound, LHSIsUnbounded, Size) <
std::tie(RHS.RecordID, RHS.Space, RHS.LowerBound, RHSIsUnbounded,
RHS.Size);
}
bool overlapsWith(const ResourceBinding &RHS) const {
if (Space != RHS.Space)
return false;
if (Size == 0)
return LowerBound < RHS.LowerBound;
return LowerBound + Size - 1 >= RHS.LowerBound;
}
};
private:
ResourceBinding Binding;
TargetExtType *HandleTy;
StringRef Name;
GlobalVariable *Symbol = nullptr;
public:
bool GloballyCoherent = false;
ResourceCounterDirection CounterDirection = ResourceCounterDirection::Unknown;
ResourceInfo(uint32_t RecordID, uint32_t Space, uint32_t LowerBound,
uint32_t Size, TargetExtType *HandleTy, StringRef Name = "",
GlobalVariable *Symbol = nullptr)
: Binding{RecordID, Space, LowerBound, Size}, HandleTy(HandleTy),
Name(Name), Symbol(Symbol) {}
void setBindingID(unsigned ID) { Binding.RecordID = ID; }
bool hasCounter() const {
return CounterDirection != ResourceCounterDirection::Unknown;
}
const ResourceBinding &getBinding() const { return Binding; }
TargetExtType *getHandleTy() const { return HandleTy; }
StringRef getName() const { return Name; }
bool hasSymbol() const { return Symbol; }
LLVM_ABI GlobalVariable *createSymbol(Module &M, StructType *Ty);
LLVM_ABI MDTuple *getAsMetadata(Module &M, dxil::ResourceTypeInfo &RTI) const;
LLVM_ABI std::pair<uint32_t, uint32_t>
getAnnotateProps(Module &M, dxil::ResourceTypeInfo &RTI) const;
bool operator==(const ResourceInfo &RHS) const {
return std::tie(Binding, HandleTy, Symbol, Name) ==
std::tie(RHS.Binding, RHS.HandleTy, RHS.Symbol, RHS.Name);
}
bool operator!=(const ResourceInfo &RHS) const { return !(*this == RHS); }
bool operator<(const ResourceInfo &RHS) const {
return Binding < RHS.Binding;
}
LLVM_ABI void print(raw_ostream &OS, dxil::ResourceTypeInfo &RTI,
const DataLayout &DL) const;
};
} // namespace dxil
//===----------------------------------------------------------------------===//
class DXILResourceTypeMap {
DenseMap<TargetExtType *, dxil::ResourceTypeInfo> Infos;
public:
LLVM_ABI bool invalidate(Module &M, const PreservedAnalyses &PA,
ModuleAnalysisManager::Invalidator &Inv);
dxil::ResourceTypeInfo &operator[](TargetExtType *Ty) {
auto It = Infos.find(Ty);
if (It != Infos.end())
return It->second;
auto [NewIt, Inserted] = Infos.try_emplace(Ty, Ty);
return NewIt->second;
}
};
class DXILResourceTypeAnalysis
: public AnalysisInfoMixin<DXILResourceTypeAnalysis> {
friend AnalysisInfoMixin<DXILResourceTypeAnalysis>;
LLVM_ABI static AnalysisKey Key;
public:
using Result = DXILResourceTypeMap;
DXILResourceTypeMap run(Module &M, ModuleAnalysisManager &AM) {
// Running the pass just generates an empty map, which will be filled when
// users of the pass query the results.
return Result();
}
};
class LLVM_ABI DXILResourceTypeWrapperPass : public ImmutablePass {
DXILResourceTypeMap DRTM;
virtual void anchor();
public:
static char ID;
DXILResourceTypeWrapperPass();
DXILResourceTypeMap &getResourceTypeMap() { return DRTM; }
const DXILResourceTypeMap &getResourceTypeMap() const { return DRTM; }
};
LLVM_ABI ModulePass *createDXILResourceTypeWrapperPassPass();
//===----------------------------------------------------------------------===//
class DXILResourceMap {
using CallMapTy = DenseMap<CallInst *, unsigned>;
SmallVector<dxil::ResourceInfo> Infos;
CallMapTy CallMap;
unsigned FirstUAV = 0;
unsigned FirstCBuffer = 0;
unsigned FirstSampler = 0;
bool HasInvalidDirection = false;
/// Populate all the resource instance data.
void populate(Module &M, DXILResourceTypeMap &DRTM);
/// Populate the map given the resource binding calls in the given module.
void populateResourceInfos(Module &M, DXILResourceTypeMap &DRTM);
/// Analyze and populate the directions of the resource counters.
void populateCounterDirections(Module &M);
/// Resolves a resource handle into a vector of ResourceInfos that
/// represent the possible unique creations of the handle. Certain cases are
/// ambiguous so multiple creation instructions may be returned. The resulting
/// ResourceInfo can be used to depuplicate unique handles that
/// reference the same resource
SmallVector<dxil::ResourceInfo *> findByUse(const Value *Key);
public:
using iterator = SmallVector<dxil::ResourceInfo>::iterator;
using const_iterator = SmallVector<dxil::ResourceInfo>::const_iterator;
iterator begin() { return Infos.begin(); }
const_iterator begin() const { return Infos.begin(); }
iterator end() { return Infos.end(); }
const_iterator end() const { return Infos.end(); }
bool empty() const { return Infos.empty(); }
iterator find(const CallInst *Key) {
auto Pos = CallMap.find(Key);
return Pos == CallMap.end() ? Infos.end() : (Infos.begin() + Pos->second);
}
const_iterator find(const CallInst *Key) const {
auto Pos = CallMap.find(Key);
return Pos == CallMap.end() ? Infos.end() : (Infos.begin() + Pos->second);
}
iterator srv_begin() { return begin(); }
const_iterator srv_begin() const { return begin(); }
iterator srv_end() { return begin() + FirstUAV; }
const_iterator srv_end() const { return begin() + FirstUAV; }
iterator_range<iterator> srvs() { return make_range(srv_begin(), srv_end()); }
iterator_range<const_iterator> srvs() const {
return make_range(srv_begin(), srv_end());
}
iterator uav_begin() { return begin() + FirstUAV; }
const_iterator uav_begin() const { return begin() + FirstUAV; }
iterator uav_end() { return begin() + FirstCBuffer; }
const_iterator uav_end() const { return begin() + FirstCBuffer; }
iterator_range<iterator> uavs() { return make_range(uav_begin(), uav_end()); }
iterator_range<const_iterator> uavs() const {
return make_range(uav_begin(), uav_end());
}
iterator cbuffer_begin() { return begin() + FirstCBuffer; }
const_iterator cbuffer_begin() const { return begin() + FirstCBuffer; }
iterator cbuffer_end() { return begin() + FirstSampler; }
const_iterator cbuffer_end() const { return begin() + FirstSampler; }
iterator_range<iterator> cbuffers() {
return make_range(cbuffer_begin(), cbuffer_end());
}
iterator_range<const_iterator> cbuffers() const {
return make_range(cbuffer_begin(), cbuffer_end());
}
iterator sampler_begin() { return begin() + FirstSampler; }
const_iterator sampler_begin() const { return begin() + FirstSampler; }
iterator sampler_end() { return end(); }
const_iterator sampler_end() const { return end(); }
iterator_range<iterator> samplers() {
return make_range(sampler_begin(), sampler_end());
}
iterator_range<const_iterator> samplers() const {
return make_range(sampler_begin(), sampler_end());
}
struct call_iterator
: iterator_adaptor_base<call_iterator, CallMapTy::iterator> {
call_iterator() = default;
call_iterator(CallMapTy::iterator Iter)
: call_iterator::iterator_adaptor_base(std::move(Iter)) {}
CallInst *operator*() const { return I->first; }
};
call_iterator call_begin() { return call_iterator(CallMap.begin()); }
call_iterator call_end() { return call_iterator(CallMap.end()); }
iterator_range<call_iterator> calls() {
return make_range(call_begin(), call_end());
}
bool hasInvalidCounterDirection() const { return HasInvalidDirection; }
LLVM_ABI void print(raw_ostream &OS, DXILResourceTypeMap &DRTM,
const DataLayout &DL) const;
friend class DXILResourceAnalysis;
friend class DXILResourceWrapperPass;
};
class DXILResourceAnalysis : public AnalysisInfoMixin<DXILResourceAnalysis> {
friend AnalysisInfoMixin<DXILResourceAnalysis>;
LLVM_ABI static AnalysisKey Key;
public:
using Result = DXILResourceMap;
/// Gather resource info for the module \c M.
LLVM_ABI DXILResourceMap run(Module &M, ModuleAnalysisManager &AM);
};
/// Printer pass for the \c DXILResourceAnalysis results.
class DXILResourcePrinterPass
: public RequiredPassInfoMixin<DXILResourcePrinterPass> {
raw_ostream &OS;
public:
explicit DXILResourcePrinterPass(raw_ostream &OS) : OS(OS) {}
LLVM_ABI PreservedAnalyses run(Module &M, ModuleAnalysisManager &AM);
};
class LLVM_ABI DXILResourceWrapperPass : public ModulePass {
std::unique_ptr<DXILResourceMap> Map;
DXILResourceTypeMap *DRTM;
public:
static char ID; // Class identification, replacement for typeinfo
DXILResourceWrapperPass();
~DXILResourceWrapperPass() override;
const DXILResourceMap &getResourceMap() const { return *Map; }
DXILResourceMap &getResourceMap() { return *Map; }
void getAnalysisUsage(AnalysisUsage &AU) const override;
bool runOnModule(Module &M) override;
void releaseMemory() override;
void print(raw_ostream &OS, const Module *M) const override;
void dump() const;
};
LLVM_ABI ModulePass *createDXILResourceWrapperPassPass();
//===----------------------------------------------------------------------===//
// DXILResourceBindingInfo stores the results of DXILResourceBindingAnalysis
// which analyses all llvm.dx.resource.handlefrombinding calls in the module
// and puts together lists of used virtual register spaces and available
// virtual register slot ranges for each binding type.
// It also stores additional information found during the analysis such as
// whether the module uses implicit bindings or if any of the bindings overlap.
//
// This information will be used in DXILResourceImplicitBindings pass to assign
// register slots to resources with implicit bindings, and in a
// post-optimization validation pass that will raise diagnostic about
// overlapping bindings.
class DXILResourceBindingInfo {
hlsl::BindingInfo Bindings;
bool HasImplicitBinding = false;
bool HasOverlappingBinding = false;
// Populate the resource binding info given explicit resource binding calls
// in the module.
void populate(Module &M, DXILResourceTypeMap &DRTM);
public:
bool hasImplicitBinding() const { return HasImplicitBinding; }
void setHasImplicitBinding(bool Value) { HasImplicitBinding = Value; }
bool hasOverlappingBinding() const { return HasOverlappingBinding; }
void setHasOverlappingBinding(bool Value) { HasOverlappingBinding = Value; }
std::optional<uint32_t> findAvailableBinding(dxil::ResourceClass RC,
uint32_t Space, int32_t Size) {
return Bindings.findAvailableBinding(RC, Space, Size);
}
friend class DXILResourceBindingAnalysis;
friend class DXILResourceBindingWrapperPass;
};
class DXILResourceBindingAnalysis
: public AnalysisInfoMixin<DXILResourceBindingAnalysis> {
friend AnalysisInfoMixin<DXILResourceBindingAnalysis>;
LLVM_ABI static AnalysisKey Key;
public:
using Result = DXILResourceBindingInfo;
LLVM_ABI DXILResourceBindingInfo run(Module &M, ModuleAnalysisManager &AM);
};
class LLVM_ABI DXILResourceBindingWrapperPass : public ModulePass {
std::unique_ptr<DXILResourceBindingInfo> BindingInfo;
public:
static char ID;
DXILResourceBindingWrapperPass();
~DXILResourceBindingWrapperPass() override;
DXILResourceBindingInfo &getBindingInfo() { return *BindingInfo; }
const DXILResourceBindingInfo &getBindingInfo() const { return *BindingInfo; }
void getAnalysisUsage(AnalysisUsage &AU) const override;
bool runOnModule(Module &M) override;
void releaseMemory() override;
};
LLVM_ABI ModulePass *createDXILResourceBindingWrapperPassPass();
} // namespace llvm
#endif // LLVM_ANALYSIS_DXILRESOURCE_H