-
Notifications
You must be signed in to change notification settings - Fork 13.6k
[HLSL][RootSignature] Metadata generation of RootFlags, RootConstants, RootDescriptors #142010
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) ChangesImplements metadata generation of a Root Signature from its in-memory representation. This pr handles RootFlags, RootConstants and RootDescriptors. The metadata follows the format described here.
Note: there is no validation of metadata nodes as the First part of #126586. Full diff: https://github.com/llvm/llvm-project/pull/142010.diff 3 Files Affected:
diff --git a/clang/test/CodeGenHLSL/RootSignature.hlsl b/clang/test/CodeGenHLSL/RootSignature.hlsl
index 60e0dec175b8f..85f47727ce91f 100644
--- a/clang/test/CodeGenHLSL/RootSignature.hlsl
+++ b/clang/test/CodeGenHLSL/RootSignature.hlsl
@@ -1,16 +1,17 @@
// RUN: %clang_cc1 -triple dxil-pc-shadermodel6.3-library -emit-llvm -o - %s | FileCheck %s
-// CHECK: !dx.rootsignatures = !{![[#FIRST_ENTRY:]], ![[#SECOND_ENTRY:]]}
+// CHECK: !dx.rootsignatures = !{![[#EMPTY_ENTRY:]], ![[#DT_ENTRY:]],
+// CHECK-SAME: ![[#RF_ENTRY:]], ![[#RC_ENTRY:]], ![[#RD_ENTRY:]]}
-// CHECK: ![[#FIRST_ENTRY]] = !{ptr @FirstEntry, ![[#EMPTY:]]}
+// CHECK: ![[#EMPTY_ENTRY]] = !{ptr @EmptyEntry, ![[#EMPTY:]]}
// CHECK: ![[#EMPTY]] = !{}
[shader("compute"), RootSignature("")]
[numthreads(1,1,1)]
-void FirstEntry() {}
+void EmptyEntry() {}
-// CHECK: ![[#SECOND_ENTRY]] = !{ptr @SecondEntry, ![[#SECOND_RS:]]}
-// CHECK: ![[#SECOND_RS]] = !{![[#TABLE:]]}
+// CHECK: ![[#DT_ENTRY]] = !{ptr @DescriptorTableEntry, ![[#DT_RS:]]}
+// CHECK: ![[#DT_RS]] = !{![[#TABLE:]]}
// CHECK: ![[#TABLE]] = !{!"DescriptorTable", i32 0, ![[#CBV:]], ![[#SRV:]]}
// CHECK: ![[#CBV]] = !{!"CBV", i32 1, i32 0, i32 0, i32 -1, i32 4}
// CHECK: ![[#SRV]] = !{!"SRV", i32 4, i32 42, i32 3, i32 32, i32 0}
@@ -22,10 +23,51 @@ void FirstEntry() {}
")"
[shader("compute"), RootSignature(SampleDescriptorTable)]
[numthreads(1,1,1)]
-void SecondEntry() {}
+void DescriptorTableEntry() {}
+
+// CHECK: ![[#RF_ENTRY]] = !{ptr @RootFlagsEntry, ![[#RF_RS:]]}
+// CHECK: ![[#RF_RS]] = !{![[#ROOT_FLAGS:]]}
+// CHECK: ![[#ROOT_FLAGS]] = !{!"RootFlags", i32 2114}
+
+#define SampleRootFlags \
+ "RootFlags( " \
+ " Deny_Vertex_Shader_Root_Access | Allow_Stream_Output | " \
+ " sampler_heap_directly_indexed " \
+ ")"
+[shader("compute"), RootSignature(SampleRootFlags)]
+[numthreads(1,1,1)]
+void RootFlagsEntry() {}
+
+// CHECK: ![[#RC_ENTRY]] = !{ptr @RootConstantsEntry, ![[#RC_RS:]]}
+// CHECK: ![[#RC_RS]] = !{![[#ROOT_CONSTANTS:]]}
+// CHECK: ![[#ROOT_CONSTANTS]] = !{!"RootConstants", i32 5, i32 1, i32 2, i32 1}
+
+#define SampleRootConstants \
+ "RootConstants(" \
+ " space = 2, " \
+ " visibility = Shader_Visibility_Pixel, " \
+ " b1, num32BitConstants = 1 " \
+ ")"
+[shader("compute"), RootSignature(SampleRootConstants)]
+[numthreads(1,1,1)]
+void RootConstantsEntry() {}
+
+// CHECK: ![[#RD_ENTRY]] = !{ptr @RootDescriptorsEntry, ![[#RD_RS:]]}
+// CHECK: ![[#RD_RS]] = !{![[#ROOT_CBV:]], ![[#ROOT_UAV:]], ![[#ROOT_SRV:]]}
+// CHECK: ![[#ROOT_CBV]] = !{!"RootCBV", i32 0, i32 0, i32 0, i32 4}
+// CHECK: ![[#ROOT_UAV]] = !{!"RootUAV", i32 0, i32 0, i32 0, i32 2}
+// CHECK: ![[#ROOT_SRV]] = !{!"RootSRV", i32 0, i32 0, i32 0, i32 4}
+
+#define SampleRootDescriptors \
+ "CBV(b0), " \
+ "UAV(u0), " \
+ "SRV(t0)"
+[shader("compute"), RootSignature(SampleRootDescriptors)]
+[numthreads(1,1,1)]
+void RootDescriptorsEntry() {}
// Sanity test to ensure no root is added for this function as there is only
// two entries in !dx.roosignatures
[shader("compute")]
[numthreads(1,1,1)]
-void ThirdEntry() {}
+void NoRSEntry() {}
diff --git a/llvm/include/llvm/Frontend/HLSL/HLSLRootSignature.h b/llvm/include/llvm/Frontend/HLSL/HLSLRootSignature.h
index fd0abc9479469..d020dc413f0af 100644
--- a/llvm/include/llvm/Frontend/HLSL/HLSLRootSignature.h
+++ b/llvm/include/llvm/Frontend/HLSL/HLSLRootSignature.h
@@ -188,6 +188,9 @@ class MetadataBuilder {
private:
/// Define the various builders for the different metadata types
+ MDNode *BuildRootFlags(const RootFlags &Flags);
+ MDNode *BuildRootConstants(const RootConstants &Constants);
+ MDNode *BuildRootDescriptor(const RootDescriptor &Descriptor);
MDNode *BuildDescriptorTable(const DescriptorTable &Table);
MDNode *BuildDescriptorTableClause(const DescriptorTableClause &Clause);
diff --git a/llvm/lib/Frontend/HLSL/HLSLRootSignature.cpp b/llvm/lib/Frontend/HLSL/HLSLRootSignature.cpp
index ec0d130a6767c..cd606e61fcebf 100644
--- a/llvm/lib/Frontend/HLSL/HLSLRootSignature.cpp
+++ b/llvm/lib/Frontend/HLSL/HLSLRootSignature.cpp
@@ -171,6 +171,12 @@ void dumpRootElements(raw_ostream &OS, ArrayRef<RootElement> Elements) {
MDNode *MetadataBuilder::BuildRootSignature() {
for (const RootElement &Element : Elements) {
MDNode *ElementMD = nullptr;
+ if (const auto &Flags = std::get_if<RootFlags>(&Element))
+ ElementMD = BuildRootFlags(*Flags);
+ if (const auto &Constants = std::get_if<RootConstants>(&Element))
+ ElementMD = BuildRootConstants(*Constants);
+ if (const auto &Descriptor = std::get_if<RootDescriptor>(&Element))
+ ElementMD = BuildRootDescriptor(*Descriptor);
if (const auto &Clause = std::get_if<DescriptorTableClause>(&Element))
ElementMD = BuildDescriptorTableClause(*Clause);
if (const auto &Table = std::get_if<DescriptorTable>(&Element))
@@ -187,6 +193,46 @@ MDNode *MetadataBuilder::BuildRootSignature() {
return MDNode::get(Ctx, GeneratedMetadata);
}
+MDNode *MetadataBuilder::BuildRootFlags(const RootFlags &Flags) {
+ IRBuilder<> Builder(Ctx);
+ return MDNode::get(Ctx, {
+ MDString::get(Ctx, "RootFlags"),
+ ConstantAsMetadata::get(
+ Builder.getInt32(llvm::to_underlying(Flags))),
+ });
+}
+
+MDNode *MetadataBuilder::BuildRootConstants(const RootConstants &Constants) {
+ IRBuilder<> Builder(Ctx);
+ return MDNode::get(
+ Ctx, {
+ MDString::get(Ctx, "RootConstants"),
+ ConstantAsMetadata::get(
+ Builder.getInt32(llvm::to_underlying(Constants.Visibility))),
+ ConstantAsMetadata::get(Builder.getInt32(Constants.Reg.Number)),
+ ConstantAsMetadata::get(Builder.getInt32(Constants.Space)),
+ ConstantAsMetadata::get(Builder.getInt32(
+ Constants.Num32BitConstants)),
+ });
+}
+
+MDNode *MetadataBuilder::BuildRootDescriptor(const RootDescriptor &Descriptor) {
+ IRBuilder<> Builder(Ctx);
+ std::string Name;
+ llvm::raw_string_ostream OS(Name);
+ OS << "Root" << ClauseType(llvm::to_underlying(Descriptor.Type));
+ return MDNode::get(
+ Ctx, {
+ MDString::get(Ctx, OS.str()),
+ ConstantAsMetadata::get(
+ Builder.getInt32(llvm::to_underlying(Descriptor.Visibility))),
+ ConstantAsMetadata::get(Builder.getInt32(Descriptor.Reg.Number)),
+ ConstantAsMetadata::get(Builder.getInt32(Descriptor.Space)),
+ ConstantAsMetadata::get(
+ Builder.getInt32(llvm::to_underlying(Descriptor.Flags))),
+ });
+}
+
MDNode *MetadataBuilder::BuildDescriptorTable(const DescriptorTable &Table) {
IRBuilder<> Builder(Ctx);
SmallVector<Metadata *> TableOperands;
|
@llvm/pr-subscribers-clang Author: Finn Plummer (inbelic) ChangesImplements metadata generation of a Root Signature from its in-memory representation. This pr handles RootFlags, RootConstants and RootDescriptors. The metadata follows the format described here.
Note: there is no validation of metadata nodes as the First part of #126586. Full diff: https://github.com/llvm/llvm-project/pull/142010.diff 3 Files Affected:
diff --git a/clang/test/CodeGenHLSL/RootSignature.hlsl b/clang/test/CodeGenHLSL/RootSignature.hlsl
index 60e0dec175b8f..85f47727ce91f 100644
--- a/clang/test/CodeGenHLSL/RootSignature.hlsl
+++ b/clang/test/CodeGenHLSL/RootSignature.hlsl
@@ -1,16 +1,17 @@
// RUN: %clang_cc1 -triple dxil-pc-shadermodel6.3-library -emit-llvm -o - %s | FileCheck %s
-// CHECK: !dx.rootsignatures = !{![[#FIRST_ENTRY:]], ![[#SECOND_ENTRY:]]}
+// CHECK: !dx.rootsignatures = !{![[#EMPTY_ENTRY:]], ![[#DT_ENTRY:]],
+// CHECK-SAME: ![[#RF_ENTRY:]], ![[#RC_ENTRY:]], ![[#RD_ENTRY:]]}
-// CHECK: ![[#FIRST_ENTRY]] = !{ptr @FirstEntry, ![[#EMPTY:]]}
+// CHECK: ![[#EMPTY_ENTRY]] = !{ptr @EmptyEntry, ![[#EMPTY:]]}
// CHECK: ![[#EMPTY]] = !{}
[shader("compute"), RootSignature("")]
[numthreads(1,1,1)]
-void FirstEntry() {}
+void EmptyEntry() {}
-// CHECK: ![[#SECOND_ENTRY]] = !{ptr @SecondEntry, ![[#SECOND_RS:]]}
-// CHECK: ![[#SECOND_RS]] = !{![[#TABLE:]]}
+// CHECK: ![[#DT_ENTRY]] = !{ptr @DescriptorTableEntry, ![[#DT_RS:]]}
+// CHECK: ![[#DT_RS]] = !{![[#TABLE:]]}
// CHECK: ![[#TABLE]] = !{!"DescriptorTable", i32 0, ![[#CBV:]], ![[#SRV:]]}
// CHECK: ![[#CBV]] = !{!"CBV", i32 1, i32 0, i32 0, i32 -1, i32 4}
// CHECK: ![[#SRV]] = !{!"SRV", i32 4, i32 42, i32 3, i32 32, i32 0}
@@ -22,10 +23,51 @@ void FirstEntry() {}
")"
[shader("compute"), RootSignature(SampleDescriptorTable)]
[numthreads(1,1,1)]
-void SecondEntry() {}
+void DescriptorTableEntry() {}
+
+// CHECK: ![[#RF_ENTRY]] = !{ptr @RootFlagsEntry, ![[#RF_RS:]]}
+// CHECK: ![[#RF_RS]] = !{![[#ROOT_FLAGS:]]}
+// CHECK: ![[#ROOT_FLAGS]] = !{!"RootFlags", i32 2114}
+
+#define SampleRootFlags \
+ "RootFlags( " \
+ " Deny_Vertex_Shader_Root_Access | Allow_Stream_Output | " \
+ " sampler_heap_directly_indexed " \
+ ")"
+[shader("compute"), RootSignature(SampleRootFlags)]
+[numthreads(1,1,1)]
+void RootFlagsEntry() {}
+
+// CHECK: ![[#RC_ENTRY]] = !{ptr @RootConstantsEntry, ![[#RC_RS:]]}
+// CHECK: ![[#RC_RS]] = !{![[#ROOT_CONSTANTS:]]}
+// CHECK: ![[#ROOT_CONSTANTS]] = !{!"RootConstants", i32 5, i32 1, i32 2, i32 1}
+
+#define SampleRootConstants \
+ "RootConstants(" \
+ " space = 2, " \
+ " visibility = Shader_Visibility_Pixel, " \
+ " b1, num32BitConstants = 1 " \
+ ")"
+[shader("compute"), RootSignature(SampleRootConstants)]
+[numthreads(1,1,1)]
+void RootConstantsEntry() {}
+
+// CHECK: ![[#RD_ENTRY]] = !{ptr @RootDescriptorsEntry, ![[#RD_RS:]]}
+// CHECK: ![[#RD_RS]] = !{![[#ROOT_CBV:]], ![[#ROOT_UAV:]], ![[#ROOT_SRV:]]}
+// CHECK: ![[#ROOT_CBV]] = !{!"RootCBV", i32 0, i32 0, i32 0, i32 4}
+// CHECK: ![[#ROOT_UAV]] = !{!"RootUAV", i32 0, i32 0, i32 0, i32 2}
+// CHECK: ![[#ROOT_SRV]] = !{!"RootSRV", i32 0, i32 0, i32 0, i32 4}
+
+#define SampleRootDescriptors \
+ "CBV(b0), " \
+ "UAV(u0), " \
+ "SRV(t0)"
+[shader("compute"), RootSignature(SampleRootDescriptors)]
+[numthreads(1,1,1)]
+void RootDescriptorsEntry() {}
// Sanity test to ensure no root is added for this function as there is only
// two entries in !dx.roosignatures
[shader("compute")]
[numthreads(1,1,1)]
-void ThirdEntry() {}
+void NoRSEntry() {}
diff --git a/llvm/include/llvm/Frontend/HLSL/HLSLRootSignature.h b/llvm/include/llvm/Frontend/HLSL/HLSLRootSignature.h
index fd0abc9479469..d020dc413f0af 100644
--- a/llvm/include/llvm/Frontend/HLSL/HLSLRootSignature.h
+++ b/llvm/include/llvm/Frontend/HLSL/HLSLRootSignature.h
@@ -188,6 +188,9 @@ class MetadataBuilder {
private:
/// Define the various builders for the different metadata types
+ MDNode *BuildRootFlags(const RootFlags &Flags);
+ MDNode *BuildRootConstants(const RootConstants &Constants);
+ MDNode *BuildRootDescriptor(const RootDescriptor &Descriptor);
MDNode *BuildDescriptorTable(const DescriptorTable &Table);
MDNode *BuildDescriptorTableClause(const DescriptorTableClause &Clause);
diff --git a/llvm/lib/Frontend/HLSL/HLSLRootSignature.cpp b/llvm/lib/Frontend/HLSL/HLSLRootSignature.cpp
index ec0d130a6767c..cd606e61fcebf 100644
--- a/llvm/lib/Frontend/HLSL/HLSLRootSignature.cpp
+++ b/llvm/lib/Frontend/HLSL/HLSLRootSignature.cpp
@@ -171,6 +171,12 @@ void dumpRootElements(raw_ostream &OS, ArrayRef<RootElement> Elements) {
MDNode *MetadataBuilder::BuildRootSignature() {
for (const RootElement &Element : Elements) {
MDNode *ElementMD = nullptr;
+ if (const auto &Flags = std::get_if<RootFlags>(&Element))
+ ElementMD = BuildRootFlags(*Flags);
+ if (const auto &Constants = std::get_if<RootConstants>(&Element))
+ ElementMD = BuildRootConstants(*Constants);
+ if (const auto &Descriptor = std::get_if<RootDescriptor>(&Element))
+ ElementMD = BuildRootDescriptor(*Descriptor);
if (const auto &Clause = std::get_if<DescriptorTableClause>(&Element))
ElementMD = BuildDescriptorTableClause(*Clause);
if (const auto &Table = std::get_if<DescriptorTable>(&Element))
@@ -187,6 +193,46 @@ MDNode *MetadataBuilder::BuildRootSignature() {
return MDNode::get(Ctx, GeneratedMetadata);
}
+MDNode *MetadataBuilder::BuildRootFlags(const RootFlags &Flags) {
+ IRBuilder<> Builder(Ctx);
+ return MDNode::get(Ctx, {
+ MDString::get(Ctx, "RootFlags"),
+ ConstantAsMetadata::get(
+ Builder.getInt32(llvm::to_underlying(Flags))),
+ });
+}
+
+MDNode *MetadataBuilder::BuildRootConstants(const RootConstants &Constants) {
+ IRBuilder<> Builder(Ctx);
+ return MDNode::get(
+ Ctx, {
+ MDString::get(Ctx, "RootConstants"),
+ ConstantAsMetadata::get(
+ Builder.getInt32(llvm::to_underlying(Constants.Visibility))),
+ ConstantAsMetadata::get(Builder.getInt32(Constants.Reg.Number)),
+ ConstantAsMetadata::get(Builder.getInt32(Constants.Space)),
+ ConstantAsMetadata::get(Builder.getInt32(
+ Constants.Num32BitConstants)),
+ });
+}
+
+MDNode *MetadataBuilder::BuildRootDescriptor(const RootDescriptor &Descriptor) {
+ IRBuilder<> Builder(Ctx);
+ std::string Name;
+ llvm::raw_string_ostream OS(Name);
+ OS << "Root" << ClauseType(llvm::to_underlying(Descriptor.Type));
+ return MDNode::get(
+ Ctx, {
+ MDString::get(Ctx, OS.str()),
+ ConstantAsMetadata::get(
+ Builder.getInt32(llvm::to_underlying(Descriptor.Visibility))),
+ ConstantAsMetadata::get(Builder.getInt32(Descriptor.Reg.Number)),
+ ConstantAsMetadata::get(Builder.getInt32(Descriptor.Space)),
+ ConstantAsMetadata::get(
+ Builder.getInt32(llvm::to_underlying(Descriptor.Flags))),
+ });
+}
+
MDNode *MetadataBuilder::BuildDescriptorTable(const DescriptorTable &Table) {
IRBuilder<> Builder(Ctx);
SmallVector<Metadata *> TableOperands;
|
✅ With the latest revision this PR passed the C/C++ code formatter. |
std::string Name; | ||
llvm::raw_string_ostream OS(Name); | ||
OS << "Root" << ClauseType(llvm::to_underlying(Descriptor.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.
It'll be slightly more efficient to use SmallString<16>
and raw_svector_ostream
here to avoid a heap allocation. Also I find it a bit clearer to use Name
directly below instead of OS.str()
.
Note also that this does actually point out a bit of an inefficiency with how we've implemented only operator<<
for these simple enum stringifying functions. If we had a function like getClauseTypeName
returning static StringRef
for these we could avoid this work entirely, and the operator<<
could still exist for where it's useful and simply call this function in its implementation. It might be worth coming back to this in a follow up change.
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.
Sounds good. I have a note for a clean-up to do define the stringifying functions for the enums. Further, the pattern used here was propagated from descriptor tables, so I will update the other uses accordingly.
Implements metadata generation of a Root Signature from its in-memory representation. It follows the same style as: #139633.
This pr handles RootFlags, RootConstants and RootDescriptors.
The metadata follows the format described here.
BuildRoot[Flags|Constants|Descriptors]
intoHLSLRootSignature.h
Note: there is no validation of metadata nodes as the
llvm::hlsl::rootsig::RootElement
that generates it will have already been validated.First part of #126586.