Skip to content

[HLSL][RootSignature] Add parsing for empty RootConstants #137999

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

Open
wants to merge 4 commits into
base: main
Choose a base branch
from

Conversation

inbelic
Copy link
Contributor

@inbelic inbelic commented Apr 30, 2025

  • defines the empty RootConstants in-memory struct

  • adds test harness for testing it

  • adds missing parameter keywords to the lexer (RootConstants, num32BitConstants)

First part of implementing: #126576

@llvmbot llvmbot added clang Clang issues not falling into any other category clang:frontend Language frontend issues, e.g. anything involving "Sema" HLSL HLSL Language Support labels Apr 30, 2025
@llvmbot
Copy link
Member

llvmbot commented Apr 30, 2025

@llvm/pr-subscribers-clang

Author: Finn Plummer (inbelic)

Changes
  • defines the empty RootConstants in-memory struct

  • adds test harness for testing it

  • adds missing parameter keywords to the lexer (RootConstants, num32BitConstants)

First part of implementing: #126576


Full diff: https://github.com/llvm/llvm-project/pull/137999.diff

6 Files Affected:

  • (modified) clang/include/clang/Lex/HLSLRootSignatureTokenKinds.def (+4)
  • (modified) clang/include/clang/Parse/ParseHLSLRootSignature.h (+1)
  • (modified) clang/lib/Parse/ParseHLSLRootSignature.cpp (+26-4)
  • (modified) clang/unittests/Lex/LexHLSLRootSignatureTest.cpp (+3-1)
  • (modified) clang/unittests/Parse/ParseHLSLRootSignatureTest.cpp (+26)
  • (modified) llvm/include/llvm/Frontend/HLSL/HLSLRootSignature.h (+6-2)
diff --git a/clang/include/clang/Lex/HLSLRootSignatureTokenKinds.def b/clang/include/clang/Lex/HLSLRootSignatureTokenKinds.def
index d94be66b420c7..ecb8cfc7afa16 100644
--- a/clang/include/clang/Lex/HLSLRootSignatureTokenKinds.def
+++ b/clang/include/clang/Lex/HLSLRootSignatureTokenKinds.def
@@ -74,6 +74,10 @@ PUNCTUATOR(minus,   '-')
 // RootElement Keywords:
 KEYWORD(RootSignature) // used only for diagnostic messaging
 KEYWORD(DescriptorTable)
+KEYWORD(RootConstants)
+
+// RootConstants Keywords:
+KEYWORD(num32BitConstants)
 
 // DescriptorTable Keywords:
 KEYWORD(CBV)
