[clang] [llvm] [HLSL][RootSignature] Metadata generation of RootFlags, RootConstants, RootDescriptors (PR #142010)

Finn Plummer via cfe-commits cfe-commits at lists.llvm.org
Thu May 29 11:40:45 PDT 2025


https://github.com/inbelic created https://github.com/llvm/llvm-project/pull/142010

Implements 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](https://github.com/llvm/wg-hlsl/blob/main/proposals/0002-root-signature-in-clang.md#metadata-schema). 

- Implement `BuildRoot[Flags|Constants|Descriptors]` into `HLSLRootSignature.h`
- Add sample testcases demonstrating functionality

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 https://github.com/llvm/llvm-project/issues/126586.

>From 34733d6f150360984a01b69ac22313f3bdf4b373 Mon Sep 17 00:00:00 2001
From: Finn Plummer <canadienfinn at gmail.com>
Date: Mon, 26 May 2025 21:51:36 +0000
Subject: [PATCH 1/4] nfc: rename matches

---
 clang/test/CodeGenHLSL/RootSignature.hlsl | 14 +++++++-------
 1 file changed, 7 insertions(+), 7 deletions(-)

diff --git a/clang/test/CodeGenHLSL/RootSignature.hlsl b/clang/test/CodeGenHLSL/RootSignature.hlsl
index 60e0dec175b8f..9a2c7ac7bdf9d 100644
--- a/clang/test/CodeGenHLSL/RootSignature.hlsl
+++ b/clang/test/CodeGenHLSL/RootSignature.hlsl
@@ -1,16 +1,16 @@
 // 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: ![[#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 +22,10 @@ void FirstEntry() {}
   ")"
 [shader("compute"), RootSignature(SampleDescriptorTable)]
 [numthreads(1,1,1)]
-void SecondEntry() {}
+void DescriptorTableEntry() {}
 
 // 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() {}

>From 2ee3b108781e42b1fef80f0d0150b55becfcc5b4 Mon Sep 17 00:00:00 2001
From: Finn Plummer <canadienfinn at gmail.com>
Date: Thu, 29 May 2025 18:31:35 +0000
Subject: [PATCH 2/4] [HLSL][RootSignature] RootFlags metadata generation

---
 clang/test/CodeGenHLSL/RootSignature.hlsl        | 16 +++++++++++++++-
 .../llvm/Frontend/HLSL/HLSLRootSignature.h       |  1 +
 llvm/lib/Frontend/HLSL/HLSLRootSignature.cpp     | 11 +++++++++++
 3 files changed, 27 insertions(+), 1 deletion(-)

diff --git a/clang/test/CodeGenHLSL/RootSignature.hlsl b/clang/test/CodeGenHLSL/RootSignature.hlsl
index 9a2c7ac7bdf9d..b519b0d1ea7b7 100644
--- a/clang/test/CodeGenHLSL/RootSignature.hlsl
+++ b/clang/test/CodeGenHLSL/RootSignature.hlsl
@@ -1,6 +1,7 @@
 // RUN: %clang_cc1 -triple dxil-pc-shadermodel6.3-library -emit-llvm -o - %s | FileCheck %s
 
-// CHECK: !dx.rootsignatures = !{![[#EMPTY_ENTRY:]], ![[#DT_ENTRY:]]}
+// CHECK: !dx.rootsignatures = !{![[#EMPTY_ENTRY:]], ![[#DT_ENTRY:]],
+// CHECK-SAME: ![[#RF_ENTRY:]]}
 
 // CHECK: ![[#EMPTY_ENTRY]] = !{ptr @EmptyEntry, ![[#EMPTY:]]}
 // CHECK: ![[#EMPTY]] = !{}
@@ -24,6 +25,19 @@ void EmptyEntry() {}
 [numthreads(1,1,1)]
 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() {}
+
 // Sanity test to ensure no root is added for this function as there is only
 // two entries in !dx.roosignatures
 [shader("compute")]
diff --git a/llvm/include/llvm/Frontend/HLSL/HLSLRootSignature.h b/llvm/include/llvm/Frontend/HLSL/HLSLRootSignature.h
index fd0abc9479469..5a121d2d3f887 100644
--- a/llvm/include/llvm/Frontend/HLSL/HLSLRootSignature.h
+++ b/llvm/include/llvm/Frontend/HLSL/HLSLRootSignature.h
@@ -188,6 +188,7 @@ class MetadataBuilder {
 
 private:
   /// Define the various builders for the different metadata types
+  MDNode *BuildRootFlags(const RootFlags &Flags);
   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..a24c27e0e2efe 100644
--- a/llvm/lib/Frontend/HLSL/HLSLRootSignature.cpp
+++ b/llvm/lib/Frontend/HLSL/HLSLRootSignature.cpp
@@ -171,6 +171,8 @@ 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 &Clause = std::get_if<DescriptorTableClause>(&Element))
       ElementMD = BuildDescriptorTableClause(*Clause);
     if (const auto &Table = std::get_if<DescriptorTable>(&Element))
@@ -187,6 +189,15 @@ 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::BuildDescriptorTable(const DescriptorTable &Table) {
   IRBuilder<> Builder(Ctx);
   SmallVector<Metadata *> TableOperands;

>From 33b5b05ce1e186440944414f68db566c4b6452c9 Mon Sep 17 00:00:00 2001
From: Finn Plummer <canadienfinn at gmail.com>
Date: Thu, 29 May 2025 18:32:43 +0000
Subject: [PATCH 3/4] [HLSL][RootSignature] RootConstants metadata generation

---
 clang/test/CodeGenHLSL/RootSignature.hlsl        | 16 +++++++++++++++-
 .../llvm/Frontend/HLSL/HLSLRootSignature.h       |  1 +
 llvm/lib/Frontend/HLSL/HLSLRootSignature.cpp     | 16 ++++++++++++++++
 3 files changed, 32 insertions(+), 1 deletion(-)

diff --git a/clang/test/CodeGenHLSL/RootSignature.hlsl b/clang/test/CodeGenHLSL/RootSignature.hlsl
index b519b0d1ea7b7..411711752f4e6 100644
--- a/clang/test/CodeGenHLSL/RootSignature.hlsl
+++ b/clang/test/CodeGenHLSL/RootSignature.hlsl
@@ -1,7 +1,7 @@
 // RUN: %clang_cc1 -triple dxil-pc-shadermodel6.3-library -emit-llvm -o - %s | FileCheck %s
 
 // CHECK: !dx.rootsignatures = !{![[#EMPTY_ENTRY:]], ![[#DT_ENTRY:]],
-// CHECK-SAME: ![[#RF_ENTRY:]]}
+// CHECK-SAME: ![[#RF_ENTRY:]], ![[#RC_ENTRY:]]}
 
 // CHECK: ![[#EMPTY_ENTRY]] = !{ptr @EmptyEntry, ![[#EMPTY:]]}
 // CHECK: ![[#EMPTY]] = !{}
@@ -38,6 +38,20 @@ void DescriptorTableEntry() {}
 [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() {}
+
 // Sanity test to ensure no root is added for this function as there is only
 // two entries in !dx.roosignatures
 [shader("compute")]
diff --git a/llvm/include/llvm/Frontend/HLSL/HLSLRootSignature.h b/llvm/include/llvm/Frontend/HLSL/HLSLRootSignature.h
index 5a121d2d3f887..306ad6cb26a7d 100644
--- a/llvm/include/llvm/Frontend/HLSL/HLSLRootSignature.h
+++ b/llvm/include/llvm/Frontend/HLSL/HLSLRootSignature.h
@@ -189,6 +189,7 @@ class MetadataBuilder {
 private:
   /// Define the various builders for the different metadata types
   MDNode *BuildRootFlags(const RootFlags &Flags);
+  MDNode *BuildRootConstants(const RootConstants &Constants);
   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 a24c27e0e2efe..ea61d14902023 100644
--- a/llvm/lib/Frontend/HLSL/HLSLRootSignature.cpp
+++ b/llvm/lib/Frontend/HLSL/HLSLRootSignature.cpp
@@ -173,6 +173,8 @@ MDNode *MetadataBuilder::BuildRootSignature() {
     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 &Clause = std::get_if<DescriptorTableClause>(&Element))
       ElementMD = BuildDescriptorTableClause(*Clause);
     if (const auto &Table = std::get_if<DescriptorTable>(&Element))
@@ -198,6 +200,20 @@ MDNode *MetadataBuilder::BuildRootFlags(const RootFlags &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::BuildDescriptorTable(const DescriptorTable &Table) {
   IRBuilder<> Builder(Ctx);
   SmallVector<Metadata *> TableOperands;

>From 5875d8dec08d499f0f81f6351e950991dfcc508e Mon Sep 17 00:00:00 2001
From: Finn Plummer <canadienfinn at gmail.com>
Date: Thu, 29 May 2025 18:33:08 +0000
Subject: [PATCH 4/4] [HLSL][RootSignature] DescriptorTable metadata generation

---
 clang/test/CodeGenHLSL/RootSignature.hlsl     | 16 +++++++++++++++-
 .../llvm/Frontend/HLSL/HLSLRootSignature.h    |  1 +
 llvm/lib/Frontend/HLSL/HLSLRootSignature.cpp  | 19 +++++++++++++++++++
 3 files changed, 35 insertions(+), 1 deletion(-)

diff --git a/clang/test/CodeGenHLSL/RootSignature.hlsl b/clang/test/CodeGenHLSL/RootSignature.hlsl
index 411711752f4e6..85f47727ce91f 100644
--- a/clang/test/CodeGenHLSL/RootSignature.hlsl
+++ b/clang/test/CodeGenHLSL/RootSignature.hlsl
@@ -1,7 +1,7 @@
 // RUN: %clang_cc1 -triple dxil-pc-shadermodel6.3-library -emit-llvm -o - %s | FileCheck %s
 
 // CHECK: !dx.rootsignatures = !{![[#EMPTY_ENTRY:]], ![[#DT_ENTRY:]],
-// CHECK-SAME: ![[#RF_ENTRY:]], ![[#RC_ENTRY:]]}
+// CHECK-SAME: ![[#RF_ENTRY:]], ![[#RC_ENTRY:]], ![[#RD_ENTRY:]]}
 
 // CHECK: ![[#EMPTY_ENTRY]] = !{ptr @EmptyEntry, ![[#EMPTY:]]}
 // CHECK: ![[#EMPTY]] = !{}
@@ -52,6 +52,20 @@ void RootFlagsEntry() {}
 [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")]
diff --git a/llvm/include/llvm/Frontend/HLSL/HLSLRootSignature.h b/llvm/include/llvm/Frontend/HLSL/HLSLRootSignature.h
index 306ad6cb26a7d..d020dc413f0af 100644
--- a/llvm/include/llvm/Frontend/HLSL/HLSLRootSignature.h
+++ b/llvm/include/llvm/Frontend/HLSL/HLSLRootSignature.h
@@ -190,6 +190,7 @@ class MetadataBuilder {
   /// 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 ea61d14902023..cd606e61fcebf 100644
--- a/llvm/lib/Frontend/HLSL/HLSLRootSignature.cpp
+++ b/llvm/lib/Frontend/HLSL/HLSLRootSignature.cpp
@@ -175,6 +175,8 @@ MDNode *MetadataBuilder::BuildRootSignature() {
       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))
@@ -214,6 +216,23 @@ MDNode *MetadataBuilder::BuildRootConstants(const RootConstants &Constants) {
            });
 }
 
+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;



More information about the cfe-commits mailing list