[llvm] [DirectX][objdump] Add support for printing signatures (PR #152531)

James Henderson via llvm-commits llvm-commits at lists.llvm.org
Thu Aug 7 23:47:14 PDT 2025


================
@@ -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";
+  }
+}
+
----------------
jh7370 wrote:

Nit: the namespace starts with no blank lines after the opening brace, but finishes with one before the closing one. I don't think the coding standards have a stated preferred style, but mismatching seems wrong regardless!

https://github.com/llvm/llvm-project/pull/152531


More information about the llvm-commits mailing list