diff --git a/llvm/include/llvm/Analysis/DXILResource.h b/llvm/include/llvm/Analysis/DXILResource.h index 6b577c02f0545..b3bcd244094d0 100644 --- a/llvm/include/llvm/Analysis/DXILResource.h +++ b/llvm/include/llvm/Analysis/DXILResource.h @@ -11,6 +11,8 @@ #include "llvm/ADT/MapVector.h" #include "llvm/ADT/StringRef.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" @@ -18,12 +20,183 @@ namespace llvm { class CallInst; +class DataLayout; class LLVMContext; class MDTuple; class Value; namespace dxil { +/// 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(T) && classof(cast(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(T) && classof(cast(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(getIntParameter(3)); + } + + static bool classof(const TargetExtType *T) { + return T->getName() == "dx.Texture"; + } + static bool classof(const Type *T) { + return isa(T) && classof(cast(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(getIntParameter(3)); + } + + static bool classof(const TargetExtType *T) { + return T->getName() == "dx.MSTexture"; + } + static bool classof(const Type *T) { + return isa(T) && classof(cast(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(getIntParameter(0)); + } + dxil::ResourceKind getDimension() const { + return static_cast(getIntParameter(1)); + } + + static bool classof(const TargetExtType *T) { + return T->getName() == "dx.FeedbackTexture"; + } + static bool classof(const Type *T) { + return isa(T) && classof(cast(T)); + } +}; + +/// The dx.CBuffer target extension type +/// +/// `target("dx.CBuffer", , ...)` +class CBufferExtType : public TargetExtType { +public: + CBufferExtType() = delete; + CBufferExtType(const CBufferExtType &) = delete; + CBufferExtType &operator=(const CBufferExtType &) = delete; + + Type *getResourceType() const { return getTypeParameter(0); } + uint32_t getCBufferSize() const { return getIntParameter(0); } + + static bool classof(const TargetExtType *T) { + return T->getName() == "dx.CBuffer"; + } + static bool classof(const Type *T) { + return isa(T) && classof(cast(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(getIntParameter(0)); + } + + static bool classof(const TargetExtType *T) { + return T->getName() == "dx.Sampler"; + } + static bool classof(const Type *T) { + return isa(T) && classof(cast(T)); + } +}; + +//===----------------------------------------------------------------------===// + class ResourceInfo { public: struct ResourceBinding { @@ -93,55 +266,27 @@ class ResourceInfo { } }; - struct MSInfo { - uint32_t Count; - - bool operator==(const MSInfo &RHS) const { return Count == RHS.Count; } - bool operator!=(const MSInfo &RHS) const { return !(*this == RHS); } - bool operator<(const MSInfo &RHS) const { return Count < RHS.Count; } - }; - - struct FeedbackInfo { - dxil::SamplerFeedbackType Type; - - bool operator==(const FeedbackInfo &RHS) const { return Type == RHS.Type; } - bool operator!=(const FeedbackInfo &RHS) const { return !(*this == RHS); } - bool operator<(const FeedbackInfo &RHS) const { return Type < RHS.Type; } - }; - private: - // Universal properties. - Value *Symbol; - StringRef Name; + ResourceBinding Binding; + TargetExtType *HandleTy; + + // GloballyCoherent and HasCounter aren't really part of the type and need to + // be determined by analysis, so they're just provided directly when we + // construct these. + bool GloballyCoherent; + bool HasCounter; dxil::ResourceClass RC; dxil::ResourceKind Kind; - ResourceBinding Binding = {}; - - // Resource class dependent properties. - // CBuffer, Sampler, and RawBuffer end here. - union { - UAVInfo UAVFlags; // UAV - uint32_t CBufferSize; // CBuffer - dxil::SamplerType SamplerTy; // Sampler - }; - - // Resource kind dependent properties. - union { - StructInfo Struct; // StructuredBuffer - TypedInfo Typed; // All SRV/UAV except Raw/StructuredBuffer - FeedbackInfo Feedback; // FeedbackTexture - }; - - MSInfo MultiSample; - public: - ResourceInfo(dxil::ResourceClass RC, dxil::ResourceKind Kind, Value *Symbol, - StringRef Name) - : Symbol(Symbol), Name(Name), RC(RC), Kind(Kind) {} + ResourceInfo(uint32_t RecordID, uint32_t Space, uint32_t LowerBound, + uint32_t Size, TargetExtType *HandleTy, + bool GloballyCoherent = false, bool HasCounter = false); + + TargetExtType *getHandleTy() const { return HandleTy; } - // Conditions to check before accessing union members. + // Conditions to check before accessing specific views. bool isUAV() const; bool isCBuffer() const; bool isSampler() const; @@ -150,148 +295,69 @@ class ResourceInfo { bool isFeedback() const; bool isMultiSample() const; - void bind(uint32_t RecordID, uint32_t Space, uint32_t LowerBound, - uint32_t Size) { - Binding.RecordID = RecordID; - Binding.Space = Space; - Binding.LowerBound = LowerBound; - Binding.Size = Size; - } - const ResourceBinding &getBinding() const { return Binding; } - void setUAV(bool GloballyCoherent, bool HasCounter, bool IsROV) { - assert(isUAV() && "Not a UAV"); - UAVFlags.GloballyCoherent = GloballyCoherent; - UAVFlags.HasCounter = HasCounter; - UAVFlags.IsROV = IsROV; - } - const UAVInfo &getUAV() const { - assert(isUAV() && "Not a UAV"); - return UAVFlags; - } - void setCBuffer(uint32_t Size) { - assert(isCBuffer() && "Not a CBuffer"); - CBufferSize = Size; - } - void setSampler(dxil::SamplerType Ty) { SamplerTy = Ty; } - void setStruct(uint32_t Stride, MaybeAlign Alignment) { - assert(isStruct() && "Not a Struct"); - Struct.Stride = Stride; - Struct.AlignLog2 = Alignment ? Log2(*Alignment) : 0; - } - void setTyped(dxil::ElementType ElementTy, uint32_t ElementCount) { - assert(isTyped() && "Not Typed"); - Typed.ElementTy = ElementTy; - Typed.ElementCount = ElementCount; - } - const TypedInfo &getTyped() const { - assert(isTyped() && "Not typed"); - return Typed; - } - void setFeedback(dxil::SamplerFeedbackType Type) { - assert(isFeedback() && "Not Feedback"); - Feedback.Type = Type; - } - void setMultiSample(uint32_t Count) { - assert(isMultiSample() && "Not MultiSampled"); - MultiSample.Count = Count; + // Views into the type. + UAVInfo getUAV() const; + uint32_t getCBufferSize(const DataLayout &DL) const; + dxil::SamplerType getSamplerType() const; + StructInfo getStruct(const DataLayout &DL) const; + TypedInfo getTyped() const; + dxil::SamplerFeedbackType getFeedbackType() const; + uint32_t getMultiSampleCount() const; + + StringRef getName() const { + // TODO: Get the name from the symbol once we include one here. + return ""; } - const MSInfo &getMultiSample() const { - assert(isMultiSample() && "Not MultiSampled"); - return MultiSample; - } - - StringRef getName() const { return Name; } dxil::ResourceClass getResourceClass() const { return RC; } dxil::ResourceKind getResourceKind() const { return Kind; } + void setBindingID(unsigned ID) { Binding.RecordID = ID; } + + const ResourceBinding &getBinding() const { return Binding; } + + MDTuple *getAsMetadata(Module &M) const; + std::pair getAnnotateProps(Module &M) const; + bool operator==(const ResourceInfo &RHS) const; bool operator!=(const ResourceInfo &RHS) const { return !(*this == RHS); } bool operator<(const ResourceInfo &RHS) const; - static ResourceInfo SRV(Value *Symbol, StringRef Name, - dxil::ElementType ElementTy, uint32_t ElementCount, - dxil::ResourceKind Kind); - static ResourceInfo RawBuffer(Value *Symbol, StringRef Name); - static ResourceInfo StructuredBuffer(Value *Symbol, StringRef Name, - uint32_t Stride, MaybeAlign Alignment); - static ResourceInfo Texture2DMS(Value *Symbol, StringRef Name, - dxil::ElementType ElementTy, - uint32_t ElementCount, uint32_t SampleCount); - static ResourceInfo Texture2DMSArray(Value *Symbol, StringRef Name, - dxil::ElementType ElementTy, - uint32_t ElementCount, - uint32_t SampleCount); - - static ResourceInfo UAV(Value *Symbol, StringRef Name, - dxil::ElementType ElementTy, uint32_t ElementCount, - bool GloballyCoherent, bool IsROV, - dxil::ResourceKind Kind); - static ResourceInfo RWRawBuffer(Value *Symbol, StringRef Name, - bool GloballyCoherent, bool IsROV); - static ResourceInfo RWStructuredBuffer(Value *Symbol, StringRef Name, - uint32_t Stride, MaybeAlign Alignment, - bool GloballyCoherent, bool IsROV, - bool HasCounter); - static ResourceInfo RWTexture2DMS(Value *Symbol, StringRef Name, - dxil::ElementType ElementTy, - uint32_t ElementCount, uint32_t SampleCount, - bool GloballyCoherent); - static ResourceInfo RWTexture2DMSArray(Value *Symbol, StringRef Name, - dxil::ElementType ElementTy, - uint32_t ElementCount, - uint32_t SampleCount, - bool GloballyCoherent); - static ResourceInfo FeedbackTexture2D(Value *Symbol, StringRef Name, - dxil::SamplerFeedbackType FeedbackTy); - static ResourceInfo - FeedbackTexture2DArray(Value *Symbol, StringRef Name, - dxil::SamplerFeedbackType FeedbackTy); - - static ResourceInfo CBuffer(Value *Symbol, StringRef Name, uint32_t Size); - - static ResourceInfo Sampler(Value *Symbol, StringRef Name, - dxil::SamplerType SamplerTy); - - MDTuple *getAsMetadata(LLVMContext &Ctx) const; - - std::pair getAnnotateProps() const; - - void print(raw_ostream &OS) const; + void print(raw_ostream &OS, const DataLayout &DL) const; }; } // namespace dxil +//===----------------------------------------------------------------------===// + class DXILResourceMap { - SmallVector Resources; + SmallVector Infos; DenseMap CallMap; unsigned FirstUAV = 0; unsigned FirstCBuffer = 0; unsigned FirstSampler = 0; + /// Populate the map given the resource binding calls in the given module. + void populate(Module &M); + public: using iterator = SmallVector::iterator; using const_iterator = SmallVector::const_iterator; - DXILResourceMap( - SmallVectorImpl> &&CIToRI); + iterator begin() { return Infos.begin(); } + const_iterator begin() const { return Infos.begin(); } + iterator end() { return Infos.end(); } + const_iterator end() const { return Infos.end(); } - iterator begin() { return Resources.begin(); } - const_iterator begin() const { return Resources.begin(); } - iterator end() { return Resources.end(); } - const_iterator end() const { return Resources.end(); } - - bool empty() const { return Resources.empty(); } + bool empty() const { return Infos.empty(); } iterator find(const CallInst *Key) { auto Pos = CallMap.find(Key); - return Pos == CallMap.end() ? Resources.end() - : (Resources.begin() + Pos->second); + 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() ? Resources.end() - : (Resources.begin() + Pos->second); + return Pos == CallMap.end() ? Infos.end() : (Infos.begin() + Pos->second); } iterator srv_begin() { return begin(); } @@ -334,7 +400,10 @@ class DXILResourceMap { return make_range(sampler_begin(), sampler_end()); } - void print(raw_ostream &OS) const; + void print(raw_ostream &OS, const DataLayout &DL) const; + + friend class DXILResourceAnalysis; + friend class DXILResourceWrapperPass; }; class DXILResourceAnalysis : public AnalysisInfoMixin { @@ -362,7 +431,7 @@ class DXILResourcePrinterPass : public PassInfoMixin { }; class DXILResourceWrapperPass : public ModulePass { - std::unique_ptr ResourceMap; + std::unique_ptr Map; public: static char ID; // Class identification, replacement for typeinfo @@ -370,8 +439,8 @@ class DXILResourceWrapperPass : public ModulePass { DXILResourceWrapperPass(); ~DXILResourceWrapperPass() override; - const DXILResourceMap &getResourceMap() const { return *ResourceMap; } - DXILResourceMap &getResourceMap() { return *ResourceMap; } + const DXILResourceMap &getResourceMap() const { return *Map; } + DXILResourceMap &getResourceMap() { return *Map; } void getAnalysisUsage(AnalysisUsage &AU) const override; bool runOnModule(Module &M) override; diff --git a/llvm/lib/Analysis/DXILResource.cpp b/llvm/lib/Analysis/DXILResource.cpp index 2802480481690..3fa9d67488b0c 100644 --- a/llvm/lib/Analysis/DXILResource.cpp +++ b/llvm/lib/Analysis/DXILResource.cpp @@ -8,6 +8,7 @@ #include "llvm/Analysis/DXILResource.h" #include "llvm/ADT/APInt.h" +#include "llvm/ADT/SmallString.h" #include "llvm/IR/Constants.h" #include "llvm/IR/DerivedTypes.h" #include "llvm/IR/DiagnosticInfo.h" @@ -17,6 +18,7 @@ #include "llvm/IR/Metadata.h" #include "llvm/IR/Module.h" #include "llvm/InitializePasses.h" +#include "llvm/Support/FormatVariadic.h" #define DEBUG_TYPE "dxil-resource" @@ -148,6 +150,65 @@ static StringRef getSamplerFeedbackTypeName(SamplerFeedbackType SFT) { llvm_unreachable("Unhandled SamplerFeedbackType"); } +static dxil::ElementType toDXILElementType(Type *Ty, bool IsSigned) { + // TODO: Handle unorm, snorm, and packed. + Ty = Ty->getScalarType(); + + if (Ty->isIntegerTy()) { + switch (Ty->getIntegerBitWidth()) { + case 16: + return IsSigned ? ElementType::I16 : ElementType::U16; + case 32: + return IsSigned ? ElementType::I32 : ElementType::U32; + case 64: + return IsSigned ? ElementType::I64 : ElementType::U64; + case 1: + default: + return ElementType::Invalid; + } + } else if (Ty->isFloatTy()) { + return ElementType::F32; + } else if (Ty->isDoubleTy()) { + return ElementType::F64; + } else if (Ty->isHalfTy()) { + return ElementType::F16; + } + + return ElementType::Invalid; +} + +ResourceInfo::ResourceInfo(uint32_t RecordID, uint32_t Space, + uint32_t LowerBound, uint32_t Size, + TargetExtType *HandleTy, bool GloballyCoherent, + bool HasCounter) + : Binding{RecordID, Space, LowerBound, Size}, HandleTy(HandleTy), + GloballyCoherent(GloballyCoherent), HasCounter(HasCounter) { + if (auto *Ty = dyn_cast(HandleTy)) { + RC = Ty->isWriteable() ? ResourceClass::UAV : ResourceClass::SRV; + Kind = Ty->isStructured() ? ResourceKind::StructuredBuffer + : ResourceKind::RawBuffer; + } else if (auto *Ty = dyn_cast(HandleTy)) { + RC = Ty->isWriteable() ? ResourceClass::UAV : ResourceClass::SRV; + Kind = ResourceKind::TypedBuffer; + } else if (auto *Ty = dyn_cast(HandleTy)) { + RC = Ty->isWriteable() ? ResourceClass::UAV : ResourceClass::SRV; + Kind = Ty->getDimension(); + } else if (auto *Ty = dyn_cast(HandleTy)) { + RC = Ty->isWriteable() ? ResourceClass::UAV : ResourceClass::SRV; + Kind = Ty->getDimension(); + } else if (auto *Ty = dyn_cast(HandleTy)) { + RC = ResourceClass::UAV; + Kind = Ty->getDimension(); + } else if (isa(HandleTy)) { + RC = ResourceClass::CBuffer; + Kind = ResourceKind::CBuffer; + } else if (isa(HandleTy)) { + RC = ResourceClass::Sampler; + Kind = ResourceKind::Sampler; + } else + llvm_unreachable("Unknown handle type"); +} + bool ResourceInfo::isUAV() const { return RC == ResourceClass::UAV; } bool ResourceInfo::isCBuffer() const { return RC == ResourceClass::CBuffer; } @@ -197,184 +258,127 @@ bool ResourceInfo::isMultiSample() const { Kind == ResourceKind::Texture2DMSArray; } -ResourceInfo ResourceInfo::SRV(Value *Symbol, StringRef Name, - ElementType ElementTy, uint32_t ElementCount, - ResourceKind Kind) { - ResourceInfo RI(ResourceClass::SRV, Kind, Symbol, Name); - assert(RI.isTyped() && !(RI.isStruct() || RI.isMultiSample()) && - "Invalid ResourceKind for SRV constructor."); - RI.setTyped(ElementTy, ElementCount); - return RI; -} - -ResourceInfo ResourceInfo::RawBuffer(Value *Symbol, StringRef Name) { - ResourceInfo RI(ResourceClass::SRV, ResourceKind::RawBuffer, Symbol, Name); - return RI; -} - -ResourceInfo ResourceInfo::StructuredBuffer(Value *Symbol, StringRef Name, - uint32_t Stride, - MaybeAlign Alignment) { - ResourceInfo RI(ResourceClass::SRV, ResourceKind::StructuredBuffer, Symbol, - Name); - RI.setStruct(Stride, Alignment); - return RI; -} - -ResourceInfo ResourceInfo::Texture2DMS(Value *Symbol, StringRef Name, - ElementType ElementTy, - uint32_t ElementCount, - uint32_t SampleCount) { - ResourceInfo RI(ResourceClass::SRV, ResourceKind::Texture2DMS, Symbol, Name); - RI.setTyped(ElementTy, ElementCount); - RI.setMultiSample(SampleCount); - return RI; -} - -ResourceInfo ResourceInfo::Texture2DMSArray(Value *Symbol, StringRef Name, - ElementType ElementTy, - uint32_t ElementCount, - uint32_t SampleCount) { - ResourceInfo RI(ResourceClass::SRV, ResourceKind::Texture2DMSArray, Symbol, - Name); - RI.setTyped(ElementTy, ElementCount); - RI.setMultiSample(SampleCount); - return RI; -} - -ResourceInfo ResourceInfo::UAV(Value *Symbol, StringRef Name, - ElementType ElementTy, uint32_t ElementCount, - bool GloballyCoherent, bool IsROV, - ResourceKind Kind) { - ResourceInfo RI(ResourceClass::UAV, Kind, Symbol, Name); - assert(RI.isTyped() && !(RI.isStruct() || RI.isMultiSample()) && - "Invalid ResourceKind for UAV constructor."); - RI.setTyped(ElementTy, ElementCount); - RI.setUAV(GloballyCoherent, /*HasCounter=*/false, IsROV); - return RI; -} - -ResourceInfo ResourceInfo::RWRawBuffer(Value *Symbol, StringRef Name, - bool GloballyCoherent, bool IsROV) { - ResourceInfo RI(ResourceClass::UAV, ResourceKind::RawBuffer, Symbol, Name); - RI.setUAV(GloballyCoherent, /*HasCounter=*/false, IsROV); - return RI; -} - -ResourceInfo ResourceInfo::RWStructuredBuffer(Value *Symbol, StringRef Name, - uint32_t Stride, - MaybeAlign Alignment, - bool GloballyCoherent, bool IsROV, - bool HasCounter) { - ResourceInfo RI(ResourceClass::UAV, ResourceKind::StructuredBuffer, Symbol, - Name); - RI.setStruct(Stride, Alignment); - RI.setUAV(GloballyCoherent, HasCounter, IsROV); - return RI; -} - -ResourceInfo ResourceInfo::RWTexture2DMS(Value *Symbol, StringRef Name, - ElementType ElementTy, - uint32_t ElementCount, - uint32_t SampleCount, - bool GloballyCoherent) { - ResourceInfo RI(ResourceClass::UAV, ResourceKind::Texture2DMS, Symbol, Name); - RI.setTyped(ElementTy, ElementCount); - RI.setUAV(GloballyCoherent, /*HasCounter=*/false, /*IsROV=*/false); - RI.setMultiSample(SampleCount); - return RI; -} - -ResourceInfo ResourceInfo::RWTexture2DMSArray(Value *Symbol, StringRef Name, - ElementType ElementTy, - uint32_t ElementCount, - uint32_t SampleCount, - bool GloballyCoherent) { - ResourceInfo RI(ResourceClass::UAV, ResourceKind::Texture2DMSArray, Symbol, - Name); - RI.setTyped(ElementTy, ElementCount); - RI.setUAV(GloballyCoherent, /*HasCounter=*/false, /*IsROV=*/false); - RI.setMultiSample(SampleCount); - return RI; -} - -ResourceInfo ResourceInfo::FeedbackTexture2D(Value *Symbol, StringRef Name, - SamplerFeedbackType FeedbackTy) { - ResourceInfo RI(ResourceClass::UAV, ResourceKind::FeedbackTexture2D, Symbol, - Name); - RI.setUAV(/*GloballyCoherent=*/false, /*HasCounter=*/false, /*IsROV=*/false); - RI.setFeedback(FeedbackTy); - return RI; -} - -ResourceInfo -ResourceInfo::FeedbackTexture2DArray(Value *Symbol, StringRef Name, - SamplerFeedbackType FeedbackTy) { - ResourceInfo RI(ResourceClass::UAV, ResourceKind::FeedbackTexture2DArray, - Symbol, Name); - RI.setUAV(/*GloballyCoherent=*/false, /*HasCounter=*/false, /*IsROV=*/false); - RI.setFeedback(FeedbackTy); - return RI; -} - -ResourceInfo ResourceInfo::CBuffer(Value *Symbol, StringRef Name, - uint32_t Size) { - ResourceInfo RI(ResourceClass::CBuffer, ResourceKind::CBuffer, Symbol, Name); - RI.setCBuffer(Size); - return RI; -} - -ResourceInfo ResourceInfo::Sampler(Value *Symbol, StringRef Name, - SamplerType SamplerTy) { - ResourceInfo RI(ResourceClass::Sampler, ResourceKind::Sampler, Symbol, Name); - RI.setSampler(SamplerTy); - return RI; +static bool isROV(dxil::ResourceKind Kind, TargetExtType *Ty) { + switch (Kind) { + case ResourceKind::Texture1D: + case ResourceKind::Texture2D: + case ResourceKind::Texture3D: + case ResourceKind::TextureCube: + case ResourceKind::Texture1DArray: + case ResourceKind::Texture2DArray: + case ResourceKind::TextureCubeArray: + return cast(Ty)->isROV(); + case ResourceKind::TypedBuffer: + return cast(Ty)->isROV(); + case ResourceKind::RawBuffer: + case ResourceKind::StructuredBuffer: + return cast(Ty)->isROV(); + case ResourceKind::Texture2DMS: + case ResourceKind::Texture2DMSArray: + case ResourceKind::FeedbackTexture2D: + case ResourceKind::FeedbackTexture2DArray: + return false; + case ResourceKind::CBuffer: + case ResourceKind::Sampler: + case ResourceKind::TBuffer: + case ResourceKind::RTAccelerationStructure: + case ResourceKind::Invalid: + case ResourceKind::NumEntries: + llvm_unreachable("Resource cannot be ROV"); + } + llvm_unreachable("Unhandled ResourceKind enum"); } -bool ResourceInfo::operator==(const ResourceInfo &RHS) const { - if (std::tie(Symbol, Name, Binding, RC, Kind) != - std::tie(RHS.Symbol, RHS.Name, RHS.Binding, RHS.RC, RHS.Kind)) - return false; - if (isCBuffer() && RHS.isCBuffer() && CBufferSize != RHS.CBufferSize) - return false; - if (isSampler() && RHS.isSampler() && SamplerTy != RHS.SamplerTy) - return false; - if (isUAV() && RHS.isUAV() && UAVFlags != RHS.UAVFlags) - return false; - if (isStruct() && RHS.isStruct() && Struct != RHS.Struct) - return false; - if (isFeedback() && RHS.isFeedback() && Feedback != RHS.Feedback) - return false; - if (isTyped() && RHS.isTyped() && Typed != RHS.Typed) - return false; - if (isMultiSample() && RHS.isMultiSample() && MultiSample != RHS.MultiSample) - return false; - return true; +ResourceInfo::UAVInfo ResourceInfo::getUAV() const { + assert(isUAV() && "Not a UAV"); + return {GloballyCoherent, HasCounter, isROV(Kind, HandleTy)}; } -bool ResourceInfo::operator<(const ResourceInfo &RHS) const { - // Skip the symbol to avoid non-determinism, and the name to keep a consistent - // ordering even when we strip reflection data. - if (std::tie(Binding, RC, Kind) < std::tie(RHS.Binding, RHS.RC, RHS.Kind)) - return true; - if (isCBuffer() && RHS.isCBuffer() && CBufferSize < RHS.CBufferSize) - return true; - if (isSampler() && RHS.isSampler() && SamplerTy < RHS.SamplerTy) - return true; - if (isUAV() && RHS.isUAV() && UAVFlags < RHS.UAVFlags) - return true; - if (isStruct() && RHS.isStruct() && Struct < RHS.Struct) - return true; - if (isFeedback() && RHS.isFeedback() && Feedback < RHS.Feedback) - return true; - if (isTyped() && RHS.isTyped() && Typed < RHS.Typed) - return true; - if (isMultiSample() && RHS.isMultiSample() && MultiSample < RHS.MultiSample) - return true; - return false; +uint32_t ResourceInfo::getCBufferSize(const DataLayout &DL) const { + assert(isCBuffer() && "Not a CBuffer"); + return cast(HandleTy)->getCBufferSize(); +} + +dxil::SamplerType ResourceInfo::getSamplerType() const { + assert(isSampler() && "Not a Sampler"); + return cast(HandleTy)->getSamplerType(); +} + +ResourceInfo::StructInfo ResourceInfo::getStruct(const DataLayout &DL) const { + assert(isStruct() && "Not a Struct"); + + Type *ElTy = cast(HandleTy)->getResourceType(); + + uint32_t Stride = DL.getTypeAllocSize(ElTy); + MaybeAlign Alignment; + if (auto *STy = dyn_cast(ElTy)) + Alignment = DL.getStructLayout(STy)->getAlignment(); + uint32_t AlignLog2 = Alignment ? Log2(*Alignment) : 0; + return {Stride, AlignLog2}; } -MDTuple *ResourceInfo::getAsMetadata(LLVMContext &Ctx) const { +static std::pair getTypedElementType(dxil::ResourceKind Kind, + TargetExtType *Ty) { + switch (Kind) { + case ResourceKind::Texture1D: + case ResourceKind::Texture2D: + case ResourceKind::Texture3D: + case ResourceKind::TextureCube: + case ResourceKind::Texture1DArray: + case ResourceKind::Texture2DArray: + case ResourceKind::TextureCubeArray: { + auto *RTy = cast(Ty); + return {RTy->getResourceType(), RTy->isSigned()}; + } + case ResourceKind::Texture2DMS: + case ResourceKind::Texture2DMSArray: { + auto *RTy = cast(Ty); + return {RTy->getResourceType(), RTy->isSigned()}; + } + case ResourceKind::TypedBuffer: { + auto *RTy = cast(Ty); + return {RTy->getResourceType(), RTy->isSigned()}; + } + case ResourceKind::RawBuffer: + case ResourceKind::StructuredBuffer: + case ResourceKind::FeedbackTexture2D: + case ResourceKind::FeedbackTexture2DArray: + case ResourceKind::CBuffer: + case ResourceKind::Sampler: + case ResourceKind::TBuffer: + case ResourceKind::RTAccelerationStructure: + case ResourceKind::Invalid: + case ResourceKind::NumEntries: + llvm_unreachable("Resource is not typed"); + } + llvm_unreachable("Unhandled ResourceKind enum"); +} + +ResourceInfo::TypedInfo ResourceInfo::getTyped() const { + assert(isTyped() && "Not typed"); + + auto [ElTy, IsSigned] = getTypedElementType(Kind, HandleTy); + dxil::ElementType ET = toDXILElementType(ElTy, IsSigned); + uint32_t Count = 1; + if (auto *VTy = dyn_cast(ElTy)) + Count = VTy->getNumElements(); + return {ET, Count}; +} + +dxil::SamplerFeedbackType ResourceInfo::getFeedbackType() const { + assert(isFeedback() && "Not Feedback"); + return cast(HandleTy)->getFeedbackType(); +} + +uint32_t ResourceInfo::getMultiSampleCount() const { + assert(isMultiSample() && "Not MultiSampled"); + return cast(HandleTy)->getSampleCount(); +} + +MDTuple *ResourceInfo::getAsMetadata(Module &M) const { + LLVMContext &Ctx = M.getContext(); + const DataLayout &DL = M.getDataLayout(); + SmallVector MDVals; Type *I32Ty = Type::getInt32Ty(Ctx); @@ -389,22 +393,28 @@ MDTuple *ResourceInfo::getAsMetadata(LLVMContext &Ctx) const { }; MDVals.push_back(getIntMD(Binding.RecordID)); - MDVals.push_back(ValueAsMetadata::get(Symbol)); - MDVals.push_back(MDString::get(Ctx, Name)); + + // TODO: We need API to create a symbol of the appropriate type to emit here. + // See https://github.com/llvm/llvm-project/issues/116849 + MDVals.push_back( + ValueAsMetadata::get(UndefValue::get(PointerType::getUnqual(Ctx)))); + MDVals.push_back(MDString::get(Ctx, "")); + MDVals.push_back(getIntMD(Binding.Space)); MDVals.push_back(getIntMD(Binding.LowerBound)); MDVals.push_back(getIntMD(Binding.Size)); if (isCBuffer()) { - MDVals.push_back(getIntMD(CBufferSize)); + MDVals.push_back(getIntMD(getCBufferSize(DL))); MDVals.push_back(nullptr); } else if (isSampler()) { - MDVals.push_back(getIntMD(llvm::to_underlying(SamplerTy))); + MDVals.push_back(getIntMD(llvm::to_underlying(getSamplerType()))); MDVals.push_back(nullptr); } else { - MDVals.push_back(getIntMD(llvm::to_underlying(Kind))); + MDVals.push_back(getIntMD(llvm::to_underlying(getResourceKind()))); if (isUAV()) { + ResourceInfo::UAVInfo UAVFlags = getUAV(); MDVals.push_back(getBoolMD(UAVFlags.GloballyCoherent)); MDVals.push_back(getBoolMD(UAVFlags.HasCounter)); MDVals.push_back(getBoolMD(UAVFlags.IsROV)); @@ -412,7 +422,7 @@ MDTuple *ResourceInfo::getAsMetadata(LLVMContext &Ctx) const { // All SRVs include sample count in the metadata, but it's only meaningful // for multi-sampled textured. Also, UAVs can be multisampled in SM6.7+, // but this just isn't reflected in the metadata at all. - uint32_t SampleCount = isMultiSample() ? MultiSample.Count : 0; + uint32_t SampleCount = isMultiSample() ? getMultiSampleCount() : 0; MDVals.push_back(getIntMD(SampleCount)); } @@ -421,14 +431,14 @@ MDTuple *ResourceInfo::getAsMetadata(LLVMContext &Ctx) const { if (isStruct()) { Tags.push_back( getIntMD(llvm::to_underlying(ExtPropTags::StructuredBufferStride))); - Tags.push_back(getIntMD(Struct.Stride)); + Tags.push_back(getIntMD(getStruct(DL).Stride)); } else if (isTyped()) { Tags.push_back(getIntMD(llvm::to_underlying(ExtPropTags::ElementType))); - Tags.push_back(getIntMD(llvm::to_underlying(Typed.ElementTy))); + Tags.push_back(getIntMD(llvm::to_underlying(getTyped().ElementTy))); } else if (isFeedback()) { Tags.push_back( getIntMD(llvm::to_underlying(ExtPropTags::SamplerFeedbackKind))); - Tags.push_back(getIntMD(llvm::to_underlying(Feedback.Type))); + Tags.push_back(getIntMD(llvm::to_underlying(getFeedbackType()))); } MDVals.push_back(Tags.empty() ? nullptr : MDNode::get(Ctx, Tags)); } @@ -436,17 +446,20 @@ MDTuple *ResourceInfo::getAsMetadata(LLVMContext &Ctx) const { return MDNode::get(Ctx, MDVals); } -std::pair ResourceInfo::getAnnotateProps() const { - uint32_t ResourceKind = llvm::to_underlying(Kind); - uint32_t AlignLog2 = isStruct() ? Struct.AlignLog2 : 0; +std::pair ResourceInfo::getAnnotateProps(Module &M) const { + const DataLayout &DL = M.getDataLayout(); + + uint32_t ResourceKind = llvm::to_underlying(getResourceKind()); + uint32_t AlignLog2 = isStruct() ? getStruct(DL).AlignLog2 : 0; bool IsUAV = isUAV(); + ResourceInfo::UAVInfo UAVFlags = IsUAV ? getUAV() : ResourceInfo::UAVInfo{}; bool IsROV = IsUAV && UAVFlags.IsROV; bool IsGloballyCoherent = IsUAV && UAVFlags.GloballyCoherent; uint8_t SamplerCmpOrHasCounter = 0; if (IsUAV) SamplerCmpOrHasCounter = UAVFlags.HasCounter; else if (isSampler()) - SamplerCmpOrHasCounter = SamplerTy == SamplerType::Comparison; + SamplerCmpOrHasCounter = getSamplerType() == SamplerType::Comparison; // TODO: Document this format. Currently the only reference is the // implementation of dxc's DxilResourceProperties struct. @@ -460,15 +473,16 @@ std::pair ResourceInfo::getAnnotateProps() const { uint32_t Word1 = 0; if (isStruct()) - Word1 = Struct.Stride; + Word1 = getStruct(DL).Stride; else if (isCBuffer()) - Word1 = CBufferSize; + Word1 = getCBufferSize(DL); else if (isFeedback()) - Word1 = llvm::to_underlying(Feedback.Type); + Word1 = llvm::to_underlying(getFeedbackType()); else if (isTyped()) { + ResourceInfo::TypedInfo Typed = getTyped(); uint32_t CompType = llvm::to_underlying(Typed.ElementTy); uint32_t CompCount = Typed.ElementCount; - uint32_t SampleCount = isMultiSample() ? MultiSample.Count : 0; + uint32_t SampleCount = isMultiSample() ? getMultiSampleCount() : 0; Word1 |= (CompType & 0xFF) << 0; Word1 |= (CompCount & 0xFF) << 8; @@ -478,255 +492,131 @@ std::pair ResourceInfo::getAnnotateProps() const { return {Word0, Word1}; } -void ResourceInfo::print(raw_ostream &OS) const { - OS << " Symbol: "; - Symbol->printAsOperand(OS); - OS << "\n"; +bool ResourceInfo::operator==(const ResourceInfo &RHS) const { + return std::tie(Binding, HandleTy, GloballyCoherent, HasCounter) == + std::tie(RHS.Binding, RHS.HandleTy, RHS.GloballyCoherent, + RHS.HasCounter); +} - OS << " Name: \"" << Name << "\"\n" - << " Binding:\n" +bool ResourceInfo::operator<(const ResourceInfo &RHS) const { + // An empty datalayout is sufficient for sorting purposes. + DataLayout DummyDL; + if (std::tie(Binding, RC, Kind) < std::tie(RHS.Binding, RHS.RC, RHS.Kind)) + return true; + if (isCBuffer() && RHS.isCBuffer() && + getCBufferSize(DummyDL) < RHS.getCBufferSize(DummyDL)) + return true; + if (isSampler() && RHS.isSampler() && getSamplerType() < RHS.getSamplerType()) + return true; + if (isUAV() && RHS.isUAV() && getUAV() < RHS.getUAV()) + return true; + if (isStruct() && RHS.isStruct() && + getStruct(DummyDL) < RHS.getStruct(DummyDL)) + return true; + if (isFeedback() && RHS.isFeedback() && + getFeedbackType() < RHS.getFeedbackType()) + return true; + if (isTyped() && RHS.isTyped() && getTyped() < RHS.getTyped()) + return true; + if (isMultiSample() && RHS.isMultiSample() && + getMultiSampleCount() < RHS.getMultiSampleCount()) + return true; + return false; +} + +void ResourceInfo::print(raw_ostream &OS, const DataLayout &DL) const { + OS << " Binding:\n" << " Record ID: " << Binding.RecordID << "\n" << " Space: " << Binding.Space << "\n" << " Lower Bound: " << Binding.LowerBound << "\n" - << " Size: " << Binding.Size << "\n" - << " Class: " << getResourceClassName(RC) << "\n" + << " Size: " << Binding.Size << "\n"; + + OS << " Class: " << getResourceClassName(RC) << "\n" << " Kind: " << getResourceKindName(Kind) << "\n"; if (isCBuffer()) { - OS << " CBuffer size: " << CBufferSize << "\n"; + OS << " CBuffer size: " << getCBufferSize(DL) << "\n"; } else if (isSampler()) { - OS << " Sampler Type: " << getSamplerTypeName(SamplerTy) << "\n"; + OS << " Sampler Type: " << getSamplerTypeName(getSamplerType()) << "\n"; } else { if (isUAV()) { + UAVInfo UAVFlags = getUAV(); OS << " Globally Coherent: " << UAVFlags.GloballyCoherent << "\n" << " HasCounter: " << UAVFlags.HasCounter << "\n" << " IsROV: " << UAVFlags.IsROV << "\n"; } if (isMultiSample()) - OS << " Sample Count: " << MultiSample.Count << "\n"; + OS << " Sample Count: " << getMultiSampleCount() << "\n"; if (isStruct()) { + StructInfo Struct = getStruct(DL); OS << " Buffer Stride: " << Struct.Stride << "\n"; OS << " Alignment: " << Struct.AlignLog2 << "\n"; } else if (isTyped()) { + TypedInfo Typed = getTyped(); OS << " Element Type: " << getElementTypeName(Typed.ElementTy) << "\n" << " Element Count: " << Typed.ElementCount << "\n"; } else if (isFeedback()) - OS << " Feedback Type: " << getSamplerFeedbackTypeName(Feedback.Type) + OS << " Feedback Type: " << getSamplerFeedbackTypeName(getFeedbackType()) << "\n"; } } //===----------------------------------------------------------------------===// -// ResourceMapper -static dxil::ElementType toDXILElementType(Type *Ty, bool IsSigned) { - // TODO: Handle unorm, snorm, and packed. - Ty = Ty->getScalarType(); +void DXILResourceMap::populate(Module &M) { + SmallVector> CIToInfo; - if (Ty->isIntegerTy()) { - switch (Ty->getIntegerBitWidth()) { - case 16: - return IsSigned ? ElementType::I16 : ElementType::U16; - case 32: - return IsSigned ? ElementType::I32 : ElementType::U32; - case 64: - return IsSigned ? ElementType::I64 : ElementType::U64; - case 1: + for (Function &F : M.functions()) { + if (!F.isDeclaration()) + continue; + LLVM_DEBUG(dbgs() << "Function: " << F.getName() << "\n"); + Intrinsic::ID ID = F.getIntrinsicID(); + switch (ID) { default: - return ElementType::Invalid; - } - } else if (Ty->isFloatTy()) { - return ElementType::F32; - } else if (Ty->isDoubleTy()) { - return ElementType::F64; - } else if (Ty->isHalfTy()) { - return ElementType::F16; - } - - return ElementType::Invalid; -} - -namespace { - -class ResourceMapper { - Module &M; - LLVMContext &Context; - SmallVector> Resources; - -public: - ResourceMapper(Module &M) : M(M), Context(M.getContext()) {} - - void diagnoseHandle(CallInst *CI, const Twine &Msg, - DiagnosticSeverity Severity = DS_Error) { - std::string S; - raw_string_ostream SS(S); - CI->printAsOperand(SS); - DiagnosticInfoUnsupported Diag(*CI->getFunction(), Msg + ": " + SS.str(), - CI->getDebugLoc(), Severity); - Context.diagnose(Diag); - } - - ResourceInfo *mapBufferType(CallInst *CI, TargetExtType *HandleTy, - bool IsTyped) { - if (HandleTy->getNumTypeParameters() != 1 || - HandleTy->getNumIntParameters() != (IsTyped ? 3 : 2)) { - diagnoseHandle(CI, Twine("Invalid buffer target type")); - return nullptr; - } - - Type *ElTy = HandleTy->getTypeParameter(0); - unsigned IsWriteable = HandleTy->getIntParameter(0); - unsigned IsROV = HandleTy->getIntParameter(1); - bool IsSigned = IsTyped && HandleTy->getIntParameter(2); - - ResourceClass RC = IsWriteable ? ResourceClass::UAV : ResourceClass::SRV; - ResourceKind Kind; - if (IsTyped) - Kind = ResourceKind::TypedBuffer; - else if (ElTy->isIntegerTy(8)) - Kind = ResourceKind::RawBuffer; - else - Kind = ResourceKind::StructuredBuffer; - - // TODO: We need to lower to a typed pointer, can we smuggle the type - // through? - Value *Symbol = UndefValue::get(PointerType::getUnqual(Context)); - // TODO: We don't actually keep track of the name right now... - StringRef Name = ""; - - // Note that we return a pointer into the vector's storage. This is okay as - // long as we don't add more elements until we're done with the pointer. - auto &Pair = - Resources.emplace_back(CI, ResourceInfo{RC, Kind, Symbol, Name}); - ResourceInfo *RI = &Pair.second; - - if (RI->isUAV()) - // TODO: We need analysis for GloballyCoherent and HasCounter - RI->setUAV(false, false, IsROV); - - if (RI->isTyped()) { - dxil::ElementType ET = toDXILElementType(ElTy, IsSigned); - uint32_t Count = 1; - if (auto *VTy = dyn_cast(ElTy)) - Count = VTy->getNumElements(); - RI->setTyped(ET, Count); - } else if (RI->isStruct()) { - const DataLayout &DL = M.getDataLayout(); - - // This mimics what DXC does. Notably, we only ever set the alignment if - // the type is actually a struct type. - uint32_t Stride = DL.getTypeAllocSize(ElTy); - MaybeAlign Alignment; - if (auto *STy = dyn_cast(ElTy)) - Alignment = DL.getStructLayout(STy)->getAlignment(); - RI->setStruct(Stride, Alignment); - } - - return RI; - } + continue; + case Intrinsic::dx_handle_fromBinding: { + auto *HandleTy = cast(F.getReturnType()); - ResourceInfo *mapHandleIntrin(CallInst *CI) { - FunctionType *FTy = CI->getFunctionType(); - Type *RetTy = FTy->getReturnType(); - auto *HandleTy = dyn_cast(RetTy); - if (!HandleTy) { - diagnoseHandle(CI, "dx.handle.fromBinding requires target type"); - return nullptr; - } - - StringRef TypeName = HandleTy->getName(); - if (TypeName == "dx.TypedBuffer") { - return mapBufferType(CI, HandleTy, /*IsTyped=*/true); - } else if (TypeName == "dx.RawBuffer") { - return mapBufferType(CI, HandleTy, /*IsTyped=*/false); - } else if (TypeName == "dx.CBuffer") { - // TODO: implement - diagnoseHandle(CI, "dx.CBuffer handles are not implemented yet"); - return nullptr; - } else if (TypeName == "dx.Sampler") { - // TODO: implement - diagnoseHandle(CI, "dx.Sampler handles are not implemented yet"); - return nullptr; - } else if (TypeName == "dx.Texture") { - // TODO: implement - diagnoseHandle(CI, "dx.Texture handles are not implemented yet"); - return nullptr; - } - - diagnoseHandle(CI, "Invalid target(dx) type"); - return nullptr; - } - - ResourceInfo *mapHandleFromBinding(CallInst *CI) { - assert(CI->getIntrinsicID() == Intrinsic::dx_handle_fromBinding && - "Must be dx.handle.fromBinding intrinsic"); - - ResourceInfo *RI = mapHandleIntrin(CI); - if (!RI) - return nullptr; - - uint32_t Space = cast(CI->getArgOperand(0))->getZExtValue(); - uint32_t LowerBound = - cast(CI->getArgOperand(1))->getZExtValue(); - uint32_t Size = cast(CI->getArgOperand(2))->getZExtValue(); - - // We use a binding ID of zero for now - these will be filled in later. - RI->bind(0U, Space, LowerBound, Size); - - return RI; - } - - DXILResourceMap mapResources() { - for (Function &F : M.functions()) { - if (!F.isDeclaration()) - continue; - LLVM_DEBUG(dbgs() << "Function: " << F.getName() << "\n"); - Intrinsic::ID ID = F.getIntrinsicID(); - switch (ID) { - default: - // TODO: handle `dx.op` functions. - continue; - case Intrinsic::dx_handle_fromBinding: - for (User *U : F.users()) { + for (User *U : F.users()) + if (CallInst *CI = dyn_cast(U)) { LLVM_DEBUG(dbgs() << " Visiting: " << *U << "\n"); - if (CallInst *CI = dyn_cast(U)) - mapHandleFromBinding(CI); + uint32_t Space = + cast(CI->getArgOperand(0))->getZExtValue(); + uint32_t LowerBound = + cast(CI->getArgOperand(1))->getZExtValue(); + uint32_t Size = + cast(CI->getArgOperand(2))->getZExtValue(); + ResourceInfo RI = + ResourceInfo{/*RecordID=*/0, Space, LowerBound, Size, HandleTy}; + + CIToInfo.emplace_back(CI, RI); } - break; - } - } - return DXILResourceMap(std::move(Resources)); + break; + } + } } -}; - -} // namespace - -DXILResourceMap::DXILResourceMap( - SmallVectorImpl> &&CIToRI) { - if (CIToRI.empty()) - return; - llvm::stable_sort(CIToRI, [](auto &LHS, auto &RHS) { + llvm::stable_sort(CIToInfo, [](auto &LHS, auto &RHS) { // Sort by resource class first for grouping purposes, and then by the rest // of the fields so that we can remove duplicates. ResourceClass LRC = LHS.second.getResourceClass(); ResourceClass RRC = RHS.second.getResourceClass(); return std::tie(LRC, LHS.second) < std::tie(RRC, RHS.second); }); - for (auto [CI, RI] : CIToRI) { - if (Resources.empty() || RI != Resources.back()) - Resources.push_back(RI); - CallMap[CI] = Resources.size() - 1; + for (auto [CI, RI] : CIToInfo) { + if (Infos.empty() || RI != Infos.back()) + Infos.push_back(RI); + CallMap[CI] = Infos.size() - 1; } - unsigned Size = Resources.size(); + unsigned Size = Infos.size(); // In DXC, Record ID is unique per resource type. Match that. FirstUAV = FirstCBuffer = FirstSampler = Size; uint32_t NextID = 0; for (unsigned I = 0, E = Size; I != E; ++I) { - ResourceInfo &RI = Resources[I]; + ResourceInfo &RI = Infos[I]; if (RI.isUAV() && FirstUAV == Size) { FirstUAV = I; NextID = 0; @@ -739,15 +629,14 @@ DXILResourceMap::DXILResourceMap( } // Adjust the resource binding to use the next ID. - const ResourceInfo::ResourceBinding &Binding = RI.getBinding(); - RI.bind(NextID++, Binding.Space, Binding.LowerBound, Binding.Size); + RI.setBindingID(NextID++); } } -void DXILResourceMap::print(raw_ostream &OS) const { - for (unsigned I = 0, E = Resources.size(); I != E; ++I) { +void DXILResourceMap::print(raw_ostream &OS, const DataLayout &DL) const { + for (unsigned I = 0, E = Infos.size(); I != E; ++I) { OS << "Binding " << I << ":\n"; - Resources[I].print(OS); + Infos[I].print(OS, DL); OS << "\n"; } @@ -759,27 +648,24 @@ void DXILResourceMap::print(raw_ostream &OS) const { } //===----------------------------------------------------------------------===// -// DXILResourceAnalysis and DXILResourcePrinterPass -// Provide an explicit template instantiation for the static ID. AnalysisKey DXILResourceAnalysis::Key; DXILResourceMap DXILResourceAnalysis::run(Module &M, ModuleAnalysisManager &AM) { - DXILResourceMap Data = ResourceMapper(M).mapResources(); + DXILResourceMap Data; + Data.populate(M); return Data; } PreservedAnalyses DXILResourcePrinterPass::run(Module &M, ModuleAnalysisManager &AM) { - DXILResourceMap &DRM = AM.getResult(M); - DRM.print(OS); + DXILResourceMap &DBM = AM.getResult(M); + + DBM.print(OS, M.getDataLayout()); return PreservedAnalyses::all(); } -//===----------------------------------------------------------------------===// -// DXILResourceWrapperPass - DXILResourceWrapperPass::DXILResourceWrapperPass() : ModulePass(ID) { initializeDXILResourceWrapperPassPass(*PassRegistry::getPassRegistry()); } @@ -791,18 +677,21 @@ void DXILResourceWrapperPass::getAnalysisUsage(AnalysisUsage &AU) const { } bool DXILResourceWrapperPass::runOnModule(Module &M) { - ResourceMap.reset(new DXILResourceMap(ResourceMapper(M).mapResources())); + Map.reset(new DXILResourceMap()); + + Map->populate(M); + return false; } -void DXILResourceWrapperPass::releaseMemory() { ResourceMap.reset(); } +void DXILResourceWrapperPass::releaseMemory() { Map.reset(); } -void DXILResourceWrapperPass::print(raw_ostream &OS, const Module *) const { - if (!ResourceMap) { +void DXILResourceWrapperPass::print(raw_ostream &OS, const Module *M) const { + if (!Map) { OS << "No resource map has been built!\n"; return; } - ResourceMap->print(OS); + Map->print(OS, M->getDataLayout()); } #if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP) @@ -810,8 +699,8 @@ LLVM_DUMP_METHOD void DXILResourceWrapperPass::dump() const { print(dbgs(), nullptr); } #endif -INITIALIZE_PASS(DXILResourceWrapperPass, DEBUG_TYPE, "DXIL Resource analysis", - false, true) +INITIALIZE_PASS(DXILResourceWrapperPass, "dxil-resource-binding", + "DXIL Resource analysis", false, true) char DXILResourceWrapperPass::ID = 0; ModulePass *llvm::createDXILResourceWrapperPassPass() { diff --git a/llvm/lib/Target/DirectX/DXILOpLowering.cpp b/llvm/lib/Target/DirectX/DXILOpLowering.cpp index d9e70da6ed653..78efdcf194b6c 100644 --- a/llvm/lib/Target/DirectX/DXILOpLowering.cpp +++ b/llvm/lib/Target/DirectX/DXILOpLowering.cpp @@ -304,7 +304,7 @@ class OpLowerer { IndexOp = IRB.CreateAdd(IndexOp, ConstantInt::get(Int32Ty, Binding.LowerBound)); - std::pair Props = RI.getAnnotateProps(); + std::pair Props = RI.getAnnotateProps(*F.getParent()); // For `CreateHandleFromBinding` we need the upper bound rather than the // size, so we need to be careful about the difference for "unbounded". diff --git a/llvm/lib/Target/DirectX/DXILPrettyPrinter.cpp b/llvm/lib/Target/DirectX/DXILPrettyPrinter.cpp index 0478dc2df988d..4aa25b3996e3c 100644 --- a/llvm/lib/Target/DirectX/DXILPrettyPrinter.cpp +++ b/llvm/lib/Target/DirectX/DXILPrettyPrinter.cpp @@ -149,7 +149,7 @@ struct FormatResourceDimension default: { OS << getTextureDimName(RK); if (Item.isMultiSample()) - OS << Item.getMultiSample().Count; + OS << Item.getMultiSampleCount(); break; } case dxil::ResourceKind::RawBuffer: diff --git a/llvm/lib/Target/DirectX/DXILTranslateMetadata.cpp b/llvm/lib/Target/DirectX/DXILTranslateMetadata.cpp index 4ba10d123e8d2..baefadede6e3a 100644 --- a/llvm/lib/Target/DirectX/DXILTranslateMetadata.cpp +++ b/llvm/lib/Target/DirectX/DXILTranslateMetadata.cpp @@ -78,13 +78,13 @@ static NamedMDNode *emitResourceMetadata(Module &M, const DXILResourceMap &DRM, SmallVector SRVs, UAVs, CBufs, Smps; for (const ResourceInfo &RI : DRM.srvs()) - SRVs.push_back(RI.getAsMetadata(Context)); + SRVs.push_back(RI.getAsMetadata(M)); for (const ResourceInfo &RI : DRM.uavs()) - UAVs.push_back(RI.getAsMetadata(Context)); + UAVs.push_back(RI.getAsMetadata(M)); for (const ResourceInfo &RI : DRM.cbuffers()) - CBufs.push_back(RI.getAsMetadata(Context)); + CBufs.push_back(RI.getAsMetadata(M)); for (const ResourceInfo &RI : DRM.samplers()) - Smps.push_back(RI.getAsMetadata(Context)); + Smps.push_back(RI.getAsMetadata(M)); Metadata *SRVMD = SRVs.empty() ? nullptr : MDNode::get(Context, SRVs); Metadata *UAVMD = UAVs.empty() ? nullptr : MDNode::get(Context, UAVs); diff --git a/llvm/test/Analysis/DXILResource/buffer-frombinding.ll b/llvm/test/Analysis/DXILResource/buffer-frombinding.ll index b26a185423597..5c8b6998c76aa 100644 --- a/llvm/test/Analysis/DXILResource/buffer-frombinding.ll +++ b/llvm/test/Analysis/DXILResource/buffer-frombinding.ll @@ -8,8 +8,6 @@ define void @test_typedbuffer() { @llvm.dx.handle.fromBinding.tdx.RawBuffer_i8_0_0t( i32 1, i32 8, i32 1, i32 0, i1 false) ; CHECK: Binding [[SRV0:[0-9]+]]: - ; CHECK: Symbol: ptr undef - ; CHECK: Name: "" ; CHECK: Binding: ; CHECK: Record ID: 0 ; CHECK: Space: 1 @@ -24,8 +22,6 @@ define void @test_typedbuffer() { @llvm.dx.handle.fromBinding.tdx.RawBuffer_sl_v4f32v4i32s_0_0t( i32 4, i32 2, i32 1, i32 0, i1 false) ; CHECK: Binding [[SRV1:[0-9]+]]: - ; CHECK: Symbol: ptr undef - ; CHECK: Name: "" ; CHECK: Binding: ; CHECK: Record ID: 1 ; CHECK: Space: 4 @@ -41,8 +37,6 @@ define void @test_typedbuffer() { @llvm.dx.handle.fromBinding.tdx.TypedBuffer_i32_0_0t( i32 5, i32 3, i32 24, i32 0, i1 false) ; CHECK: Binding [[SRV2:[0-9]+]]: - ; CHECK: Symbol: ptr undef - ; CHECK: Name: "" ; CHECK: Binding: ; CHECK: Record ID: 2 ; CHECK: Space: 5 @@ -58,8 +52,6 @@ define void @test_typedbuffer() { @llvm.dx.handle.fromBinding.tdx.TypedBuffer_i32_1_0t( i32 2, i32 7, i32 1, i32 0, i1 false) ; CHECK: Binding [[UAV0:[0-9]+]]: - ; CHECK: Symbol: ptr undef - ; CHECK: Name: "" ; CHECK: Binding: ; CHECK: Record ID: 0 ; CHECK: Space: 2 @@ -78,8 +70,6 @@ define void @test_typedbuffer() { @llvm.dx.handle.fromBinding.tdx.TypedBuffer_f32_1_0( i32 3, i32 5, i32 1, i32 0, i1 false) ; CHECK: Binding [[UAV1:[0-9]+]]: - ; CHECK: Symbol: ptr undef - ; CHECK: Name: "" ; CHECK: Binding: ; CHECK: Record ID: 1 ; CHECK: Space: 3 @@ -103,8 +93,6 @@ define void @test_typedbuffer() { @llvm.dx.handle.fromBinding.tdx.TypedBuffer_f32_1_0( i32 4, i32 0, i32 10, i32 5, i1 false) ; CHECK: Binding [[UAV2:[0-9]+]]: - ; CHECK: Symbol: ptr undef - ; CHECK: Name: "" ; CHECK: Binding: ; CHECK: Record ID: 2 ; CHECK: Space: 4 diff --git a/llvm/unittests/Analysis/DXILResourceTest.cpp b/llvm/unittests/Analysis/DXILResourceTest.cpp index e24018457dabe..776c914b89a04 100644 --- a/llvm/unittests/Analysis/DXILResourceTest.cpp +++ b/llvm/unittests/Analysis/DXILResourceTest.cpp @@ -8,6 +8,9 @@ #include "llvm/Analysis/DXILResource.h" #include "llvm/IR/Constants.h" +#include "llvm/IR/DataLayout.h" +#include "llvm/IR/GlobalVariable.h" +#include "llvm/IR/Module.h" #include "gtest/gtest.h" using namespace llvm; @@ -99,8 +102,16 @@ testing::AssertionResult MDTupleEq(const char *LHSExpr, const char *RHSExpr, } // namespace TEST(DXILResource, AnnotationsAndMetadata) { + // TODO: How am I supposed to get this? + DataLayout DL("e-m:e-p:32:32-i1:32-i8:8-i16:16-i32:32-i64:64-f16:16-f32:32-" + "f64:64-n8:16:32:64-v96:32"); + LLVMContext Context; + Module M("AnnotationsAndMetadata", Context); + M.setDataLayout(DL); + Type *Int1Ty = Type::getInt1Ty(Context); + Type *Int8Ty = Type::getInt8Ty(Context); Type *Int32Ty = Type::getInt32Ty(Context); Type *FloatTy = Type::getFloatTy(Context); Type *DoubleTy = Type::getDoubleTy(Context); @@ -109,206 +120,311 @@ TEST(DXILResource, AnnotationsAndMetadata) { Type *Int32x2Ty = FixedVectorType::get(Int32Ty, 2); MDBuilder TestMD(Context, Int32Ty, Int1Ty); + Value *DummyGV = UndefValue::get(PointerType::getUnqual(Context)); + + // ByteAddressBuffer Buffer; + auto *HandleTy = llvm::TargetExtType::get(Context, "dx.RawBuffer", Int8Ty, + {/*IsWriteable=*/0, /*IsROV=*/0}); + ResourceInfo RI( + /*RecordID=*/0, /*Space=*/0, /*LowerBound=*/0, /*Size=*/1, HandleTy); - // ByteAddressBuffer Buffer0; - Value *Symbol = UndefValue::get( - StructType::create(Context, {Int32Ty}, "struct.ByteAddressBuffer")); - ResourceInfo Resource = ResourceInfo::RawBuffer(Symbol, "Buffer0"); - Resource.bind(0, 0, 0, 1); - std::pair Props = Resource.getAnnotateProps(); + EXPECT_EQ(RI.getResourceClass(), ResourceClass::SRV); + EXPECT_EQ(RI.getResourceKind(), ResourceKind::RawBuffer); + + std::pair Props = RI.getAnnotateProps(M); EXPECT_EQ(Props.first, 0x0000000bU); EXPECT_EQ(Props.second, 0U); - MDTuple *MD = Resource.getAsMetadata(Context); - EXPECT_MDEQ(MD, TestMD.get(0, Symbol, "Buffer0", 0, 0, 1, 11, 0, nullptr)); + MDTuple *MD = RI.getAsMetadata(M); + EXPECT_MDEQ(MD, TestMD.get(0, DummyGV, "", 0, 0, 1, 11, 0, nullptr)); // RWByteAddressBuffer BufferOut : register(u3, space2); - Symbol = UndefValue::get( - StructType::create(Context, {Int32Ty}, "struct.RWByteAddressBuffer")); - Resource = - ResourceInfo::RWRawBuffer(Symbol, "BufferOut", - /*GloballyCoherent=*/false, /*IsROV=*/false); - Resource.bind(1, 2, 3, 1); - Props = Resource.getAnnotateProps(); + HandleTy = llvm::TargetExtType::get(Context, "dx.RawBuffer", Int8Ty, + {/*IsWriteable=*/1, /*IsROV=*/0}); + RI = ResourceInfo( + /*RecordID=*/1, /*Space=*/2, /*LowerBound=*/3, /*Size=*/1, HandleTy); + + EXPECT_EQ(RI.getResourceClass(), ResourceClass::UAV); + EXPECT_EQ(RI.getUAV().GloballyCoherent, false); + EXPECT_EQ(RI.getUAV().HasCounter, false); + EXPECT_EQ(RI.getUAV().IsROV, false); + EXPECT_EQ(RI.getResourceKind(), ResourceKind::RawBuffer); + + Props = RI.getAnnotateProps(M); EXPECT_EQ(Props.first, 0x0000100bU); EXPECT_EQ(Props.second, 0U); - MD = Resource.getAsMetadata(Context); - EXPECT_MDEQ(MD, TestMD.get(1, Symbol, "BufferOut", 2, 3, 1, 11, false, false, - false, nullptr)); + MD = RI.getAsMetadata(M); + EXPECT_MDEQ(MD, TestMD.get(1, DummyGV, "", 2, 3, 1, 11, false, false, false, + nullptr)); // struct BufType0 { int i; float f; double d; }; // StructuredBuffer Buffer0 : register(t0); StructType *BufType0 = StructType::create(Context, {Int32Ty, FloatTy, DoubleTy}, "BufType0"); - Symbol = UndefValue::get(StructType::create( - Context, {BufType0}, "class.StructuredBuffer")); - Resource = ResourceInfo::StructuredBuffer(Symbol, "Buffer0", - /*Stride=*/16, Align(8)); - Resource.bind(0, 0, 0, 1); - Props = Resource.getAnnotateProps(); + HandleTy = llvm::TargetExtType::get(Context, "dx.RawBuffer", BufType0, + {/*IsWriteable=*/0, /*IsROV=*/0}); + RI = ResourceInfo( + /*RecordID=*/0, /*Space=*/0, /*LowerBound=*/0, /*Size=*/1, HandleTy); + + EXPECT_EQ(RI.getResourceClass(), ResourceClass::SRV); + ASSERT_EQ(RI.isStruct(), true); + EXPECT_EQ(RI.getStruct(DL).Stride, 16u); + EXPECT_EQ(RI.getStruct(DL).AlignLog2, Log2(Align(8))); + EXPECT_EQ(RI.getResourceKind(), ResourceKind::StructuredBuffer); + + Props = RI.getAnnotateProps(M); EXPECT_EQ(Props.first, 0x0000030cU); EXPECT_EQ(Props.second, 0x00000010U); - MD = Resource.getAsMetadata(Context); - EXPECT_MDEQ( - MD, TestMD.get(0, Symbol, "Buffer0", 0, 0, 1, 12, 0, TestMD.get(1, 16))); + MD = RI.getAsMetadata(M); + EXPECT_MDEQ(MD, + TestMD.get(0, DummyGV, "", 0, 0, 1, 12, 0, TestMD.get(1, 16))); // StructuredBuffer Buffer1 : register(t1); - Symbol = UndefValue::get(StructType::create( - Context, {Floatx3Ty}, "class.StructuredBuffer >")); - Resource = ResourceInfo::StructuredBuffer(Symbol, "Buffer1", - /*Stride=*/12, {}); - Resource.bind(1, 0, 1, 1); - Props = Resource.getAnnotateProps(); + HandleTy = llvm::TargetExtType::get(Context, "dx.RawBuffer", Floatx3Ty, + {/*IsWriteable=*/0, /*IsROV=*/0}); + RI = ResourceInfo( + /*RecordID=*/1, /*Space=*/0, /*LowerBound=*/1, /*Size=*/1, HandleTy); + + EXPECT_EQ(RI.getResourceClass(), ResourceClass::SRV); + ASSERT_EQ(RI.isStruct(), true); + EXPECT_EQ(RI.getStruct(DL).Stride, 12u); + EXPECT_EQ(RI.getStruct(DL).AlignLog2, 0u); + EXPECT_EQ(RI.getResourceKind(), ResourceKind::StructuredBuffer); + + Props = RI.getAnnotateProps(M); EXPECT_EQ(Props.first, 0x0000000cU); EXPECT_EQ(Props.second, 0x0000000cU); - MD = Resource.getAsMetadata(Context); - EXPECT_MDEQ( - MD, TestMD.get(1, Symbol, "Buffer1", 0, 1, 1, 12, 0, TestMD.get(1, 12))); + MD = RI.getAsMetadata(M); + EXPECT_MDEQ(MD, + TestMD.get(1, DummyGV, "", 0, 1, 1, 12, 0, TestMD.get(1, 12))); // Texture2D ColorMapTexture : register(t2); - Symbol = UndefValue::get(StructType::create( - Context, {Floatx4Ty}, "class.Texture2D >")); - Resource = - ResourceInfo::SRV(Symbol, "ColorMapTexture", dxil::ElementType::F32, - /*ElementCount=*/4, dxil::ResourceKind::Texture2D); - Resource.bind(2, 0, 2, 1); - Props = Resource.getAnnotateProps(); + HandleTy = + llvm::TargetExtType::get(Context, "dx.Texture", Floatx4Ty, + {/*IsWriteable=*/0, /*IsROV=*/0, /*IsSigned=*/0, + llvm::to_underlying(ResourceKind::Texture2D)}); + RI = ResourceInfo( + /*RecordID=*/2, /*Space=*/0, /*LowerBound=*/2, /*Size=*/1, HandleTy); + + EXPECT_EQ(RI.getResourceClass(), ResourceClass::SRV); + ASSERT_EQ(RI.isTyped(), true); + EXPECT_EQ(RI.getTyped().ElementTy, ElementType::F32); + EXPECT_EQ(RI.getTyped().ElementCount, 4u); + EXPECT_EQ(RI.getResourceKind(), ResourceKind::Texture2D); + + Props = RI.getAnnotateProps(M); EXPECT_EQ(Props.first, 0x00000002U); EXPECT_EQ(Props.second, 0x00000409U); - MD = Resource.getAsMetadata(Context); - EXPECT_MDEQ(MD, TestMD.get(2, Symbol, "ColorMapTexture", 0, 2, 1, 2, 0, - TestMD.get(0, 9))); + MD = RI.getAsMetadata(M); + EXPECT_MDEQ(MD, TestMD.get(2, DummyGV, "", 0, 2, 1, 2, 0, TestMD.get(0, 9))); // Texture2DMS DepthBuffer : register(t0); - Symbol = UndefValue::get( - StructType::create(Context, {FloatTy}, "class.Texture2DMS")); - Resource = - ResourceInfo::Texture2DMS(Symbol, "DepthBuffer", dxil::ElementType::F32, - /*ElementCount=*/1, /*SampleCount=*/8); - Resource.bind(0, 0, 0, 1); - Props = Resource.getAnnotateProps(); + HandleTy = llvm::TargetExtType::get( + Context, "dx.MSTexture", FloatTy, + {/*IsWriteable=*/0, /*SampleCount=*/8, + /*IsSigned=*/0, llvm::to_underlying(ResourceKind::Texture2DMS)}); + RI = ResourceInfo( + /*RecordID=*/0, /*Space=*/0, /*LowerBound=*/0, /*Size=*/1, HandleTy); + + EXPECT_EQ(RI.getResourceClass(), ResourceClass::SRV); + ASSERT_EQ(RI.isTyped(), true); + EXPECT_EQ(RI.getTyped().ElementTy, ElementType::F32); + EXPECT_EQ(RI.getTyped().ElementCount, 1u); + ASSERT_EQ(RI.isMultiSample(), true); + EXPECT_EQ(RI.getMultiSampleCount(), 8u); + EXPECT_EQ(RI.getResourceKind(), ResourceKind::Texture2DMS); + + Props = RI.getAnnotateProps(M); EXPECT_EQ(Props.first, 0x00000003U); EXPECT_EQ(Props.second, 0x00080109U); - MD = Resource.getAsMetadata(Context); - EXPECT_MDEQ(MD, TestMD.get(0, Symbol, "DepthBuffer", 0, 0, 1, 3, 8, - TestMD.get(0, 9))); + MD = RI.getAsMetadata(M); + EXPECT_MDEQ(MD, TestMD.get(0, DummyGV, "", 0, 0, 1, 3, 8, TestMD.get(0, 9))); // FeedbackTexture2D feedbackMinMip; - Symbol = UndefValue::get( - StructType::create(Context, {Int32Ty}, "class.FeedbackTexture2D<0>")); - Resource = ResourceInfo::FeedbackTexture2D(Symbol, "feedbackMinMip", - SamplerFeedbackType::MinMip); - Resource.bind(0, 0, 0, 1); - Props = Resource.getAnnotateProps(); + HandleTy = llvm::TargetExtType::get( + Context, "dx.FeedbackTexture", {}, + {llvm::to_underlying(SamplerFeedbackType::MinMip), + llvm::to_underlying(ResourceKind::FeedbackTexture2D)}); + RI = ResourceInfo( + /*RecordID=*/0, /*Space=*/0, /*LowerBound=*/0, /*Size=*/1, HandleTy); + + EXPECT_EQ(RI.getResourceClass(), ResourceClass::UAV); + ASSERT_EQ(RI.isFeedback(), true); + EXPECT_EQ(RI.getFeedbackType(), SamplerFeedbackType::MinMip); + EXPECT_EQ(RI.getResourceKind(), ResourceKind::FeedbackTexture2D); + + Props = RI.getAnnotateProps(M); EXPECT_EQ(Props.first, 0x00001011U); EXPECT_EQ(Props.second, 0U); - MD = Resource.getAsMetadata(Context); - EXPECT_MDEQ(MD, TestMD.get(0, Symbol, "feedbackMinMip", 0, 0, 1, 17, false, - false, false, TestMD.get(2, 0))); + MD = RI.getAsMetadata(M); + EXPECT_MDEQ(MD, TestMD.get(0, DummyGV, "", 0, 0, 1, 17, false, false, false, + TestMD.get(2, 0))); // FeedbackTexture2DArray feedbackMipRegion; - Symbol = UndefValue::get(StructType::create( - Context, {Int32Ty}, "class.FeedbackTexture2DArray<1>")); - Resource = ResourceInfo::FeedbackTexture2DArray( - Symbol, "feedbackMipRegion", SamplerFeedbackType::MipRegionUsed); - Resource.bind(0, 0, 0, 1); - Props = Resource.getAnnotateProps(); + HandleTy = llvm::TargetExtType::get( + Context, "dx.FeedbackTexture", {}, + {llvm::to_underlying(SamplerFeedbackType::MipRegionUsed), + llvm::to_underlying(ResourceKind::FeedbackTexture2DArray)}); + RI = ResourceInfo( + /*RecordID=*/0, /*Space=*/0, /*LowerBound=*/0, /*Size=*/1, HandleTy); + + EXPECT_EQ(RI.getResourceClass(), ResourceClass::UAV); + ASSERT_EQ(RI.isFeedback(), true); + EXPECT_EQ(RI.getFeedbackType(), SamplerFeedbackType::MipRegionUsed); + EXPECT_EQ(RI.getResourceKind(), ResourceKind::FeedbackTexture2DArray); + + Props = RI.getAnnotateProps(M); EXPECT_EQ(Props.first, 0x00001012U); EXPECT_EQ(Props.second, 0x00000001U); - MD = Resource.getAsMetadata(Context); - EXPECT_MDEQ(MD, TestMD.get(0, Symbol, "feedbackMipRegion", 0, 0, 1, 18, false, - false, false, TestMD.get(2, 1))); + MD = RI.getAsMetadata(M); + EXPECT_MDEQ(MD, TestMD.get(0, DummyGV, "", 0, 0, 1, 18, false, false, false, + TestMD.get(2, 1))); // globallycoherent RWTexture2D OutputTexture : register(u0, space2); - Symbol = UndefValue::get(StructType::create( - Context, {Int32x2Ty}, "class.RWTexture2D >")); - Resource = ResourceInfo::UAV(Symbol, "OutputTexture", dxil::ElementType::I32, - /*ElementCount=*/2, /*GloballyCoherent=*/1, - /*IsROV=*/0, dxil::ResourceKind::Texture2D); - Resource.bind(0, 2, 0, 1); - Props = Resource.getAnnotateProps(); + HandleTy = + llvm::TargetExtType::get(Context, "dx.Texture", Int32x2Ty, + {/*IsWriteable=*/1, + /*IsROV=*/0, /*IsSigned=*/1, + llvm::to_underlying(ResourceKind::Texture2D)}); + + RI = ResourceInfo( + /*RecordID=*/0, /*Space=*/2, /*LowerBound=*/0, /*Size=*/1, HandleTy, + /*GloballyCoherent=*/true, /*HasCounter=*/false); + + EXPECT_EQ(RI.getResourceClass(), ResourceClass::UAV); + EXPECT_EQ(RI.getUAV().GloballyCoherent, true); + EXPECT_EQ(RI.getUAV().HasCounter, false); + EXPECT_EQ(RI.getUAV().IsROV, false); + EXPECT_EQ(RI.getResourceKind(), ResourceKind::Texture2D); + + Props = RI.getAnnotateProps(M); EXPECT_EQ(Props.first, 0x00005002U); EXPECT_EQ(Props.second, 0x00000204U); - MD = Resource.getAsMetadata(Context); - EXPECT_MDEQ(MD, TestMD.get(0, Symbol, "OutputTexture", 2, 0, 1, 2, true, - false, false, TestMD.get(0, 4))); + MD = RI.getAsMetadata(M); + EXPECT_MDEQ(MD, TestMD.get(0, DummyGV, "", 2, 0, 1, 2, true, false, false, + TestMD.get(0, 4))); // RasterizerOrderedBuffer ROB; - Symbol = UndefValue::get( - StructType::create(Context, {Floatx4Ty}, - "class.RasterizerOrderedBuffer >")); - Resource = ResourceInfo::UAV(Symbol, "ROB", dxil::ElementType::F32, - /*ElementCount=*/4, /*GloballyCoherent=*/0, - /*IsROV=*/1, dxil::ResourceKind::TypedBuffer); - Resource.bind(0, 0, 0, 1); - Props = Resource.getAnnotateProps(); + HandleTy = llvm::TargetExtType::get( + Context, "dx.TypedBuffer", Floatx4Ty, + {/*IsWriteable=*/1, /*IsROV=*/1, /*IsSigned=*/0}); + RI = ResourceInfo( + /*RecordID=*/0, /*Space=*/0, /*LowerBound=*/0, /*Size=*/1, HandleTy); + + EXPECT_EQ(RI.getResourceClass(), ResourceClass::UAV); + EXPECT_EQ(RI.getUAV().GloballyCoherent, false); + EXPECT_EQ(RI.getUAV().HasCounter, false); + EXPECT_EQ(RI.getUAV().IsROV, true); + ASSERT_EQ(RI.isTyped(), true); + EXPECT_EQ(RI.getTyped().ElementTy, ElementType::F32); + EXPECT_EQ(RI.getTyped().ElementCount, 4u); + EXPECT_EQ(RI.getResourceKind(), ResourceKind::TypedBuffer); + + Props = RI.getAnnotateProps(M); EXPECT_EQ(Props.first, 0x0000300aU); EXPECT_EQ(Props.second, 0x00000409U); - MD = Resource.getAsMetadata(Context); - EXPECT_MDEQ(MD, TestMD.get(0, Symbol, "ROB", 0, 0, 1, 10, false, false, true, + MD = RI.getAsMetadata(M); + EXPECT_MDEQ(MD, TestMD.get(0, DummyGV, "", 0, 0, 1, 10, false, false, true, TestMD.get(0, 9))); // RWStructuredBuffer g_OutputBuffer : register(u2); StructType *BufType1 = StructType::create( Context, {Floatx3Ty, FloatTy, Int32Ty}, "ParticleMotion"); - Symbol = UndefValue::get(StructType::create( - Context, {BufType1}, "class.StructuredBuffer")); - Resource = - ResourceInfo::RWStructuredBuffer(Symbol, "g_OutputBuffer", /*Stride=*/20, - Align(4), /*GloballyCoherent=*/false, - /*IsROV=*/false, /*HasCounter=*/true); - Resource.bind(0, 0, 2, 1); - Props = Resource.getAnnotateProps(); + HandleTy = llvm::TargetExtType::get(Context, "dx.RawBuffer", BufType1, + {/*IsWriteable=*/1, /*IsROV=*/0}); + RI = ResourceInfo( + /*RecordID=*/0, /*Space=*/0, /*LowerBound=*/2, /*Size=*/1, HandleTy, + /*GloballyCoherent=*/false, /*HasCounter=*/true); + + EXPECT_EQ(RI.getResourceClass(), ResourceClass::UAV); + EXPECT_EQ(RI.getUAV().GloballyCoherent, false); + EXPECT_EQ(RI.getUAV().HasCounter, true); + EXPECT_EQ(RI.getUAV().IsROV, false); + ASSERT_EQ(RI.isStruct(), true); + EXPECT_EQ(RI.getStruct(DL).Stride, 20u); + EXPECT_EQ(RI.getStruct(DL).AlignLog2, Log2(Align(4))); + EXPECT_EQ(RI.getResourceKind(), ResourceKind::StructuredBuffer); + + Props = RI.getAnnotateProps(M); EXPECT_EQ(Props.first, 0x0000920cU); EXPECT_EQ(Props.second, 0x00000014U); - MD = Resource.getAsMetadata(Context); - EXPECT_MDEQ(MD, TestMD.get(0, Symbol, "g_OutputBuffer", 0, 2, 1, 12, false, - true, false, TestMD.get(1, 20))); - - // RWTexture2DMSArray g_rw_t2dmsa; - Symbol = UndefValue::get(StructType::create( - Context, {Int32Ty}, "class.RWTexture2DMSArray")); - Resource = ResourceInfo::RWTexture2DMSArray( - Symbol, "g_rw_t2dmsa", dxil::ElementType::U32, /*ElementCount=*/1, - /*SampleCount=*/8, /*GloballyCoherent=*/false); - Resource.bind(0, 0, 0, 1); - Props = Resource.getAnnotateProps(); + MD = RI.getAsMetadata(M); + EXPECT_MDEQ(MD, TestMD.get(0, DummyGV, "", 0, 2, 1, 12, false, true, false, + TestMD.get(1, 20))); + + // RWTexture2DMSArray g_rw_t2dmsa; + HandleTy = llvm::TargetExtType::get( + Context, "dx.MSTexture", Int32Ty, + {/*IsWriteable=*/1, /*SampleCount=*/8, /*IsSigned=*/0, + llvm::to_underlying(ResourceKind::Texture2DMSArray)}); + RI = ResourceInfo( + /*RecordID=*/0, /*Space=*/0, /*LowerBound=*/0, /*Size=*/1, HandleTy); + + EXPECT_EQ(RI.getResourceClass(), ResourceClass::UAV); + EXPECT_EQ(RI.getUAV().GloballyCoherent, false); + EXPECT_EQ(RI.getUAV().HasCounter, false); + EXPECT_EQ(RI.getUAV().IsROV, false); + ASSERT_EQ(RI.isTyped(), true); + EXPECT_EQ(RI.getTyped().ElementTy, ElementType::U32); + EXPECT_EQ(RI.getTyped().ElementCount, 1u); + ASSERT_EQ(RI.isMultiSample(), true); + EXPECT_EQ(RI.getMultiSampleCount(), 8u); + EXPECT_EQ(RI.getResourceKind(), ResourceKind::Texture2DMSArray); + + Props = RI.getAnnotateProps(M); EXPECT_EQ(Props.first, 0x00001008U); EXPECT_EQ(Props.second, 0x00080105U); - MD = Resource.getAsMetadata(Context); - EXPECT_MDEQ(MD, TestMD.get(0, Symbol, "g_rw_t2dmsa", 0, 0, 1, 8, false, false, - false, TestMD.get(0, 5))); + MD = RI.getAsMetadata(M); + EXPECT_MDEQ(MD, TestMD.get(0, DummyGV, "", 0, 0, 1, 8, false, false, false, + TestMD.get(0, 5))); // cbuffer cb0 { float4 g_X; float4 g_Y; } - Symbol = UndefValue::get( - StructType::create(Context, {Floatx4Ty, Floatx4Ty}, "cb0")); - Resource = ResourceInfo::CBuffer(Symbol, "cb0", /*Size=*/32); - Resource.bind(0, 0, 0, 1); - Props = Resource.getAnnotateProps(); + StructType *CBufType0 = + StructType::create(Context, {Floatx4Ty, Floatx4Ty}, "cb0"); + HandleTy = + llvm::TargetExtType::get(Context, "dx.CBuffer", CBufType0, {/*Size=*/32}); + RI = ResourceInfo( + /*RecordID=*/0, /*Space=*/0, /*LowerBound=*/0, /*Size=*/1, HandleTy); + + EXPECT_EQ(RI.getResourceClass(), ResourceClass::CBuffer); + EXPECT_EQ(RI.getCBufferSize(DL), 32u); + EXPECT_EQ(RI.getResourceKind(), ResourceKind::CBuffer); + + Props = RI.getAnnotateProps(M); EXPECT_EQ(Props.first, 0x0000000dU); EXPECT_EQ(Props.second, 0x00000020U); - MD = Resource.getAsMetadata(Context); - EXPECT_MDEQ(MD, TestMD.get(0, Symbol, "cb0", 0, 0, 1, 32, nullptr)); + MD = RI.getAsMetadata(M); + EXPECT_MDEQ(MD, TestMD.get(0, DummyGV, "", 0, 0, 1, 32, nullptr)); // SamplerState ColorMapSampler : register(s0); - Symbol = UndefValue::get( - StructType::create(Context, {Int32Ty}, "struct.SamplerState")); - Resource = ResourceInfo::Sampler(Symbol, "ColorMapSampler", - dxil::SamplerType::Default); - Resource.bind(0, 0, 0, 1); - Props = Resource.getAnnotateProps(); + HandleTy = llvm::TargetExtType::get( + Context, "dx.Sampler", {}, + {llvm::to_underlying(dxil::SamplerType::Default)}); + RI = ResourceInfo( + /*RecordID=*/0, /*Space=*/0, /*LowerBound=*/0, /*Size=*/1, HandleTy); + + EXPECT_EQ(RI.getResourceClass(), ResourceClass::Sampler); + EXPECT_EQ(RI.getSamplerType(), dxil::SamplerType::Default); + EXPECT_EQ(RI.getResourceKind(), ResourceKind::Sampler); + + Props = RI.getAnnotateProps(M); EXPECT_EQ(Props.first, 0x0000000eU); EXPECT_EQ(Props.second, 0U); - MD = Resource.getAsMetadata(Context); - EXPECT_MDEQ(MD, - TestMD.get(0, Symbol, "ColorMapSampler", 0, 0, 1, 0, nullptr)); + MD = RI.getAsMetadata(M); + EXPECT_MDEQ(MD, TestMD.get(0, DummyGV, "", 0, 0, 1, 0, nullptr)); + + HandleTy = llvm::TargetExtType::get( + Context, "dx.Sampler", {}, + {llvm::to_underlying(dxil::SamplerType::Comparison)}); + RI = ResourceInfo( + /*RecordID=*/0, /*Space=*/0, /*LowerBound=*/0, /*Size=*/1, HandleTy); + + EXPECT_EQ(RI.getResourceClass(), ResourceClass::Sampler); + EXPECT_EQ(RI.getSamplerType(), dxil::SamplerType::Comparison); + EXPECT_EQ(RI.getResourceKind(), ResourceKind::Sampler); - // SamplerComparisonState ShadowSampler {...}; - Resource = ResourceInfo::Sampler(Symbol, "CmpSampler", - dxil::SamplerType::Comparison); - Resource.bind(0, 0, 0, 1); - Props = Resource.getAnnotateProps(); + Props = RI.getAnnotateProps(M); EXPECT_EQ(Props.first, 0x0000800eU); EXPECT_EQ(Props.second, 0U); - MD = Resource.getAsMetadata(Context); - EXPECT_MDEQ(MD, TestMD.get(0, Symbol, "CmpSampler", 0, 0, 1, 1, nullptr)); + MD = RI.getAsMetadata(M); + EXPECT_MDEQ(MD, TestMD.get(0, DummyGV, "", 0, 0, 1, 1, nullptr)); }