diff --git a/llvm/include/llvm/Object/DXContainer.h b/llvm/include/llvm/Object/DXContainer.h index ad1b2361ff064..93d39dabae4b9 100644 --- a/llvm/include/llvm/Object/DXContainer.h +++ b/llvm/include/llvm/Object/DXContainer.h @@ -603,6 +603,8 @@ class LLVM_ABI DXContainerObjectFile : public ObjectFile { } public: + const DXContainer &getDXContainer() const { return Container; } + static bool classof(const Binary *v) { return v->isDXContainer(); } Expected 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..7cc11af251182 --- /dev/null +++ b/llvm/test/tools/llvm-objdump/DXContainer/input-output-signatures.yaml @@ -0,0 +1,167 @@ +# RUN: yaml2obj %s -o %t +# RUN: llvm-objdump -p %t | FileCheck %s --match-full-lines --strict-whitespace + +# This test covers llvm-objdump printing private headers for the ISG1, OSG1, and +# PSG1 "parts" of the DX container file format. The test uses a few absurdly +# large values and long string names to ensure that the columns in the printed +# table widen correctly. + +--- !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..963ff54d4e411 100644 --- a/llvm/tools/llvm-objdump/DXContainerDump.cpp +++ b/llvm/tools/llvm-objdump/DXContainerDump.cpp @@ -12,16 +12,141 @@ //===----------------------------------------------------------------------===// #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 Lengths) { + for (auto L : Lengths) { + printColumnHeader(OS, L); + OS << " "; + } + OS << "\n"; +} + +static size_t digitsForNumber(size_t N) { + return static_cast(log10(static_cast(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(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 llvm::objdump::createDXContainerDumper(