-
Notifications
You must be signed in to change notification settings - Fork 14.8k
[HLSL][RootSignature] Implement serialized dump of Descriptor Tables #138326
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
@llvm/pr-subscribers-hlsl Author: Finn Plummer (inbelic) Changes
Resolves #138189 Full diff: https://github.com/llvm/llvm-project/pull/138326.diff 5 Files Affected:
diff --git a/llvm/include/llvm/Frontend/HLSL/HLSLRootSignature.h b/llvm/include/llvm/Frontend/HLSL/HLSLRootSignature.h
index 818caccfe1998..6d3ecd166f461 100644
--- a/llvm/include/llvm/Frontend/HLSL/HLSLRootSignature.h
+++ b/llvm/include/llvm/Frontend/HLSL/HLSLRootSignature.h
@@ -15,6 +15,7 @@
#define LLVM_FRONTEND_HLSL_HLSLROOTSIGNATURE_H
#include "llvm/Support/DXILABI.h"
+#include "llvm/Support/raw_ostream.h"
#include <variant>
namespace llvm {
@@ -52,12 +53,16 @@ enum class RegisterType { BReg, TReg, UReg, SReg };
struct Register {
RegisterType ViewType;
uint32_t Number;
+
+ void dump(raw_ostream &OS) const;
};
// Models the end of a descriptor table and stores its visibility
struct DescriptorTable {
ShaderVisibility Visibility = ShaderVisibility::All;
uint32_t NumClauses = 0; // The number of clauses in the table
+
+ void dump(raw_ostream &OS) const;
};
static const uint32_t NumDescriptorsUnbounded = 0xffffffff;
@@ -86,6 +91,8 @@ struct DescriptorTableClause {
break;
}
}
+
+ void dump(raw_ostream &OS) const;
};
// Models RootElement : DescriptorTable | DescriptorTableClause
diff --git a/llvm/lib/Frontend/HLSL/CMakeLists.txt b/llvm/lib/Frontend/HLSL/CMakeLists.txt
index 07a0c845ceef6..dd987544fe80b 100644
--- a/llvm/lib/Frontend/HLSL/CMakeLists.txt
+++ b/llvm/lib/Frontend/HLSL/CMakeLists.txt
@@ -1,6 +1,7 @@
add_llvm_component_library(LLVMFrontendHLSL
CBuffer.cpp
HLSLResource.cpp
+ HLSLRootSignature.cpp
ADDITIONAL_HEADER_DIRS
${LLVM_MAIN_INCLUDE_DIR}/llvm/Frontend
diff --git a/llvm/lib/Frontend/HLSL/HLSLRootSignature.cpp b/llvm/lib/Frontend/HLSL/HLSLRootSignature.cpp
new file mode 100644
index 0000000000000..a5f0313138521
--- /dev/null
+++ b/llvm/lib/Frontend/HLSL/HLSLRootSignature.cpp
@@ -0,0 +1,154 @@
+//===- HLSLRootSignature.cpp - HLSL Root Signature helper objects ---------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+///
+/// \file This file contains helpers for working with HLSL Root Signatures.
+///
+//===----------------------------------------------------------------------===//
+
+#include "llvm/Frontend/HLSL/HLSLRootSignature.h"
+#include "llvm/ADT/bit.h"
+
+namespace llvm {
+namespace hlsl {
+namespace rootsig {
+
+static void dumpRegType(raw_ostream &OS, RegisterType Type) {
+ switch (Type) {
+ case RegisterType::BReg:
+ OS << "b";
+ break;
+ case RegisterType::TReg:
+ OS << "t";
+ break;
+ case RegisterType::UReg:
+ OS << "u";
+ break;
+ case RegisterType::SReg:
+ OS << "s";
+ break;
+ }
+}
+
+void Register::dump(raw_ostream &OS) const {
+ dumpRegType(OS, ViewType);
+ OS << Number;
+}
+
+static void dumpVisibility(raw_ostream &OS, ShaderVisibility Visibility) {
+ switch (Visibility) {
+ case ShaderVisibility::All:
+ OS << "All";
+ break;
+ case ShaderVisibility::Vertex:
+ OS << "Vertex";
+ break;
+ case ShaderVisibility::Hull:
+ OS << "Hull";
+ break;
+ case ShaderVisibility::Domain:
+ OS << "Domain";
+ break;
+ case ShaderVisibility::Geometry:
+ OS << "Geometry";
+ break;
+ case ShaderVisibility::Pixel:
+ OS << "Pixel";
+ break;
+ case ShaderVisibility::Amplification:
+ OS << "Amplification";
+ break;
+ case ShaderVisibility::Mesh:
+ OS << "Mesh";
+ break;
+ }
+}
+
+void DescriptorTable::dump(raw_ostream &OS) const {
+ OS << "DescriptorTable(numClauses = " << NumClauses;
+ OS << ", visibility = ";
+ dumpVisibility(OS, Visibility);
+ OS << ")";
+}
+
+static void dumpClauseType(raw_ostream &OS, ClauseType Type) {
+ switch (Type) {
+ case ClauseType::CBuffer:
+ OS << "CBV";
+ break;
+ case ClauseType::SRV:
+ OS << "SRV";
+ break;
+ case ClauseType::UAV:
+ OS << "UAV";
+ break;
+ case ClauseType::Sampler:
+ OS << "Sampler";
+ break;
+ }
+}
+
+static void dumpDescriptorRangeFlag(raw_ostream &OS, unsigned Bit) {
+ switch (static_cast<DescriptorRangeFlags>(Bit)) {
+ case DescriptorRangeFlags::DescriptorsVolatile:
+ OS << "DescriptorsVolatile";
+ break;
+ case DescriptorRangeFlags::DataVolatile:
+ OS << "DataVolatile";
+ break;
+ case DescriptorRangeFlags::DataStaticWhileSetAtExecute:
+ OS << "DataStaticWhileSetAtExecute";
+ break;
+ case DescriptorRangeFlags::DataStatic:
+ OS << "DataStatic";
+ break;
+ case DescriptorRangeFlags::DescriptorsStaticKeepingBufferBoundsChecks:
+ OS << "DescriptorsStaticKeepingBufferBoundsChecks";
+ break;
+ default:
+ OS << "invalid: " << Bit;
+ break;
+ }
+}
+
+static void dumpDescriptorRangeFlags(raw_ostream &OS,
+ DescriptorRangeFlags Flags) {
+ bool FlagSet = false;
+ unsigned Remaining = llvm::to_underlying(Flags);
+ while (Remaining) {
+ unsigned Bit = 1u << llvm::countr_zero(Remaining);
+ if (Remaining & Bit) {
+ if (FlagSet)
+ OS << " | ";
+ dumpDescriptorRangeFlag(OS, Bit);
+ FlagSet = true;
+ }
+ Remaining &= ~Bit;
+ }
+ if (!FlagSet)
+ OS << "None";
+}
+
+void DescriptorTableClause::dump(raw_ostream &OS) const {
+ dumpClauseType(OS, Type);
+ OS << "(";
+ Reg.dump(OS);
+ OS << ", numDescriptors = " << NumDescriptors;
+ OS << ", space = " << Space;
+ OS << ", offset = ";
+ if (Offset == DescriptorTableOffsetAppend)
+ OS << "DescriptorTableOffsetAppend";
+ else
+ OS << Offset;
+ OS << ", flags = ";
+ dumpDescriptorRangeFlags(OS, Flags);
+ OS << ")";
+}
+
+} // namespace rootsig
+} // namespace hlsl
+} // namespace llvm
diff --git a/llvm/unittests/Frontend/CMakeLists.txt b/llvm/unittests/Frontend/CMakeLists.txt
index 85e113816e3bc..2119642769e3d 100644
--- a/llvm/unittests/Frontend/CMakeLists.txt
+++ b/llvm/unittests/Frontend/CMakeLists.txt
@@ -1,6 +1,7 @@
set(LLVM_LINK_COMPONENTS
Analysis
Core
+ FrontendHLSL
FrontendOpenACC
FrontendOpenMP
Passes
@@ -10,6 +11,7 @@ set(LLVM_LINK_COMPONENTS
)
add_llvm_unittest(LLVMFrontendTests
+ HLSLRootSignatureDumpTest.cpp
OpenACCTest.cpp
OpenMPContextTest.cpp
OpenMPIRBuilderTest.cpp
diff --git a/llvm/unittests/Frontend/HLSLRootSignatureDumpTest.cpp b/llvm/unittests/Frontend/HLSLRootSignatureDumpTest.cpp
new file mode 100644
index 0000000000000..ba1fbfd1f8708
--- /dev/null
+++ b/llvm/unittests/Frontend/HLSLRootSignatureDumpTest.cpp
@@ -0,0 +1,111 @@
+//===-------- HLSLRootSignatureDumpTest.cpp - RootSignature dump tests ----===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include "llvm/Frontend/HLSL/HLSLRootSignature.h"
+#include "gtest/gtest.h"
+
+using namespace llvm::hlsl::rootsig;
+
+namespace {
+
+TEST(HLSLRootSignatureTest, DescriptorCBVClauseDump) {
+ DescriptorTableClause Clause;
+ Clause.Type = ClauseType::CBuffer;
+ Clause.Reg = {RegisterType::BReg, 0};
+ Clause.setDefaultFlags();
+
+ std::string Out;
+ llvm::raw_string_ostream OS(Out);
+ Clause.dump(OS);
+ OS.flush();
+
+ std::string Expected = "CBV(b0, numDescriptors = 1, space = 0, "
+ "offset = DescriptorTableOffsetAppend, "
+ "flags = DataStaticWhileSetAtExecute)";
+ EXPECT_EQ(Out, Expected);
+}
+
+TEST(HLSLRootSignatureTest, DescriptorSRVClauseDump) {
+ DescriptorTableClause Clause;
+ Clause.Type = ClauseType::SRV;
+ Clause.Reg = {RegisterType::TReg, 0};
+ Clause.NumDescriptors = 2;
+ Clause.Space = 42;
+ Clause.Offset = 3;
+ Clause.Flags = DescriptorRangeFlags::None;
+
+ std::string Out;
+ llvm::raw_string_ostream OS(Out);
+ Clause.dump(OS);
+ OS.flush();
+
+ std::string Expected =
+ "SRV(t0, numDescriptors = 2, space = 42, offset = 3, flags = None)";
+ EXPECT_EQ(Out, Expected);
+}
+
+TEST(HLSLRootSignatureTest, DescriptorUAVClauseDump) {
+ DescriptorTableClause Clause;
+ Clause.Type = ClauseType::UAV;
+ Clause.Reg = {RegisterType::UReg, 92374};
+ Clause.NumDescriptors = 3298;
+ Clause.Space = 932847;
+ Clause.Offset = 1;
+ Clause.Flags = DescriptorRangeFlags::ValidFlags;
+
+ std::string Out;
+ llvm::raw_string_ostream OS(Out);
+ Clause.dump(OS);
+ OS.flush();
+
+ std::string Expected =
+ "UAV(u92374, numDescriptors = 3298, space = 932847, offset = 1, flags = "
+ "DescriptorsVolatile | "
+ "DataVolatile | "
+ "DataStaticWhileSetAtExecute | "
+ "DataStatic | "
+ "DescriptorsStaticKeepingBufferBoundsChecks)";
+ EXPECT_EQ(Out, Expected);
+}
+
+TEST(HLSLRootSignatureTest, DescriptorSamplerClauseDump) {
+ DescriptorTableClause Clause;
+ Clause.Type = ClauseType::Sampler;
+ Clause.Reg = {RegisterType::SReg, 0};
+ Clause.NumDescriptors = 2;
+ Clause.Space = 42;
+ Clause.Offset = DescriptorTableOffsetAppend;
+ Clause.Flags = DescriptorRangeFlags::ValidSamplerFlags;
+
+ std::string Out;
+ llvm::raw_string_ostream OS(Out);
+ Clause.dump(OS);
+ OS.flush();
+
+ std::string Expected = "Sampler(s0, numDescriptors = 2, space = 42, offset = "
+ "DescriptorTableOffsetAppend, "
+ "flags = DescriptorsVolatile)";
+ EXPECT_EQ(Out, Expected);
+}
+
+TEST(HLSLRootSignatureTest, DescriptorTableDump) {
+ DescriptorTable Table;
+ Table.NumClauses = 4;
+ Table.Visibility = ShaderVisibility::Geometry;
+
+ std::string Out;
+ llvm::raw_string_ostream OS(Out);
+ Table.dump(OS);
+ OS.flush();
+
+ std::string Expected =
+ "DescriptorTable(numClauses = 4, visibility = Geometry)";
+ EXPECT_EQ(Out, Expected);
+}
+
+} // namespace
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
nit: Is it possible to have invalid data when serializing ? What is expected in such scenario?
The data structures are only constructed through using the |
namespace hlsl { | ||
namespace rootsig { | ||
|
||
static void dumpRegType(raw_ostream &OS, RegisterType Type) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think this whole file becomes a bit simpler and cleaner if we define a bunch of operator<<
s instead of dump functions. So here we could have
static raw_ostream &operator<<(raw_ostream &OS, const Register &Reg) {
switch (Reg.Type) {
case RegisterType::BReg:
OS << "b";
break;
// ...
}
OS << Number;
return OS;
and similarly for the rest of these static dump functions. Then the publicly visible dump()
methods can be implemented as OS << "Foo(" << thing1 << "bar = " << thing2 << ")"
etc
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
+1
- nicely improves code readability
LLVM Buildbot has detected a new failure on builder Full details are available at: https://lab.llvm.org/buildbot/#/builders/23/builds/10148 Here is the relevant piece of the build log for the reference
|
LLVM Buildbot has detected a new failure on builder Full details are available at: https://lab.llvm.org/buildbot/#/builders/64/builds/3488 Here is the relevant piece of the build log for the reference
|
LLVM Buildbot has detected a new failure on builder Full details are available at: https://lab.llvm.org/buildbot/#/builders/146/builds/2888 Here is the relevant piece of the build log for the reference
|
dump
method for in-memory descriptor table data structs inFrontend/HLSLRootSignature
Resolves #138189