Skip to content

Commit be01355

Browse files
authored
[DirectX][objdump] Add support for printing signatures (llvm#153320)
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. The original version's printed output left some trailing whitespace on lines, which caused the tests to fail with the strict whitespace matching. Re-lands llvm#152531. Resolves llvm#152380.
1 parent 4f34c74 commit be01355

File tree

3 files changed

+307
-2
lines changed

3 files changed

+307
-2
lines changed

llvm/include/llvm/Object/DXContainer.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -603,6 +603,8 @@ class LLVM_ABI DXContainerObjectFile : public ObjectFile {
603603
}
604604

605605
public:
606+
const DXContainer &getDXContainer() const { return Container; }
607+
606608
static bool classof(const Binary *v) { return v->isDXContainer(); }
607609

608610
Expected<StringRef> getSymbolName(DataRefImpl) const override;
Lines changed: 167 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,167 @@
1+
# RUN: yaml2obj %s -o %t
2+
# RUN: llvm-objdump -p %t | FileCheck %s --match-full-lines --strict-whitespace
3+
4+
## This test covers llvm-objdump printing private headers for the ISG1, OSG1,
5+
## and PSG1 "parts" of the DX container file format. The test uses a few
6+
## absurdly large values and long string names to ensure that the columns in the
7+
## printed table widen correctly.
8+
9+
--- !dxcontainer
10+
Header:
11+
Hash: [ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
12+
0x0, 0x0, 0x0, 0x0, 0x0, 0x0 ]
13+
Version:
14+
Major: 1
15+
Minor: 0
16+
FileSize: 630
17+
PartCount: 3
18+
PartOffsets: [ 64, 124, 184 ]
19+
Parts:
20+
- Name: ISG1
21+
Size: 52
22+
Signature:
23+
Parameters:
24+
- Stream: 0
25+
Name: AAA_HSFoo
26+
Index: 4391238 # This value forces the index column to widen
27+
SystemValue: Undefined
28+
CompType: Float32
29+
Register: 0
30+
Mask: 7
31+
ExclusiveMask: 2
32+
MinPrecision: Default
33+
- Name: OSG1
34+
Size: 52
35+
Signature:
36+
Parameters:
37+
- Stream: 0
38+
Name: SV_Position
39+
Index: 0
40+
SystemValue: Position
41+
CompType: Float32
42+
Register: 2147483647 # This value forces the register column to widen
43+
Mask: 15
44+
ExclusiveMask: 0
45+
MinPrecision: Default
46+
- Name: PSG1
47+
Size: 402
48+
Signature:
49+
Parameters:
50+
- Stream: 0
51+
Name: SV_TessFactor
52+
Index: 0
53+
SystemValue: FinalQuadEdgeTessfactor # The tessfactor forces the SysVal column to widen
54+
CompType: Float32
55+
Register: 0
56+
Mask: 8
57+
ExclusiveMask: 8
58+
MinPrecision: Default
59+
- Stream: 0
60+
Name: BBB
61+
Index: 0
62+
SystemValue: Undefined
63+
CompType: Float32
64+
Register: 0
65+
Mask: 7
66+
ExclusiveMask: 0
67+
MinPrecision: Default
68+
- Stream: 0
69+
Name: SV_TessFactor
70+
Index: 1
71+
SystemValue: FinalQuadEdgeTessfactor
72+
CompType: Float32
73+
Register: 1
74+
Mask: 8
75+
ExclusiveMask: 8
76+
MinPrecision: Default
77+
- Stream: 0
78+
Name: BBB
79+
Index: 1
80+
SystemValue: Undefined
81+
CompType: Float32
82+
Register: 1
83+
Mask: 7
84+
ExclusiveMask: 0
85+
MinPrecision: Default
86+
- Stream: 0
87+
Name: SV_TessFactor
88+
Index: 2
89+
SystemValue: FinalQuadEdgeTessfactor
90+
CompType: Float32
91+
Register: 2
92+
Mask: 8
93+
ExclusiveMask: 8
94+
MinPrecision: Default
95+
- Stream: 0
96+
Name: BBB
97+
Index: 2
98+
SystemValue: Undefined
99+
CompType: Float32
100+
Register: 2
101+
Mask: 7
102+
ExclusiveMask: 0
103+
MinPrecision: Default
104+
- Stream: 0
105+
Name: SV_TessFactor
106+
Index: 3
107+
SystemValue: FinalQuadEdgeTessfactor
108+
CompType: Float32
109+
Register: 3
110+
Mask: 8
111+
ExclusiveMask: 8
112+
MinPrecision: Default
113+
- Stream: 0
114+
Name: SV_InsideTessFactor
115+
Index: 0
116+
SystemValue: FinalQuadInsideTessfactor
117+
CompType: Float32
118+
Register: 4
119+
Mask: 8
120+
ExclusiveMask: 0
121+
MinPrecision: Default
122+
- Stream: 0
123+
Name: SV_InsideTessFactor
124+
Index: 1
125+
SystemValue: FinalQuadInsideTessfactor
126+
CompType: Float32
127+
Register: 5
128+
Mask: 8
129+
ExclusiveMask: 0
130+
MinPrecision: Default
131+
- Stream: 0
132+
Name: AVeryLongStringThatWillForceWidening # This value forces name column to widen
133+
Index: 0
134+
SystemValue: Undefined
135+
CompType: Float32
136+
Register: 6
137+
Mask: 15
138+
ExclusiveMask: 4
139+
MinPrecision: Default
140+
...
141+
142+
# CHECK:; Input signature:
143+
# CHECK-NEXT:;
144+
# CHECK-NEXT:; Name Index Mask Register SysValue Format Used
145+
# CHECK-NEXT:; ------------------------ ------- ----- -------- ---------- ------- -----
146+
# CHECK-NEXT:; AAA_HSFoo 4391238 xyz 0 Undefined Float32 y
147+
148+
# CHECK:; Output signature:
149+
# CHECK-NEXT:;
150+
# CHECK-NEXT:; Name Index Mask Register SysValue Format Used
151+
# CHECK-NEXT:; ------------------------ ----- ----- ---------- ---------- ------- -----
152+
# CHECK-NEXT:; SV_Position 0 xyzw 2147483647 Position Float32
153+
154+
# CHECK:; Patch Constant signature:
155+
# CHECK-NEXT:;
156+
# CHECK-NEXT:; Name Index Mask Register SysValue Format Used
157+
# CHECK-NEXT:; ------------------------------------ ----- ----- -------- ------------------------- ------- -----
158+
# CHECK-NEXT:; SV_TessFactor 0 w 0 FinalQuadEdgeTessfactor Float32 w
159+
# CHECK-NEXT:; BBB 0 xyz 0 Undefined Float32
160+
# CHECK-NEXT:; SV_TessFactor 1 w 1 FinalQuadEdgeTessfactor Float32 w
161+
# CHECK-NEXT:; BBB 1 xyz 1 Undefined Float32
162+
# CHECK-NEXT:; SV_TessFactor 2 w 2 FinalQuadEdgeTessfactor Float32 w
163+
# CHECK-NEXT:; BBB 2 xyz 2 Undefined Float32
164+
# CHECK-NEXT:; SV_TessFactor 3 w 3 FinalQuadEdgeTessfactor Float32 w
165+
# CHECK-NEXT:; SV_InsideTessFactor 0 w 4 FinalQuadInsideTessfactor Float32
166+
# CHECK-NEXT:; SV_InsideTessFactor 1 w 5 FinalQuadInsideTessfactor Float32
167+
# CHECK-NEXT:; AVeryLongStringThatWillForceWidening 0 xyzw 6 Undefined Float32 z

llvm/tools/llvm-objdump/DXContainerDump.cpp

Lines changed: 138 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -12,16 +12,152 @@
1212
//===----------------------------------------------------------------------===//
1313

1414
#include "llvm-objdump.h"
15+
#include "llvm/BinaryFormat/DXContainer.h"
1516
#include "llvm/Object/DXContainer.h"
17+
#include "llvm/Support/ScopedPrinter.h"
1618

1719
using namespace llvm;
20+
using namespace llvm::object;
21+
22+
static llvm::SmallString<4> maskToString(uint8_t Mask,
23+
bool StripTrailing = false) {
24+
llvm::SmallString<4> Result(" ");
25+
if (Mask & 1)
26+
Result[0] = 'x';
27+
if (Mask & 2)
28+
Result[1] = 'y';
29+
if (Mask & 4)
30+
Result[2] = 'z';
31+
if (Mask & 8)
32+
Result[3] = 'w';
33+
if (!StripTrailing)
34+
return Result;
35+
int Size = 8 - countl_zero(Mask);
36+
return Result.slice(0, Size);
37+
}
38+
39+
static void printColumnHeader(raw_ostream &OS, size_t Length) {
40+
for (size_t I = 0; I < Length; ++I)
41+
OS << "-";
42+
}
43+
44+
static void printColumnHeaders(raw_ostream &OS, ArrayRef<size_t> Lengths) {
45+
// Generate the header in a temporary to avoid trailing whitespace.
46+
SmallString<256> Str;
47+
raw_svector_ostream Tmp(Str);
48+
for (auto L : Lengths) {
49+
printColumnHeader(Tmp, L);
50+
Tmp << " ";
51+
}
52+
Str.back() = '\n';
53+
OS << Str;
54+
}
55+
56+
static size_t digitsForNumber(size_t N) {
57+
if (N == 0)
58+
return 1;
59+
return static_cast<size_t>(log10(static_cast<double>(N))) + 1;
60+
}
1861

1962
namespace {
2063
class DXContainerDumper : public objdump::Dumper {
64+
const DXContainerObjectFile &Obj;
65+
2166
public:
22-
DXContainerDumper(const object::DXContainerObjectFile &Obj)
23-
: objdump::Dumper(Obj) {}
67+
DXContainerDumper(const DXContainerObjectFile &O)
68+
: objdump::Dumper(O), Obj(O) {}
69+
70+
void printPrivateHeaders() override;
71+
void printSignature(const DirectX::Signature &S);
2472
};
73+
74+
void DXContainerDumper::printSignature(const DirectX::Signature &S) {
75+
// DXC prints a table like this as part of the shader disassembly:
76+
//; Name Index Mask Register SysValue Format Used
77+
//; -------------------- ----- ------ -------- -------- ------- ------
78+
//; NORMAL 0 xyz 0 NONE float xyz
79+
//; TEXCOORD 0 xy 1 NONE float xy
80+
81+
// DXC's implementation doesn't scale columns entirely completely for the
82+
// provided input, so this implementation is a bit more complicated in
83+
// formatting logic to scale with the size of the printed text.
84+
85+
// DXC gives names 21 characters for some unknown reason, I arbitrarily chose
86+
// to start at 24 so that we're not going shorter but are using a round
87+
// number.
88+
size_t LongestName = 24;
89+
size_t LongestSV = 10;
90+
size_t LongestIndex = strlen("Index");
91+
size_t LongestRegister = strlen("Register");
92+
size_t LongestFormat = strlen("Format");
93+
const size_t MaskWidth = 5;
94+
// Compute the column widths. Skip calculating the "Mask" and "Used" columns
95+
// since they both have widths of 4.
96+
for (auto El : S) {
97+
LongestName = std::max(LongestName, S.getName(El.NameOffset).size());
98+
LongestSV = std::max(
99+
LongestSV,
100+
enumToStringRef(El.SystemValue, dxbc::getD3DSystemValues()).size());
101+
LongestIndex = std::max(LongestIndex, digitsForNumber(El.Index));
102+
LongestRegister = std::max(LongestRegister, digitsForNumber(El.Register));
103+
LongestFormat = std::max(
104+
LongestFormat,
105+
enumToStringRef(El.CompType, dxbc::getSigComponentTypes()).size());
106+
}
107+
108+
// Print Column headers.
109+
OS << "; ";
110+
OS << left_justify("Name", LongestName) << " ";
111+
OS << right_justify("Index", LongestIndex) << " ";
112+
OS << right_justify("Mask", MaskWidth) << " ";
113+
OS << right_justify("Register", LongestRegister) << " ";
114+
OS << right_justify("SysValue", LongestSV) << " ";
115+
OS << right_justify("Format", LongestFormat) << " ";
116+
OS << right_justify("Used", MaskWidth) << "\n";
117+
OS << "; ";
118+
printColumnHeaders(OS, {LongestName, LongestIndex, MaskWidth, LongestRegister,
119+
LongestSV, LongestFormat, MaskWidth});
120+
121+
for (auto El : S) {
122+
OS << "; " << left_justify(S.getName(El.NameOffset), LongestName) << " ";
123+
OS << right_justify(std::to_string(El.Index), LongestIndex) << " ";
124+
OS << right_justify(maskToString(El.Mask), MaskWidth) << " ";
125+
OS << right_justify(std::to_string(El.Register), LongestRegister) << " ";
126+
OS << right_justify(
127+
enumToStringRef(El.SystemValue, dxbc::getD3DSystemValues()),
128+
LongestSV)
129+
<< " ";
130+
OS << right_justify(
131+
enumToStringRef(El.CompType, dxbc::getSigComponentTypes()),
132+
LongestFormat);
133+
if (El.ExclusiveMask)
134+
OS << " " << maskToString(El.ExclusiveMask, true);
135+
OS << "\n";
136+
}
137+
}
138+
139+
void DXContainerDumper::printPrivateHeaders() {
140+
const DXContainer &C =
141+
cast<object::DXContainerObjectFile>(Obj).getDXContainer();
142+
143+
if (!C.getInputSignature().isEmpty()) {
144+
OS << "; Input signature:\n;\n";
145+
printSignature(C.getInputSignature());
146+
OS << ";\n";
147+
}
148+
149+
if (!C.getOutputSignature().isEmpty()) {
150+
OS << "; Output signature:\n;\n";
151+
printSignature(C.getOutputSignature());
152+
OS << ";\n";
153+
}
154+
155+
if (!C.getPatchConstantSignature().isEmpty()) {
156+
OS << "; Patch Constant signature:\n;\n";
157+
printSignature(C.getPatchConstantSignature());
158+
OS << ";\n";
159+
}
160+
}
25161
} // namespace
26162

27163
std::unique_ptr<objdump::Dumper> llvm::objdump::createDXContainerDumper(

0 commit comments

Comments
 (0)