[llvm] [DirectX][objdump] Add support for printing signatures (PR #152531)
Chris B via llvm-commits
llvm-commits at lists.llvm.org
Thu Aug 7 12:44:37 PDT 2025
https://github.com/llvm-beanz updated https://github.com/llvm/llvm-project/pull/152531
>From 729fccb86e063e16925b2d3665f718c2c385ed69 Mon Sep 17 00:00:00 2001
From: Chris Bieneman <chris.bieneman at me.com>
Date: Thu, 7 Aug 2025 10:18:24 -0500
Subject: [PATCH 1/2] [DirectX][objdump] Add support for printing signatures
This adds support for printing the signature sections as part of the
`-p` flag for printing private headers.
The formatting aims to roughly match the formatting used by DXC's
`/dumpbin` flag.
Resolves #152380.
---
llvm/include/llvm/Object/DXContainer.h | 4 +
.../DXContainer/input-output-signatures.yaml | 161 ++++++++++++++++++
llvm/tools/llvm-objdump/DXContainerDump.cpp | 130 +++++++++++++-
3 files changed, 293 insertions(+), 2 deletions(-)
create mode 100644 llvm/test/tools/llvm-objdump/DXContainer/input-output-signatures.yaml
diff --git a/llvm/include/llvm/Object/DXContainer.h b/llvm/include/llvm/Object/DXContainer.h
index ad1b2361ff064..8a2efe2e928b0 100644
--- a/llvm/include/llvm/Object/DXContainer.h
+++ b/llvm/include/llvm/Object/DXContainer.h
@@ -603,6 +603,10 @@ class LLVM_ABI DXContainerObjectFile : public ObjectFile {
}
public:
+ const DXContainer &getDXContainer() const {
+ return Container;
+ }
+
static bool classof(const Binary *v) { return v->isDXContainer(); }
Expected<StringRef> getSymbolName(DataRefImpl) const override;
diff --git a/llvm/test/tools/llvm-objdump/DXContainer/input-output-signatures.yaml b/llvm/test/tools/llvm-objdump/DXContainer/input-output-signatures.yaml
new file mode 100644
index 0000000000000..fbfe17149cfb5
--- /dev/null
+++ b/llvm/test/tools/llvm-objdump/DXContainer/input-output-signatures.yaml
@@ -0,0 +1,161 @@
+# RUN: yaml2obj %s -o %t
+# RUN: llvm-objdump -p %t | FileCheck %s
+--- !dxcontainer
+Header:
+ Hash: [ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0 ]
+ Version:
+ Major: 1
+ Minor: 0
+ FileSize: 630
+ PartCount: 3
+ PartOffsets: [ 64, 124, 184 ]
+Parts:
+ - Name: ISG1
+ Size: 52
+ Signature:
+ Parameters:
+ - Stream: 0
+ Name: AAA_HSFoo
+ Index: 4391238 # This value forces the index column to widen
+ SystemValue: Undefined
+ CompType: Float32
+ Register: 0
+ Mask: 7
+ ExclusiveMask: 2
+ MinPrecision: Default
+ - Name: OSG1
+ Size: 52
+ Signature:
+ Parameters:
+ - Stream: 0
+ Name: SV_Position
+ Index: 0
+ SystemValue: Position
+ CompType: Float32
+ Register: 2147483647 # This value forces the register column to widen
+ Mask: 15
+ ExclusiveMask: 0
+ MinPrecision: Default
+ - Name: PSG1
+ Size: 402
+ Signature:
+ Parameters:
+ - Stream: 0
+ Name: SV_TessFactor
+ Index: 0
+ SystemValue: FinalQuadEdgeTessfactor # The tessfactor forces the SysVal column to widen
+ CompType: Float32
+ Register: 0
+ Mask: 8
+ ExclusiveMask: 8
+ MinPrecision: Default
+ - Stream: 0
+ Name: BBB
+ Index: 0
+ SystemValue: Undefined
+ CompType: Float32
+ Register: 0
+ Mask: 7
+ ExclusiveMask: 0
+ MinPrecision: Default
+ - Stream: 0
+ Name: SV_TessFactor
+ Index: 1
+ SystemValue: FinalQuadEdgeTessfactor
+ CompType: Float32
+ Register: 1
+ Mask: 8
+ ExclusiveMask: 8
+ MinPrecision: Default
+ - Stream: 0
+ Name: BBB
+ Index: 1
+ SystemValue: Undefined
+ CompType: Float32
+ Register: 1
+ Mask: 7
+ ExclusiveMask: 0
+ MinPrecision: Default
+ - Stream: 0
+ Name: SV_TessFactor
+ Index: 2
+ SystemValue: FinalQuadEdgeTessfactor
+ CompType: Float32
+ Register: 2
+ Mask: 8
+ ExclusiveMask: 8
+ MinPrecision: Default
+ - Stream: 0
+ Name: BBB
+ Index: 2
+ SystemValue: Undefined
+ CompType: Float32
+ Register: 2
+ Mask: 7
+ ExclusiveMask: 0
+ MinPrecision: Default
+ - Stream: 0
+ Name: SV_TessFactor
+ Index: 3
+ SystemValue: FinalQuadEdgeTessfactor
+ CompType: Float32
+ Register: 3
+ Mask: 8
+ ExclusiveMask: 8
+ MinPrecision: Default
+ - Stream: 0
+ Name: SV_InsideTessFactor
+ Index: 0
+ SystemValue: FinalQuadInsideTessfactor
+ CompType: Float32
+ Register: 4
+ Mask: 8
+ ExclusiveMask: 0
+ MinPrecision: Default
+ - Stream: 0
+ Name: SV_InsideTessFactor
+ Index: 1
+ SystemValue: FinalQuadInsideTessfactor
+ CompType: Float32
+ Register: 5
+ Mask: 8
+ ExclusiveMask: 0
+ MinPrecision: Default
+ - Stream: 0
+ Name: AVeryLongStringThatWillForceWidening # This value forces name column to widen
+ Index: 0
+ SystemValue: Undefined
+ CompType: Float32
+ Register: 6
+ Mask: 15
+ ExclusiveMask: 4
+ MinPrecision: Default
+...
+
+# CHECK: ; Input signature:
+# CHECK-NEXT: ;
+# CHECK-NEXT: ; Name Index Mask Register SysValue Format Used
+# CHECK-NEXT: ; ------------------------ ------- ----- -------- ---------- ------- -----
+# CHECK-NEXT: ; AAA_HSFoo 4391238 xyz 0 Undefined Float32 y
+
+# CHECK: ; Output signature:
+# CHECK-NEXT: ;
+# CHECK-NEXT: ; Name Index Mask Register SysValue Format Used
+# CHECK-NEXT: ; ------------------------ ----- ----- ---------- ---------- ------- -----
+# CHECK-NEXT: ; SV_Position 0 xyzw 2147483647 Position Float32
+
+# CHECK: ; Patch Constant signature:
+# CHECK-NEXT: ;
+# CHECK-NEXT: ; Name Index Mask Register SysValue Format Used
+# CHECK-NEXT: ; ------------------------------------ ----- ----- -------- ------------------------- ------- -----
+# CHECK-NEXT: ; SV_TessFactor 0 w 0 FinalQuadEdgeTessfactor Float32 w
+# CHECK-NEXT: ; BBB 0 xyz 0 Undefined Float32
+# CHECK-NEXT: ; SV_TessFactor 1 w 1 FinalQuadEdgeTessfactor Float32 w
+# CHECK-NEXT: ; BBB 1 xyz 1 Undefined Float32
+# CHECK-NEXT: ; SV_TessFactor 2 w 2 FinalQuadEdgeTessfactor Float32 w
+# CHECK-NEXT: ; BBB 2 xyz 2 Undefined Float32
+# CHECK-NEXT: ; SV_TessFactor 3 w 3 FinalQuadEdgeTessfactor Float32 w
+# CHECK-NEXT: ; SV_InsideTessFactor 0 w 4 FinalQuadInsideTessfactor Float32
+# CHECK-NEXT: ; SV_InsideTessFactor 1 w 5 FinalQuadInsideTessfactor Float32
+# CHECK-NEXT: ; AVeryLongStringThatWillForceWidening 0 xyzw 6 Undefined Float32 z
diff --git a/llvm/tools/llvm-objdump/DXContainerDump.cpp b/llvm/tools/llvm-objdump/DXContainerDump.cpp
index 2fb073473de53..17ae79b133a88 100644
--- a/llvm/tools/llvm-objdump/DXContainerDump.cpp
+++ b/llvm/tools/llvm-objdump/DXContainerDump.cpp
@@ -12,16 +12,142 @@
//===----------------------------------------------------------------------===//
#include "llvm-objdump.h"
+#include "llvm/BinaryFormat/DXContainer.h"
#include "llvm/Object/DXContainer.h"
+#include "llvm/Support/ScopedPrinter.h"
using namespace llvm;
+using namespace llvm::object;
+
+static llvm::SmallString<4> maskToString(uint8_t Mask) {
+ llvm::SmallString<4> Result(" ");
+ if (Mask & 1)
+ Result[0] = 'x';
+ if (Mask & 2)
+ Result[1] = 'y';
+ if (Mask & 4)
+ Result[2] = 'z';
+ if (Mask & 8)
+ Result[3] = 'w';
+ return Result;
+}
+
+static void printColumnHeader(raw_ostream &OS, size_t Length) {
+ for (size_t I = 0; I < Length; ++I)
+ OS << "-";
+}
+
+static void printColumnHeaders(raw_ostream &OS, ArrayRef<size_t> Lengths) {
+ for (auto L : Lengths) {
+ printColumnHeader(OS, L);
+ OS << " ";
+ }
+ OS << "\n";
+}
+
+static size_t digitsForNumber(size_t N) {
+ return static_cast<size_t>(log10(static_cast<double>(N))) + 1;
+}
namespace {
class DXContainerDumper : public objdump::Dumper {
+ const DXContainerObjectFile &Obj;
+
public:
- DXContainerDumper(const object::DXContainerObjectFile &Obj)
- : objdump::Dumper(Obj) {}
+ DXContainerDumper(const DXContainerObjectFile &O)
+ : objdump::Dumper(O), Obj(O) {}
+
+ void printPrivateHeaders() override;
+ void printSignature(const DirectX::Signature &S);
};
+
+void DXContainerDumper::printSignature(const DirectX::Signature &S) {
+ // DXC prints a table like this as part of the shader disassembly:
+ //; Name Index Mask Register SysValue Format Used
+ //; -------------------- ----- ------ -------- -------- ------- ------
+ //; NORMAL 0 xyz 0 NONE float xyz
+ //; TEXCOORD 0 xy 1 NONE float xy
+
+ // DXC's implementation doesn't scale columns entirely completely for the
+ // provided input, so this implementation is a bit more complicated in
+ // formatting logic to scale with the size of the printed text.
+
+ // DXC gives names 21 characters for some unknown reason, I arbitrarily chose
+ // to start at 24 so that we're not going shorter but are using a round
+ // number.
+ size_t LongestName = 24;
+ size_t LongestSV = 10;
+ size_t LongestIndex = strlen("Index");
+ size_t LongestRegister = strlen("Register");
+ size_t LongestFormat = strlen("Format");
+ const size_t MaskWidth = 5;
+ // Compute the column widths. Skip calculating the "Mask" and "Used" columns
+ // since they both have widths of 4.
+ for (auto El : S) {
+ LongestName = std::max(LongestName, S.getName(El.NameOffset).size());
+ LongestSV = std::max(
+ LongestSV,
+ enumToStringRef(El.SystemValue, dxbc::getD3DSystemValues()).size());
+ LongestIndex = std::max(LongestIndex, digitsForNumber(El.Index));
+ LongestRegister = std::max(LongestRegister, digitsForNumber(El.Register));
+ LongestFormat = std::max(
+ LongestFormat,
+ enumToStringRef(El.CompType, dxbc::getSigComponentTypes()).size());
+ }
+
+ // Print Column headers
+ OS << "; ";
+ OS << left_justify("Name", LongestName) << " ";
+ OS << right_justify("Index", LongestIndex) << " ";
+ OS << right_justify("Mask", MaskWidth) << " ";
+ OS << right_justify("Register", LongestRegister) << " ";
+ OS << right_justify("SysValue", LongestSV) << " ";
+ OS << right_justify("Format", LongestFormat) << " ";
+ OS << right_justify("Used", MaskWidth) << "\n";
+ OS << "; ";
+ printColumnHeaders(OS, {LongestName, LongestIndex, MaskWidth, LongestRegister,
+ LongestSV, LongestFormat, MaskWidth});
+
+ for (auto El : S) {
+ OS << "; " << left_justify(S.getName(El.NameOffset), LongestName) << " ";
+ OS << right_justify(std::to_string(El.Index), LongestIndex) << " ";
+ OS << right_justify(maskToString(El.Mask), MaskWidth) << " ";
+ OS << right_justify(std::to_string(El.Register), LongestRegister) << " ";
+ OS << right_justify(
+ enumToStringRef(El.SystemValue, dxbc::getD3DSystemValues()),
+ LongestSV)
+ << " ";
+ OS << right_justify(
+ enumToStringRef(El.CompType, dxbc::getSigComponentTypes()),
+ LongestFormat)
+ << " ";
+ OS << right_justify(maskToString(El.ExclusiveMask), MaskWidth) << "\n";
+ }
+}
+
+void DXContainerDumper::printPrivateHeaders() {
+ const DXContainer &C =
+ cast<object::DXContainerObjectFile>(Obj).getDXContainer();
+
+ if (!C.getInputSignature().isEmpty()) {
+ OS << "; Input signature:\n;\n";
+ printSignature(C.getInputSignature());
+ OS << ";\n";
+ }
+
+ if (!C.getOutputSignature().isEmpty()) {
+ OS << "; Output signature:\n;\n";
+ printSignature(C.getOutputSignature());
+ OS << ";\n";
+ }
+
+ if (!C.getPatchConstantSignature().isEmpty()) {
+ OS << "; Patch Constant signature:\n;\n";
+ printSignature(C.getPatchConstantSignature());
+ OS << ";\n";
+ }
+}
+
} // namespace
std::unique_ptr<objdump::Dumper> llvm::objdump::createDXContainerDumper(
>From 0c5a64c6918d01a80aa8c38d957175dd331deb10 Mon Sep 17 00:00:00 2001
From: Chris Bieneman <chris.bieneman at me.com>
Date: Thu, 7 Aug 2025 14:44:20 -0500
Subject: [PATCH 2/2] clang-format
---
llvm/include/llvm/Object/DXContainer.h | 4 +---
1 file changed, 1 insertion(+), 3 deletions(-)
diff --git a/llvm/include/llvm/Object/DXContainer.h b/llvm/include/llvm/Object/DXContainer.h
index 8a2efe2e928b0..93d39dabae4b9 100644
--- a/llvm/include/llvm/Object/DXContainer.h
+++ b/llvm/include/llvm/Object/DXContainer.h
@@ -603,9 +603,7 @@ class LLVM_ABI DXContainerObjectFile : public ObjectFile {
}
public:
- const DXContainer &getDXContainer() const {
- return Container;
- }
+ const DXContainer &getDXContainer() const { return Container; }
static bool classof(const Binary *v) { return v->isDXContainer(); }
More information about the llvm-commits
mailing list