-
Notifications
You must be signed in to change notification settings - Fork 12.6k
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
[DirectX] Add resource handling to the DXIL pretty printer #104448
[DirectX] Add resource handling to the DXIL pretty printer #104448
Conversation
Created using spr 1.3.5-bogner [skip ci]
Created using spr 1.3.5-bogner
@llvm/pr-subscribers-backend-directx @llvm/pr-subscribers-llvm-analysis Author: Justin Bogner (bogner) ChangesHandle target extension type resources when printing resources to textual IR. Full diff: https://github.com/llvm/llvm-project/pull/104448.diff 5 Files Affected:
diff --git a/llvm/include/llvm/Analysis/DXILResource.h b/llvm/include/llvm/Analysis/DXILResource.h
index 2ed508b28a908..faee9f5dac1b4 100644
--- a/llvm/include/llvm/Analysis/DXILResource.h
+++ b/llvm/include/llvm/Analysis/DXILResource.h
@@ -142,12 +142,17 @@ class ResourceInfo {
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;
@@ -163,6 +168,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;
@@ -171,8 +180,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;
@@ -222,7 +237,6 @@ class ResourceInfo {
MDTuple *getAsMetadata(LLVMContext &Ctx) const;
- ResourceBinding getBinding() const { return Binding; }
std::pair<uint32_t, uint32_t> getAnnotateProps() const;
void print(raw_ostream &OS) const;
diff --git a/llvm/lib/Target/DirectX/DXILOpLowering.cpp b/llvm/lib/Target/DirectX/DXILOpLowering.cpp
index f34302cc95065..e7c36ead1cc34 100644
--- a/llvm/lib/Target/DirectX/DXILOpLowering.cpp
+++ b/llvm/lib/Target/DirectX/DXILOpLowering.cpp
@@ -175,7 +175,7 @@ class OpLowerer {
IRB.SetInsertPoint(CI);
dxil::ResourceInfo &RI = DRM[CI];
- dxil::ResourceInfo::ResourceBinding Binding = RI.getBinding();
+ const auto &Binding = RI.getBinding();
std::array<Value *, 4> Args{
ConstantInt::get(Int8Ty, llvm::to_underlying(RI.getResourceClass())),
@@ -201,7 +201,7 @@ class OpLowerer {
IRB.SetInsertPoint(CI);
dxil::ResourceInfo &RI = DRM[CI];
- dxil::ResourceInfo::ResourceBinding Binding = RI.getBinding();
+ const auto &Binding = RI.getBinding();
std::pair<uint32_t, uint32_t> Props = RI.getAnnotateProps();
Constant *ResBind = OpBuilder.getResBind(
diff --git a/llvm/lib/Target/DirectX/DXILPrettyPrinter.cpp b/llvm/lib/Target/DirectX/DXILPrettyPrinter.cpp
index c57631cc4c8b6..76a40dbfc5845 100644
--- a/llvm/lib/Target/DirectX/DXILPrettyPrinter.cpp
+++ b/llvm/lib/Target/DirectX/DXILPrettyPrinter.cpp
@@ -10,23 +10,235 @@
#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 constexpr 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 constexpr 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 constexpr 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 constexpr 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",
+ 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 (auto [_, 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);
if (MDResources.hasUAVs())
@@ -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();
}
@@ -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>();
}
};
@@ -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;
}
diff --git a/llvm/test/CodeGen/DirectX/CreateHandle.ll b/llvm/test/CodeGen/DirectX/CreateHandle.ll
index f0d1c8da5a425..cbb7359642c27 100644
--- a/llvm/test/CodeGen/DirectX/CreateHandle.ll
+++ b/llvm/test/CodeGen/DirectX/CreateHandle.ll
@@ -1,4 +1,13 @@
; 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: UAV f32 buf U0 u5,space3 1
+; CHECK-PRETTY: UAV i32 buf U1 u7,space2 1
+; CHECK-PRETTY: SRV u32 buf T0 t3,space5 24
+; CHECK-PRETTY: SRV struct r/o T1 t2,space4 1
+; CHECK-PRETTY: SRV byte r/o T2 t8,space1 1
target triple = "dxil-pc-shadermodel6.0-compute"
diff --git a/llvm/test/CodeGen/DirectX/CreateHandleFromBinding.ll b/llvm/test/CodeGen/DirectX/CreateHandleFromBinding.ll
index 345459a60c5ab..aea251a3612ef 100644
--- a/llvm/test/CodeGen/DirectX/CreateHandleFromBinding.ll
+++ b/llvm/test/CodeGen/DirectX/CreateHandleFromBinding.ll
@@ -1,4 +1,13 @@
; 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: UAV f32 buf U0 u5,space3 1
+; CHECK-PRETTY: UAV i32 buf U1 u7,space2 1
+; CHECK-PRETTY: SRV u32 buf T0 t3,space5 24
+; CHECK-PRETTY: SRV struct r/o T1 t2,space4 1
+; CHECK-PRETTY: SRV byte r/o T2 t8,space1 1
target triple = "dxil-pc-shadermodel6.6-compute"
|
✅ With the latest revision this PR passed the C/C++ code formatter. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Looks good to me. This is the first time I have seen a switch 'default:' come before the 'case:' entries. (void format(llvm::raw_ostream &OS, StringRef Style) override)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM!
; CHECK-PRETTY: UAV i32 buf U1 u7,space2 1 | ||
; CHECK-PRETTY: SRV u32 buf T0 t3,space5 24 | ||
; CHECK-PRETTY: SRV struct r/o T1 t2,space4 1 | ||
; CHECK-PRETTY: SRV byte r/o T2 t8,space1 1 | ||
|
There was a problem hiding this comment.
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
?
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", |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Neat use of the llvm::FormatAdapter
. Bit of a overkill for the simple cases but it looks elegant. ;).
Created using spr 1.3.5-bogner [skip ci]
Created using spr 1.3.5-bogner
#include "llvm/Support/FormatVariadic.h" | ||
#include "llvm/Support/raw_ostream.h" | ||
|
||
using namespace llvm; | ||
|
||
static void prettyPrintResources(raw_ostream &OS, | ||
static constexpr StringRef getRCName(dxil::ResourceClass RC) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Feel free to ignore, I was thinking of a different way to do this that would have a tighter coupling of Names and prefixes:
struct ResourceClassNameInfo {
const StringRef name;
const StringRef prefix;
};
llvm::DenseMap<dxil::ResourceClass, ResourceClassNameInfo> createResourceClassMap() {
return {
{dxil::ResourceClass::SRV, {"SRV", "t"}},
{dxil::ResourceClass::UAV, {"UAV", "u"}},
{dxil::ResourceClass::CBuffer, {"cbuffer", "cb"}},
{dxil::ResourceClass::Sampler, {"sampler", "s"}}
};
}
static const llvm::DenseMap<dxil::ResourceClass, ResourceClassNameInfo> ResourceClassMap = createResourceClassMap();
StringRef getRCName(dxil::ResourceClass RC) {
return ResourceClassMap.lookup(RC).name;
}
StringRef getRCPrefix(dxil::ResourceClass RC) {
return ResourceClassMap.lookup(RC).prefix;
}
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This generates noticeably worse code because of the hash table lookup and also introduces a static initializer, which should really be avoided. It is possible to do something similar with a static table, but you need to break the abstraction of the enum a bit to do that and adding static asserts to make sure it's correct undoes most of the potential clarity it adds.
I suppose we could do something like this to couple the names, but I'm not entirely sold that the usability hit is worth it:
struct ResourceClassNameInfo {
const StringRef Name;
const StringRef Prefix;
};
static ResourceClassNameInfo getRCNameInfo(dxil::ResourceClass RC) {
switch (RC) {
case dxil::ResourceClass::SRV:
return {"SRV", "t"};
case dxil::ResourceClass::UAV:
return {"UAV", "u"};
case dxil::ResourceClass::CBuffer:
return {"cbuffer", "cb"};
case dxil::ResourceClass::Sampler:
return {"sampler", "s"};
}
llvm_unreachable("covered switch");
}
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM
Created using spr 1.3.5-bogner [skip ci]
Created using spr 1.3.5-bogner
Created using spr 1.3.5-bogner
Created using spr 1.3.5-bogner [skip ci]
Handle target extension type resources when printing resources to textual IR. Pull Request: llvm#104448
Handle target extension type resources when printing resources to textual IR. Pull Request: llvm#104448
Handle target extension type resources when printing resources to textual IR.