diff --git a/clang/include/clang/Parse/ParseHLSLRootSignature.h b/clang/include/clang/Parse/ParseHLSLRootSignature.h
index 91640e8bf0354..efa735ea03d94 100644
--- a/clang/include/clang/Parse/ParseHLSLRootSignature.h
+++ b/clang/include/clang/Parse/ParseHLSLRootSignature.h
@@ -71,6 +71,7 @@ class RootSignatureParser {
   // expected, or, there is a lexing error
 
   /// Root Element parse methods:
+  std::optional<llvm::hlsl::rootsig::RootConstants> parseRootConstants();
   std::optional<llvm::hlsl::rootsig::DescriptorTable> parseDescriptorTable();
   std::optional<llvm::hlsl::rootsig::DescriptorTableClause>
   parseDescriptorTableClause();
diff --git a/clang/lib/Parse/ParseHLSLRootSignature.cpp b/clang/lib/Parse/ParseHLSLRootSignature.cpp
index 042aedbf1af52..f9e672850012b 100644
--- a/clang/lib/Parse/ParseHLSLRootSignature.cpp
+++ b/clang/lib/Parse/ParseHLSLRootSignature.cpp
@@ -27,6 +27,13 @@ RootSignatureParser::RootSignatureParser(SmallVector<RootElement> &Elements,
 bool RootSignatureParser::parse() {
   // Iterate as many RootElements as possible
   do {
+    if (tryConsumeExpectedToken(TokenKind::kw_RootConstants)) {
+      auto Constants = parseRootConstants();
+      if (!Constants.has_value())
+        return true;
+      Elements.push_back(*Constants);
+    }
+
     if (tryConsumeExpectedToken(TokenKind::kw_DescriptorTable)) {
       auto Table = parseDescriptorTable();
       if (!Table.has_value())
@@ -35,12 +42,27 @@ bool RootSignatureParser::parse() {
     }
   } while (tryConsumeExpectedToken(TokenKind::pu_comma));
 
-  if (consumeExpectedToken(TokenKind::end_of_stream,
+  return consumeExpectedToken(TokenKind::end_of_stream,
+                              diag::err_hlsl_unexpected_end_of_params,
+                              /*param of=*/TokenKind::kw_RootSignature));
+}
+
+std::optional<RootConstants> RootSignatureParser::parseRootConstants() {
+  assert(CurToken.TokKind == TokenKind::kw_RootConstants &&
+         "Expects to only be invoked starting at given keyword");
+
+  if (consumeExpectedToken(TokenKind::pu_l_paren, diag::err_expected_after,
+                           CurToken.TokKind))
+    return std::nullopt;
+
+  RootConstants Constants;
+
+  if (consumeExpectedToken(TokenKind::pu_r_paren,
                            diag::err_hlsl_unexpected_end_of_params,
-                           /*param of=*/TokenKind::kw_RootSignature))
-    return true;
+                           /*param of=*/TokenKind::kw_RootConstants))
+    return std::nullopt;
 
-  return false;
+  return Constants;
 }
 
 std::optional<DescriptorTable> RootSignatureParser::parseDescriptorTable() {
diff --git a/clang/unittests/Lex/LexHLSLRootSignatureTest.cpp b/clang/unittests/Lex/LexHLSLRootSignatureTest.cpp
index 2024ff3a7dba9..89e9a3183ad03 100644
--- a/clang/unittests/Lex/LexHLSLRootSignatureTest.cpp
+++ b/clang/unittests/Lex/LexHLSLRootSignatureTest.cpp
@@ -87,7 +87,9 @@ TEST_F(LexHLSLRootSignatureTest, ValidLexAllTokensTest) {
 
     RootSignature
 
-    DescriptorTable
+    DescriptorTable RootConstants
+
+    num32BitConstants
 
     CBV SRV UAV Sampler
     space visibility flags
diff --git a/clang/unittests/Parse/ParseHLSLRootSignatureTest.cpp b/clang/unittests/Parse/ParseHLSLRootSignatureTest.cpp
index 585ac051d66a2..0a7d8ac86cc5f 100644
--- a/clang/unittests/Parse/ParseHLSLRootSignatureTest.cpp
+++ b/clang/unittests/Parse/ParseHLSLRootSignatureTest.cpp
@@ -252,6 +252,32 @@ TEST_F(ParseHLSLRootSignatureTest, ValidSamplerFlagsTest) {
   ASSERT_TRUE(Consumer->isSatisfied());
 }
 
+TEST_F(ParseHLSLRootSignatureTest, ValidParseRootConsantsTest) {
+  const llvm::StringLiteral Source = R"cc(
+    RootConstants()
+  )cc";
+
+  TrivialModuleLoader ModLoader;
+  auto PP = createPP(Source, ModLoader);
+  auto TokLoc = SourceLocation();
+
+  hlsl::RootSignatureLexer Lexer(Source, TokLoc);
+  SmallVector<RootElement> Elements;
+  hlsl::RootSignatureParser Parser(Elements, Lexer, *PP);
+
+  // Test no diagnostics produced
+  Consumer->setNoDiag();
+
+  ASSERT_FALSE(Parser.parse());
+
+  ASSERT_EQ(Elements.size(), 1u);
+
+  RootElement Elem = Elements[0];
+  ASSERT_TRUE(std::holds_alternative<RootConstants>(Elem));
+
+  ASSERT_TRUE(Consumer->isSatisfied());
+}
+
 TEST_F(ParseHLSLRootSignatureTest, ValidTrailingCommaTest) {
   // This test will checks we can handling trailing commas ','
   const llvm::StringLiteral Source = R"cc(
diff --git a/llvm/include/llvm/Frontend/HLSL/HLSLRootSignature.h b/llvm/include/llvm/Frontend/HLSL/HLSLRootSignature.h
index 818caccfe1998..05735fa75b318 100644
--- a/llvm/include/llvm/Frontend/HLSL/HLSLRootSignature.h
+++ b/llvm/include/llvm/Frontend/HLSL/HLSLRootSignature.h
@@ -54,6 +54,9 @@ struct Register {
   uint32_t Number;
 };
 
+// Models the parameter values of root constants
+struct RootConstants {};
+
 // Models the end of a descriptor table and stores its visibility
 struct DescriptorTable {
   ShaderVisibility Visibility = ShaderVisibility::All;
@@ -88,8 +91,9 @@ struct DescriptorTableClause {
   }
 };
 
-// Models RootElement : DescriptorTable | DescriptorTableClause
-using RootElement = std::variant<DescriptorTable, DescriptorTableClause>;
+// Models RootElement : RootConstants | DescriptorTable | DescriptorTableClause
+using RootElement =
+    std::variant<RootConstants, DescriptorTable, DescriptorTableClause>;
 
 } // namespace rootsig
 } // namespace hlsl

@llvmbot
Copy link
Member

llvmbot commented Apr 30, 2025

@llvm/pr-subscribers-hlsl

Author: Finn Plummer (inbelic)

Changes
  • defines the empty RootConstants in-memory struct

  • adds test harness for testing it

  • adds missing parameter keywords to the lexer (RootConstants, num32BitConstants)

First part of implementing: #126576


Full diff: https://github.com/llvm/llvm-project/pull/137999.diff

6 Files Affected:

  • (modified) clang/include/clang/Lex/HLSLRootSignatureTokenKinds.def (+4)
  • (modified) clang/include/clang/Parse/ParseHLSLRootSignature.h (+1)
  • (modified) clang/lib/Parse/ParseHLSLRootSignature.cpp (+26-4)
  • (modified) clang/unittests/Lex/LexHLSLRootSignatureTest.cpp (+3-1)
  • (modified) clang/unittests/Parse/ParseHLSLRootSignatureTest.cpp (+26)
  • (modified) llvm/include/llvm/Frontend/HLSL/HLSLRootSignature.h (+6-2)
diff --git a/clang/include/clang/Lex/HLSLRootSignatureTokenKinds.def b/clang/include/clang/Lex/HLSLRootSignatureTokenKinds.def
index d94be66b420c7..ecb8cfc7afa16 100644
--- a/clang/include/clang/Lex/HLSLRootSignatureTokenKinds.def
+++ b/clang/include/clang/Lex/HLSLRootSignatureTokenKinds.def
@@ -74,6 +74,10 @@ PUNCTUATOR(minus,   '-')
 // RootElement Keywords:
 KEYWORD(RootSignature) // used only for diagnostic messaging
 KEYWORD(DescriptorTable)
+KEYWORD(RootConstants)
+
+// RootConstants Keywords:
+KEYWORD(num32BitConstants)
 
 // DescriptorTable Keywords:
 KEYWORD(CBV)
diff --git a/clang/include/clang/Parse/ParseHLSLRootSignature.h b/clang/include/clang/Parse/ParseHLSLRootSignature.h
index 91640e8bf0354..efa735ea03d94 100644
--- a/clang/include/clang/Parse/ParseHLSLRootSignature.h
+++ b/clang/include/clang/Parse/ParseHLSLRootSignature.h
@@ -71,6 +71,7 @@ class RootSignatureParser {
   // expected, or, there is a lexing error
 
   /// Root Element parse methods:
+  std::optional<llvm::hlsl::rootsig::RootConstants> parseRootConstants();
   std::optional<llvm::hlsl::rootsig::DescriptorTable> parseDescriptorTable();
   std::optional<llvm::hlsl::rootsig::DescriptorTableClause>
   parseDescriptorTableClause();
diff --git a/clang/lib/Parse/ParseHLSLRootSignature.cpp b/clang/lib/Parse/ParseHLSLRootSignature.cpp
index 042aedbf1af52..f9e672850012b 100644
--- a/clang/lib/Parse/ParseHLSLRootSignature.cpp
+++ b/clang/lib/Parse/ParseHLSLRootSignature.cpp
@@ -27,6 +27,13 @@ RootSignatureParser::RootSignatureParser(SmallVector<RootElement> &Elements,
 bool RootSignatureParser::parse() {
   // Iterate as many RootElements as possible
   do {
+    if (tryConsumeExpectedToken(TokenKind::kw_RootConstants)) {
+      auto Constants = parseRootConstants();
+      if (!Constants.has_value())
+        return true;
+      Elements.push_back(*Constants);
+    }
+
     if (tryConsumeExpectedToken(TokenKind::kw_DescriptorTable)) {
       auto Table = parseDescriptorTable();
       if (!Table.has_value())
@@ -35,12 +42,27 @@ bool RootSignatureParser::parse() {
     }
   } while (tryConsumeExpectedToken(TokenKind::pu_comma));
 
-  if (consumeExpectedToken(TokenKind::end_of_stream,
+  return consumeExpectedToken(TokenKind::end_of_stream,
+                              diag::err_hlsl_unexpected_end_of_params,
+                              /*param of=*/TokenKind::kw_RootSignature));
+}
+
+std::optional<RootConstants> RootSignatureParser::parseRootConstants() {
+  assert(CurToken.TokKind == TokenKind::kw_RootConstants &&
+         "Expects to only be invoked starting at given keyword");
+
+  if (consumeExpectedToken(TokenKind::pu_l_paren, diag::err_expected_after,
+                           CurToken.TokKind))
+    return std::nullopt;
+
+  RootConstants Constants;
+
+  if (consumeExpectedToken(TokenKind::pu_r_paren,
                            diag::err_hlsl_unexpected_end_of_params,
-                           /*param of=*/TokenKind::kw_RootSignature))
-    return true;
+                           /*param of=*/TokenKind::kw_RootConstants))
+    return std::nullopt;
 
-  return false;
+  return Constants;
 }
 
 std::optional<DescriptorTable> RootSignatureParser::parseDescriptorTable() {
diff --git a/clang/unittests/Lex/LexHLSLRootSignatureTest.cpp b/clang/unittests/Lex/LexHLSLRootSignatureTest.cpp
index 2024ff3a7dba9..89e9a3183ad03 100644
--- a/clang/unittests/Lex/LexHLSLRootSignatureTest.cpp
+++ b/clang/unittests/Lex/LexHLSLRootSignatureTest.cpp
@@ -87,7 +87,9 @@ TEST_F(LexHLSLRootSignatureTest, ValidLexAllTokensTest) {
 
     RootSignature
 
-    DescriptorTable
+    DescriptorTable RootConstants
+
+    num32BitConstants
 
     CBV SRV UAV Sampler
     space visibility flags
diff --git a/clang/unittests/Parse/ParseHLSLRootSignatureTest.cpp b/clang/unittests/Parse/ParseHLSLRootSignatureTest.cpp
index 585ac051d66a2..0a7d8ac86cc5f 100644
--- a/clang/unittests/Parse/ParseHLSLRootSignatureTest.cpp
+++ b/clang/unittests/Parse/ParseHLSLRootSignatureTest.cpp
@@ -252,6 +252,32 @@ TEST_F(ParseHLSLRootSignatureTest, ValidSamplerFlagsTest) {
   ASSERT_TRUE(Consumer->isSatisfied());
 }
 
+TEST_F(ParseHLSLRootSignatureTest, ValidParseRootConsantsTest) {
+  const llvm::StringLiteral Source = R"cc(
+    RootConstants()
+  )cc";
+
+  TrivialModuleLoader ModLoader;
+  auto PP = createPP(Source, ModLoader);
+  auto TokLoc = SourceLocation();
+
+  hlsl::RootSignatureLexer Lexer(Source, TokLoc);
+  SmallVector<RootElement> Elements;
+  hlsl::RootSignatureParser Parser(Elements, Lexer, *PP);
+
+  // Test no diagnostics produced
+  Consumer->setNoDiag();
+
+  ASSERT_FALSE(Parser.parse());
+
+  ASSERT_EQ(Elements.size(), 1u);
+
+  RootElement Elem = Elements[0];
+  ASSERT_TRUE(std::holds_alternative<RootConstants>(Elem));
+
+  ASSERT_TRUE(Consumer->isSatisfied());
+}
+
 TEST_F(ParseHLSLRootSignatureTest, ValidTrailingCommaTest) {
   // This test will checks we can handling trailing commas ','
   const llvm::StringLiteral Source = R"cc(
diff --git a/llvm/include/llvm/Frontend/HLSL/HLSLRootSignature.h b/llvm/include/llvm/Frontend/HLSL/HLSLRootSignature.h
index 818caccfe1998..05735fa75b318 100644
--- a/llvm/include/llvm/Frontend/HLSL/HLSLRootSignature.h
+++ b/llvm/include/llvm/Frontend/HLSL/HLSLRootSignature.h
@@ -54,6 +54,9 @@ struct Register {
   uint32_t Number;
 };
 
+// Models the parameter values of root constants
+struct RootConstants {};
+
 // Models the end of a descriptor table and stores its visibility
 struct DescriptorTable {
   ShaderVisibility Visibility = ShaderVisibility::All;
@@ -88,8 +91,9 @@ struct DescriptorTableClause {
   }
 };
 
-// Models RootElement : DescriptorTable | DescriptorTableClause
-using RootElement = std::variant<DescriptorTable, DescriptorTableClause>;
+// Models RootElement : RootConstants | DescriptorTable | DescriptorTableClause
+using RootElement =
+    std::variant<RootConstants, DescriptorTable, DescriptorTableClause>;
 
 } // namespace rootsig
 } // namespace hlsl

Copy link
Contributor

@joaosaffran joaosaffran left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM, just a typo and a nit

@@ -252,6 +252,32 @@ TEST_F(ParseHLSLRootSignatureTest, ValidSamplerFlagsTest) {
ASSERT_TRUE(Consumer->isSatisfied());
}

TEST_F(ParseHLSLRootSignatureTest, ValidParseRootConsantsTest) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
TEST_F(ParseHLSLRootSignatureTest, ValidParseRootConsantsTest) {
TEST_F(ParseHLSLRootSignatureTest, ValidParseRootConstantsTest) {

nit: Also, shouldn't this be, ValidParseEmptyRootConstantsTest, then we add more tests later on ?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Once we add the mandatory parameters then having an empty RootConstants is no longer valid, so the idea is that we can merge them into one

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
clang:frontend Language frontend issues, e.g. anything involving "Sema" clang Clang issues not falling into any other category HLSL HLSL Language Support
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants