diff --git a/llvm/include/llvm/Analysis/DXILResource.h b/llvm/include/llvm/Analysis/DXILResource.h index 58db0a93f2f35..6b577c02f0545 100644 --- a/llvm/include/llvm/Analysis/DXILResource.h +++ b/llvm/include/llvm/Analysis/DXILResource.h @@ -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; @@ -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; @@ -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); } diff --git a/llvm/lib/Target/DirectX/DXILPrettyPrinter.cpp b/llvm/lib/Target/DirectX/DXILPrettyPrinter.cpp index 7185771792d4a..f282eff6c002b 100644 --- a/llvm/lib/Target/DirectX/DXILPrettyPrinter.cpp +++ b/llvm/lib/Target/DirectX/DXILPrettyPrinter.cpp @@ -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 { + explicit FormatResourceDimension(const dxil::ResourceInfo &RI) + : llvm::FormatAdapter(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 { + explicit FormatBindingID(const dxil::ResourceInfo &RI) + : llvm::FormatAdapter(RI) {} + + void format(llvm::raw_ostream &OS, StringRef Style) override { + OS << getRCPrefix(Item.getResourceClass()).upper() + << Item.getBinding().RecordID; + } +}; + +struct FormatBindingLocation + : public llvm::FormatAdapter { + explicit FormatBindingLocation(const dxil::ResourceInfo &RI) + : llvm::FormatAdapter(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 { + explicit FormatBindingSize(const dxil::ResourceInfo &RI) + : llvm::FormatAdapter(RI) {} + + void format(llvm::raw_ostream &OS, StringRef Style) override { + uint32_t Size = Item.getBinding().Size; + if (Size == std::numeric_limits::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); @@ -37,8 +249,9 @@ static void prettyPrintResources(raw_ostream &OS, PreservedAnalyses DXILPrettyPrinterPass::run(Module &M, ModuleAnalysisManager &MAM) { + const DXILResourceMap &DRM = MAM.getResult(M); const dxil::Resources &MDResources = MAM.getResult(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(); AU.addRequired(); } }; @@ -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().getResourceMap(); dxil::Resources &Res = getAnalysis().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 55e72e1cb2eb0..40b3b2c712272 100644 --- a/llvm/test/CodeGen/DirectX/CreateHandle.ll +++ b/llvm/test/CodeGen/DirectX/CreateHandle.ll @@ -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.0-compute" diff --git a/llvm/test/CodeGen/DirectX/CreateHandleFromBinding.ll b/llvm/test/CodeGen/DirectX/CreateHandleFromBinding.ll index c8f9f05c35108..d0c80c018b8d7 100644 --- a/llvm/test/CodeGen/DirectX/CreateHandleFromBinding.ll +++ b/llvm/test/CodeGen/DirectX/CreateHandleFromBinding.ll @@ -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"