Skip to content

[DirectX] Add resource handling to the DXIL pretty printer #104448

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 14 additions & 0 deletions llvm/include/llvm/Analysis/DXILResource.h
Original file line number Diff line number Diff line change
Expand Up @@ -164,6 +164,10 @@ class ResourceInfo {
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;
Expand All @@ -179,6 +183,10 @@ class ResourceInfo {
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;
Expand All @@ -187,8 +195,14 @@ class ResourceInfo {
assert(isMultiSample() && "Not MultiSampled");
MultiSample.Count = Count;
}
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; }

bool operator==(const ResourceInfo &RHS) const;
bool operator!=(const ResourceInfo &RHS) const { return !(*this == RHS); }
Expand Down
229 changes: 223 additions & 6 deletions llvm/lib/Target/DirectX/DXILPrettyPrinter.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -10,22 +10,234 @@
#include "DXILResourceAnalysis.h"
#include "DirectX.h"
#include "llvm/ADT/StringRef.h"
#include "llvm/Analysis/DXILResource.h"
#include "llvm/IR/PassManager.h"
#include "llvm/InitializePasses.h"
#include "llvm/Pass.h"
#include "llvm/Support/FormatAdapters.h"
#include "llvm/Support/FormatVariadic.h"
#include "llvm/Support/raw_ostream.h"

using namespace llvm;

static void prettyPrintResources(raw_ostream &OS,
static StringRef getRCName(dxil::ResourceClass RC) {
switch (RC) {
case dxil::ResourceClass::SRV:
return "SRV";
case dxil::ResourceClass::UAV:
return "UAV";
case dxil::ResourceClass::CBuffer:
return "cbuffer";
case dxil::ResourceClass::Sampler:
return "sampler";
}
llvm_unreachable("covered switch");
}

static StringRef getRCPrefix(dxil::ResourceClass RC) {
switch (RC) {
case dxil::ResourceClass::SRV:
return "t";
case dxil::ResourceClass::UAV:
return "u";
case dxil::ResourceClass::CBuffer:
return "cb";
case dxil::ResourceClass::Sampler:
return "s";
}
}

static StringRef getFormatName(const dxil::ResourceInfo &RI) {
if (RI.isTyped()) {
switch (RI.getTyped().ElementTy) {
case dxil::ElementType::I1:
return "i1";
case dxil::ElementType::I16:
return "i16";
case dxil::ElementType::U16:
return "u16";
case dxil::ElementType::I32:
return "i32";
case dxil::ElementType::U32:
return "u32";
case dxil::ElementType::I64:
return "i64";
case dxil::ElementType::U64:
return "u64";
case dxil::ElementType::F16:
return "f16";
case dxil::ElementType::F32:
return "f32";
case dxil::ElementType::F64:
return "f64";
case dxil::ElementType::SNormF16:
return "snorm_f16";
case dxil::ElementType::UNormF16:
return "unorm_f16";
case dxil::ElementType::SNormF32:
return "snorm_f32";
case dxil::ElementType::UNormF32:
return "unorm_f32";
case dxil::ElementType::SNormF64:
return "snorm_f64";
case dxil::ElementType::UNormF64:
return "unorm_f64";
case dxil::ElementType::PackedS8x32:
return "p32i8";
case dxil::ElementType::PackedU8x32:
return "p32u8";
case dxil::ElementType::Invalid:
llvm_unreachable("Invalid ElementType");
}
llvm_unreachable("Unhandled ElementType");
} else if (RI.isStruct())
return "struct";
else if (RI.isCBuffer() || RI.isSampler())
return "NA";
return "byte";
}

static StringRef getTextureDimName(dxil::ResourceKind RK) {
switch (RK) {
case dxil::ResourceKind::Texture1D:
return "1d";
case dxil::ResourceKind::Texture2D:
return "2d";
case dxil::ResourceKind::Texture3D:
return "3d";
case dxil::ResourceKind::TextureCube:
return "cube";
case dxil::ResourceKind::Texture1DArray:
return "1darray";
case dxil::ResourceKind::Texture2DArray:
return "2darray";
case dxil::ResourceKind::TextureCubeArray:
return "cubearray";
case dxil::ResourceKind::TBuffer:
return "tbuffer";
case dxil::ResourceKind::FeedbackTexture2D:
return "fbtex2d";
case dxil::ResourceKind::FeedbackTexture2DArray:
return "fbtex2darray";
case dxil::ResourceKind::Texture2DMS:
return "2dMS";
case dxil::ResourceKind::Texture2DMSArray:
return "2darrayMS";
case dxil::ResourceKind::Invalid:
case dxil::ResourceKind::NumEntries:
case dxil::ResourceKind::CBuffer:
case dxil::ResourceKind::RawBuffer:
case dxil::ResourceKind::Sampler:
case dxil::ResourceKind::StructuredBuffer:
case dxil::ResourceKind::TypedBuffer:
case dxil::ResourceKind::RTAccelerationStructure:
llvm_unreachable("Invalid ResourceKind for texture");
}
llvm_unreachable("Unhandled ResourceKind");
}

namespace {
struct FormatResourceDimension
: public llvm::FormatAdapter<const dxil::ResourceInfo &> {
explicit FormatResourceDimension(const dxil::ResourceInfo &RI)
: llvm::FormatAdapter<const dxil::ResourceInfo &>(RI) {}

void format(llvm::raw_ostream &OS, StringRef Style) override {
dxil::ResourceKind RK = Item.getResourceKind();
switch (RK) {
default: {
OS << getTextureDimName(RK);
if (Item.isMultiSample())
OS << Item.getMultiSample().Count;
break;
}
case dxil::ResourceKind::RawBuffer:
case dxil::ResourceKind::StructuredBuffer:
if (!Item.isUAV())
OS << "r/o";
else if (Item.getUAV().HasCounter)
OS << "r/w+cnt";
else
OS << "r/w";
break;
case dxil::ResourceKind::TypedBuffer:
OS << "buf";
break;
case dxil::ResourceKind::RTAccelerationStructure:
// TODO: dxc would print "ras" here. Can/should this happen?
llvm_unreachable("RTAccelerationStructure printing is not implemented");
}
}
};

struct FormatBindingID
: public llvm::FormatAdapter<const dxil::ResourceInfo &> {
explicit FormatBindingID(const dxil::ResourceInfo &RI)
: llvm::FormatAdapter<const dxil::ResourceInfo &>(RI) {}

void format(llvm::raw_ostream &OS, StringRef Style) override {
OS << getRCPrefix(Item.getResourceClass()).upper()
<< Item.getBinding().RecordID;
}
};

struct FormatBindingLocation
: public llvm::FormatAdapter<const dxil::ResourceInfo &> {
explicit FormatBindingLocation(const dxil::ResourceInfo &RI)
: llvm::FormatAdapter<const dxil::ResourceInfo &>(RI) {}

void format(llvm::raw_ostream &OS, StringRef Style) override {
const auto &Binding = Item.getBinding();
OS << getRCPrefix(Item.getResourceClass()) << Binding.LowerBound;
if (Binding.Space)
OS << ",space" << Binding.Space;
}
};

struct FormatBindingSize
: public llvm::FormatAdapter<const dxil::ResourceInfo &> {
explicit FormatBindingSize(const dxil::ResourceInfo &RI)
: llvm::FormatAdapter<const dxil::ResourceInfo &>(RI) {}

void format(llvm::raw_ostream &OS, StringRef Style) override {
uint32_t Size = Item.getBinding().Size;
if (Size == std::numeric_limits<uint32_t>::max())
OS << "unbounded";
else
OS << Size;
}
};

} // namespace

static void prettyPrintResources(raw_ostream &OS, const DXILResourceMap &DRM,
const dxil::Resources &MDResources) {
// Column widths are arbitrary but match the widths DXC uses.
OS << ";\n; Resource Bindings:\n;\n";
OS << formatv("; {0,-30} {1,10} {2,7} {3,11} {4,7} {5,14} {6,16}\n", "Name",
OS << formatv("; {0,-30} {1,10} {2,7} {3,11} {4,7} {5,14} {6,9}\n", "Name",
"Type", "Format", "Dim", "ID", "HLSL Bind", "Count");
OS << formatv(
"; {0,-+30} {1,-+10} {2,-+7} {3,-+11} {4,-+7} {5,-+14} {6,-+16}\n", "",
"", "", "", "", "", "");
"; {0,-+30} {1,-+10} {2,-+7} {3,-+11} {4,-+7} {5,-+14} {6,-+9}\n", "", "",
"", "", "", "", "");

// TODO: Do we want to sort these by binding or something like that?
for (const dxil::ResourceInfo &RI : DRM) {
dxil::ResourceClass RC = RI.getResourceClass();
assert((RC != dxil::ResourceClass::CBuffer || !MDResources.hasCBuffers()) &&
"Old and new cbuffer representations can't coexist");
assert((RC != dxil::ResourceClass::UAV || !MDResources.hasUAVs()) &&
"Old and new UAV representations can't coexist");

StringRef Name(RI.getName());
StringRef Type(getRCName(RC));
StringRef Format(getFormatName(RI));
FormatResourceDimension Dim(RI);
FormatBindingID ID(RI);
FormatBindingLocation Bind(RI);
FormatBindingSize Count(RI);
OS << formatv("; {0,-30} {1,10} {2,7} {3,11} {4,7} {5,14} {6,9}\n", Name,
Type, Format, Dim, ID, Bind, Count);
}

if (MDResources.hasCBuffers())
MDResources.printCBuffers(OS);
Expand All @@ -37,8 +249,9 @@ static void prettyPrintResources(raw_ostream &OS,

PreservedAnalyses DXILPrettyPrinterPass::run(Module &M,
ModuleAnalysisManager &MAM) {
const DXILResourceMap &DRM = MAM.getResult<DXILResourceAnalysis>(M);
const dxil::Resources &MDResources = MAM.getResult<DXILResourceMDAnalysis>(M);
prettyPrintResources(OS, MDResources);
prettyPrintResources(OS, DRM, MDResources);
return PreservedAnalyses::all();
}

Expand All @@ -63,6 +276,7 @@ class DXILPrettyPrinterLegacy : public llvm::ModulePass {
bool runOnModule(Module &M) override;
void getAnalysisUsage(AnalysisUsage &AU) const override {
AU.setPreservesAll();
AU.addRequired<DXILResourceWrapperPass>();
AU.addRequired<DXILResourceMDWrapper>();
}
};
Expand All @@ -71,13 +285,16 @@ class DXILPrettyPrinterLegacy : public llvm::ModulePass {
char DXILPrettyPrinterLegacy::ID = 0;
INITIALIZE_PASS_BEGIN(DXILPrettyPrinterLegacy, "dxil-pretty-printer",
"DXIL Metadata Pretty Printer", true, true)
INITIALIZE_PASS_DEPENDENCY(DXILResourceWrapperPass)
INITIALIZE_PASS_DEPENDENCY(DXILResourceMDWrapper)
INITIALIZE_PASS_END(DXILPrettyPrinterLegacy, "dxil-pretty-printer",
"DXIL Metadata Pretty Printer", true, true)

bool DXILPrettyPrinterLegacy::runOnModule(Module &M) {
const DXILResourceMap &DRM =
getAnalysis<DXILResourceWrapperPass>().getResourceMap();
dxil::Resources &Res = getAnalysis<DXILResourceMDWrapper>().getDXILResource();
prettyPrintResources(OS, Res);
prettyPrintResources(OS, DRM, Res);
return false;
}

Expand Down
10 changes: 10 additions & 0 deletions llvm/test/CodeGen/DirectX/CreateHandle.ll
Original file line number Diff line number Diff line change
@@ -1,4 +1,14 @@
; RUN: opt -S -passes=dxil-op-lower,dxil-translate-metadata %s | FileCheck %s
; RUN: opt -S -passes=dxil-pretty-printer %s 2>&1 >/dev/null | FileCheck --check-prefix=CHECK-PRETTY %s

; CHECK-PRETTY: Type Format Dim ID HLSL Bind Count
; CHECK-PRETTY: ---------- ------- ----------- ------- -------------- ---------
; CHECK-PRETTY: SRV f32 buf T0 t0 unbounded
; CHECK-PRETTY: SRV byte r/o T1 t8,space1 1
; CHECK-PRETTY: SRV struct r/o T2 t2,space4 1
; CHECK-PRETTY: SRV u32 buf T3 t3,space5 24
; CHECK-PRETTY: UAV i32 buf U0 u7,space2 1
; CHECK-PRETTY: UAV f32 buf U1 u5,space3 1

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Change one of the cases to use the default space0?

target triple = "dxil-pc-shadermodel6.0-compute"

Expand Down
10 changes: 10 additions & 0 deletions llvm/test/CodeGen/DirectX/CreateHandleFromBinding.ll
Original file line number Diff line number Diff line change
@@ -1,4 +1,14 @@
; RUN: opt -S -passes=dxil-op-lower,dxil-translate-metadata %s | FileCheck %s
; RUN: opt -S -passes=dxil-pretty-printer %s 2>&1 >/dev/null | FileCheck --check-prefix=CHECK-PRETTY %s

; CHECK-PRETTY: Type Format Dim ID HLSL Bind Count
; CHECK-PRETTY: ---------- ------- ----------- ------- -------------- ---------
; CHECK-PRETTY: SRV f32 buf T0 t0 unbounded
; CHECK-PRETTY: SRV byte r/o T1 t8,space1 1
; CHECK-PRETTY: SRV struct r/o T2 t2,space4 1
; CHECK-PRETTY: SRV u32 buf T3 t3,space5 24
; CHECK-PRETTY: UAV i32 buf U0 u7,space2 1
; CHECK-PRETTY: UAV f32 buf U1 u5,space3 1

target triple = "dxil-pc-shadermodel6.6-compute"

Expand Down
Loading