https://github.com/inbelic updated 
https://github.com/llvm/llvm-project/pull/122982

>From 9fe6b897b161f7e40e4a5662ab2cad4dceed174e Mon Sep 17 00:00:00 2001
From: Finn Plummer <canadienf...@gmail.com>
Date: Thu, 13 Feb 2025 22:56:52 +0000
Subject: [PATCH 01/15] [HLSL][RootSignature] Parse empty Descriptor Table Root
 Element

- defines the Parser class and an initial set of helper methods to
support consuming tokens. functionality is demonstrated through a simple
empty descriptor table test case
- defines an initial in-memory representation of a DescriptorTable
- implements a test harness that will be used to validate the correct
diagnostics are generated. it will construct a dummy pre-processor with
diagnostics consumer to do so
---
 .../clang/Basic/DiagnosticParseKinds.td       |   2 +
 .../clang/Parse/ParseHLSLRootSignature.h      |  69 ++++++
 clang/lib/Parse/CMakeLists.txt                |   1 +
 clang/lib/Parse/ParseHLSLRootSignature.cpp    | 138 +++++++++++
 clang/unittests/CMakeLists.txt                |   1 +
 clang/unittests/Parse/CMakeLists.txt          |  23 ++
 .../Parse/ParseHLSLRootSignatureTest.cpp      | 217 ++++++++++++++++++
 .../llvm/Frontend/HLSL/HLSLRootSignature.h    |  37 +++
 8 files changed, 488 insertions(+)
 create mode 100644 clang/include/clang/Parse/ParseHLSLRootSignature.h
 create mode 100644 clang/lib/Parse/ParseHLSLRootSignature.cpp
 create mode 100644 clang/unittests/Parse/CMakeLists.txt
 create mode 100644 clang/unittests/Parse/ParseHLSLRootSignatureTest.cpp
 create mode 100644 llvm/include/llvm/Frontend/HLSL/HLSLRootSignature.h

diff --git a/clang/include/clang/Basic/DiagnosticParseKinds.td 
b/clang/include/clang/Basic/DiagnosticParseKinds.td
index c513dab810d1f..4c6adab80e60e 100644
--- a/clang/include/clang/Basic/DiagnosticParseKinds.td
+++ b/clang/include/clang/Basic/DiagnosticParseKinds.td
@@ -1818,4 +1818,6 @@ def ext_hlsl_access_specifiers : ExtWarn<
 def err_hlsl_unsupported_component : Error<"invalid component '%0' used; 
expected 'x', 'y', 'z', or 'w'">;
 def err_hlsl_packoffset_invalid_reg : Error<"invalid resource class specifier 
'%0' for packoffset, expected 'c'">;
 
+// HLSL Root Signature Parser Diagnostics
+def err_hlsl_rootsig_unexpected_token_kind : Error<"got %1 but expected 
%select{|one of}0 the following token kind%select{|s}0: %2">;
 } // end of Parser diagnostics
diff --git a/clang/include/clang/Parse/ParseHLSLRootSignature.h 
b/clang/include/clang/Parse/ParseHLSLRootSignature.h
new file mode 100644
index 0000000000000..fa46bdd663a2c
--- /dev/null
+++ b/clang/include/clang/Parse/ParseHLSLRootSignature.h
@@ -0,0 +1,69 @@
+//===--- ParseHLSLRootSignature.h -------------------------------*- C++ 
-*-===//
+//
+// 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
+//
+//===----------------------------------------------------------------------===//
+//
+//  This file defines the ParseHLSLRootSignature interface.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_PARSE_PARSEHLSLROOTSIGNATURE_H
+#define LLVM_CLANG_PARSE_PARSEHLSLROOTSIGNATURE_H
+
+#include "clang/Basic/DiagnosticParse.h"
+#include "clang/Lex/Preprocessor.h"
+#include "clang/Lex/LexHLSLRootSignature.h"
+
+#include "llvm/ADT/SmallVector.h"
+#include "llvm/ADT/StringRef.h"
+
+#include "llvm/Frontend/HLSL/HLSLRootSignature.h"
+
+namespace clang {
+namespace hlsl {
+
+class RootSignatureParser {
+public:
+  RootSignatureParser(SmallVector<llvm::hlsl::rootsig::RootElement> &Elements,
+                      RootSignatureLexer &Lexer, clang::Preprocessor &PP);
+
+  /// Consumes tokens from the Lexer and constructs the in-memory
+  /// representations of the RootElements. Tokens are consumed until an
+  /// error is encountered or the end of the buffer.
+  ///
+  /// Returns true if a parsing error is encountered.
+  bool Parse();
+
+  DiagnosticsEngine &Diags() { return PP.getDiagnostics(); }
+
+private:
+  // Root Element helpers
+  bool ParseRootElement();
+  bool ParseDescriptorTable();
+
+  /// Invoke the Lexer to consume a token and update CurToken with the result
+  void ConsumeNextToken() { CurToken = Lexer.ConsumeToken(); }
+
+  /// Consumes the next token and report an error if it is not of the expected
+  /// kind.
+  ///
+  /// Returns true if there was an error reported.
+  bool ConsumeExpectedToken(TokenKind Expected);
+  bool ConsumeExpectedToken(ArrayRef<TokenKind> AnyExpected);
+
+private:
+  SmallVector<llvm::hlsl::rootsig::RootElement> &Elements;
+  RootSignatureLexer &Lexer;
+
+  clang::Preprocessor &PP;
+
+  RootSignatureToken CurToken;
+};
+
+} // namespace hlsl
+} // namespace clang
+
+#endif // LLVM_CLANG_PARSE_PARSEHLSLROOTSIGNATURE_H
diff --git a/clang/lib/Parse/CMakeLists.txt b/clang/lib/Parse/CMakeLists.txt
index 22e902f7e1bc5..00fde537bb9c6 100644
--- a/clang/lib/Parse/CMakeLists.txt
+++ b/clang/lib/Parse/CMakeLists.txt
@@ -14,6 +14,7 @@ add_clang_library(clangParse
   ParseExpr.cpp
   ParseExprCXX.cpp
   ParseHLSL.cpp
+  ParseHLSLRootSignature.cpp
   ParseInit.cpp
   ParseObjc.cpp
   ParseOpenMP.cpp
diff --git a/clang/lib/Parse/ParseHLSLRootSignature.cpp 
b/clang/lib/Parse/ParseHLSLRootSignature.cpp
new file mode 100644
index 0000000000000..aeb33ded4d815
--- /dev/null
+++ b/clang/lib/Parse/ParseHLSLRootSignature.cpp
@@ -0,0 +1,138 @@
+#include "clang/Parse/ParseHLSLRootSignature.h"
+
+#include "llvm/Support/raw_ostream.h"
+
+using namespace llvm::hlsl::rootsig;
+
+namespace clang {
+namespace hlsl {
+
+static std::string FormatTokenKinds(ArrayRef<TokenKind> Kinds) {
+  std::string TokenString;
+  llvm::raw_string_ostream Out(TokenString);
+  bool First = true;
+  for (auto Kind : Kinds) {
+    if (!First)
+      Out << ", ";
+    switch (Kind) {
+    case TokenKind::invalid:
+      Out << "invalid identifier";
+      break;
+    case TokenKind::end_of_stream:
+      Out << "end of stream";
+      break;
+    case TokenKind::int_literal:
+      Out << "integer literal";
+      break;
+    case TokenKind::bReg:
+      Out << "b register";
+      break;
+    case TokenKind::tReg:
+      Out << "t register";
+      break;
+    case TokenKind::uReg:
+      Out << "u register";
+      break;
+    case TokenKind::sReg:
+      Out << "s register";
+      break;
+#define PUNCTUATOR(X, Y)                                                       
\
+  case TokenKind::pu_##X:                                                      
\
+    Out << #Y;                                                                 
\
+    break;
+#define KEYWORD(NAME)                                                          
\
+  case TokenKind::kw_##NAME:                                                   
\
+    Out << #NAME;                                                              
\
+    break;
+#define ENUM(NAME, LIT)                                                        
\
+  case TokenKind::en_##NAME:                                                   
\
+    Out << LIT;                                                                
\
+    break;
+#include "clang/Lex/HLSLRootSignatureTokenKinds.def"
+    }
+    First = false;
+  }
+
+  return TokenString;
+}
+
+// Parser Definitions
+
+RootSignatureParser::RootSignatureParser(SmallVector<RootElement> &Elements,
+                                         RootSignatureLexer &Lexer,
+                                         Preprocessor &PP)
+    : Elements(Elements), Lexer(Lexer), PP(PP), CurToken(SourceLocation()) {}
+
+bool RootSignatureParser::Parse() {
+  // Handle edge-case of empty RootSignature()
+  if (Lexer.EndOfBuffer())
+    return false;
+
+  // Iterate as many RootElements as possible
+  while (!ParseRootElement()) {
+    if (Lexer.EndOfBuffer())
+      return false;
+    if (ConsumeExpectedToken(TokenKind::pu_comma))
+      return true;
+  }
+
+  return true;
+}
+
+bool RootSignatureParser::ParseRootElement() {
+  if (ConsumeExpectedToken(TokenKind::kw_DescriptorTable))
+    return true;
+
+  // Dispatch onto the correct parse method
+  switch (CurToken.Kind) {
+  case TokenKind::kw_DescriptorTable:
+    return ParseDescriptorTable();
+  default:
+    llvm_unreachable("Switch for an expected token was not provided");
+  }
+  return true;
+}
+
+bool RootSignatureParser::ParseDescriptorTable() {
+  DescriptorTable Table;
+
+  if (ConsumeExpectedToken(TokenKind::pu_l_paren))
+    return true;
+
+  // Empty case:
+  if (!ConsumeExpectedToken(TokenKind::pu_r_paren)) {
+    Elements.push_back(Table);
+    return false;
+  }
+
+  return true;
+}
+
+// Is given token one of the expected kinds
+static bool IsExpectedToken(TokenKind Kind, ArrayRef<TokenKind> AnyExpected) {
+  for (auto Expected : AnyExpected)
+    if (Kind == Expected)
+      return true;
+  return false;
+}
+
+bool RootSignatureParser::ConsumeExpectedToken(TokenKind Expected) {
+  return ConsumeExpectedToken(ArrayRef{Expected});
+}
+
+bool RootSignatureParser::ConsumeExpectedToken(
+    ArrayRef<TokenKind> AnyExpected) {
+  ConsumeNextToken();
+  if (IsExpectedToken(CurToken.Kind, AnyExpected))
+    return false;
+
+  // Report unexpected token kind error
+  Diags().Report(CurToken.TokLoc, diag::err_hlsl_rootsig_unexpected_token_kind)
+      << (unsigned)(AnyExpected.size() != 1)
+      << FormatTokenKinds({CurToken.Kind})
+      << FormatTokenKinds(AnyExpected);
+  return true;
+}
+
+} // namespace hlsl
+} // namespace clang
diff --git a/clang/unittests/CMakeLists.txt b/clang/unittests/CMakeLists.txt
index 85d265426ec80..9b3ce8aa7de73 100644
--- a/clang/unittests/CMakeLists.txt
+++ b/clang/unittests/CMakeLists.txt
@@ -25,6 +25,7 @@ endfunction()
 
 add_subdirectory(Basic)
 add_subdirectory(Lex)
+add_subdirectory(Parse)
 add_subdirectory(Driver)
 if(CLANG_ENABLE_STATIC_ANALYZER)
   add_subdirectory(Analysis)
diff --git a/clang/unittests/Parse/CMakeLists.txt 
b/clang/unittests/Parse/CMakeLists.txt
new file mode 100644
index 0000000000000..eeb58174568cd
--- /dev/null
+++ b/clang/unittests/Parse/CMakeLists.txt
@@ -0,0 +1,23 @@
+set(LLVM_LINK_COMPONENTS
+  Support
+  )
+add_clang_unittest(ParseTests
+  ParseHLSLRootSignatureTest.cpp
+  )
+clang_target_link_libraries(ParseTests
+  PRIVATE
+  clangAST
+  clangASTMatchers
+  clangBasic
+  clangFrontend
+  clangParse
+  clangSema
+  clangSerialization
+  clangTooling
+  )
+target_link_libraries(ParseTests
+  PRIVATE
+  LLVMTestingAnnotations
+  LLVMTestingSupport
+  clangTesting
+  )
diff --git a/clang/unittests/Parse/ParseHLSLRootSignatureTest.cpp 
b/clang/unittests/Parse/ParseHLSLRootSignatureTest.cpp
new file mode 100644
index 0000000000000..f2ca933b4f39e
--- /dev/null
+++ b/clang/unittests/Parse/ParseHLSLRootSignatureTest.cpp
@@ -0,0 +1,217 @@
+//=== ParseHLSLRootSignatureTest.cpp - Parse Root Signature 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 "clang/Basic/Diagnostic.h"
+#include "clang/Basic/DiagnosticOptions.h"
+#include "clang/Basic/FileManager.h"
+#include "clang/Basic/LangOptions.h"
+#include "clang/Basic/SourceLocation.h"
+#include "clang/Basic/SourceManager.h"
+#include "clang/Basic/TargetInfo.h"
+#include "clang/Lex/HeaderSearch.h"
+#include "clang/Lex/HeaderSearchOptions.h"
+#include "clang/Lex/Lexer.h"
+#include "clang/Lex/ModuleLoader.h"
+#include "clang/Lex/Preprocessor.h"
+#include "clang/Lex/PreprocessorOptions.h"
+
+#include "clang/Lex/LexHLSLRootSignature.h"
+#include "clang/Parse/ParseHLSLRootSignature.h"
+#include "gtest/gtest.h"
+
+using namespace clang;
+using namespace llvm::hlsl::rootsig;
+
+namespace {
+
+// Diagnostic helper for helper tests
+class ExpectedDiagConsumer : public DiagnosticConsumer {
+  virtual void anchor() {}
+
+  void HandleDiagnostic(DiagnosticsEngine::Level DiagLevel,
+                        const Diagnostic &Info) override {
+    if (!FirstDiag || !ExpectedDiagID.has_value()) {
+      Satisfied = false;
+      return;
+    }
+    FirstDiag = false;
+
+    Satisfied = ExpectedDiagID.value() == Info.getID();
+  }
+
+  bool FirstDiag = true;
+  bool Satisfied = false;
+  std::optional<unsigned> ExpectedDiagID;
+
+public:
+  void SetNoDiag() {
+    Satisfied = true;
+    ExpectedDiagID = std::nullopt;
+  }
+
+  void SetExpected(unsigned DiagID) {
+    Satisfied = false;
+    ExpectedDiagID = DiagID;
+  }
+
+  bool IsSatisfied() { return Satisfied; }
+};
+
+// The test fixture.
+class ParseHLSLRootSignatureTest : public ::testing::Test {
+protected:
+  ParseHLSLRootSignatureTest()
+      : FileMgr(FileMgrOpts), DiagID(new DiagnosticIDs()),
+        Consumer(new ExpectedDiagConsumer()),
+        Diags(DiagID, new DiagnosticOptions, Consumer),
+        SourceMgr(Diags, FileMgr), TargetOpts(new TargetOptions) {
+    // This is an arbitrarily chosen target triple to create the target info.
+    TargetOpts->Triple = "dxil";
+    Target = TargetInfo::CreateTargetInfo(Diags, TargetOpts);
+  }
+
+  std::unique_ptr<Preprocessor> CreatePP(StringRef Source,
+                                         TrivialModuleLoader &ModLoader) {
+    std::unique_ptr<llvm::MemoryBuffer> Buf =
+        llvm::MemoryBuffer::getMemBuffer(Source);
+    SourceMgr.setMainFileID(SourceMgr.createFileID(std::move(Buf)));
+
+    HeaderSearch HeaderInfo(std::make_shared<HeaderSearchOptions>(), SourceMgr,
+                            Diags, LangOpts, Target.get());
+    std::unique_ptr<Preprocessor> PP = std::make_unique<Preprocessor>(
+        std::make_shared<PreprocessorOptions>(), Diags, LangOpts, SourceMgr,
+        HeaderInfo, ModLoader,
+        /*IILookup =*/nullptr,
+        /*OwnsHeaderSearch =*/false);
+    PP->Initialize(*Target);
+    PP->EnterMainSourceFile();
+    return PP;
+  }
+
+  FileSystemOptions FileMgrOpts;
+  FileManager FileMgr;
+  IntrusiveRefCntPtr<DiagnosticIDs> DiagID;
+  ExpectedDiagConsumer *Consumer;
+  DiagnosticsEngine Diags;
+  SourceManager SourceMgr;
+  LangOptions LangOpts;
+  std::shared_ptr<TargetOptions> TargetOpts;
+  IntrusiveRefCntPtr<TargetInfo> Target;
+};
+
+// Valid Parser Tests
+
+TEST_F(ParseHLSLRootSignatureTest, ValidParseEmptyTest) {
+  const llvm::StringLiteral Source = R"cc()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((int)Elements.size(), 0);
+
+  ASSERT_TRUE(Consumer->IsSatisfied());
+}
+
+TEST_F(ParseHLSLRootSignatureTest, ValidParseDTClausesTest) {
+  const llvm::StringLiteral Source = R"cc(
+    DescriptorTable()
+  )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());
+  RootElement Elem = Elements[0];
+
+  // Test generated DescriptorTable start has correct default values
+  ASSERT_TRUE(std::holds_alternative<DescriptorTable>(Elem));
+  ASSERT_EQ(std::get<DescriptorTable>(Elem).NumClauses, 0u);
+  ASSERT_TRUE(Consumer->IsSatisfied());
+}
+
+// Invalid Parser Tests
+
+TEST_F(ParseHLSLRootSignatureTest, InvalidParseUnexpectedTokenTest) {
+  const llvm::StringLiteral Source = R"cc(
+    DescriptorTable()
+    space
+  )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 correct diagnostic produced
+  Consumer->SetExpected(diag::err_hlsl_rootsig_unexpected_token_kind);
+  ASSERT_TRUE(Parser.Parse());
+
+  ASSERT_TRUE(Consumer->IsSatisfied());
+}
+
+TEST_F(ParseHLSLRootSignatureTest, InvalidParseInvalidTokenTest) {
+  const llvm::StringLiteral Source = R"cc(
+    notAnIdentifier
+  )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 correct diagnostic produced - invalid token
+  Consumer->SetExpected(diag::err_hlsl_rootsig_unexpected_token_kind);
+  ASSERT_TRUE(Parser.Parse());
+
+  ASSERT_TRUE(Consumer->IsSatisfied());
+}
+
+TEST_F(ParseHLSLRootSignatureTest, InvalidParseUnexpectedEndOfStreamTest) {
+  const llvm::StringLiteral Source = R"cc(
+    DescriptorTable(
+  )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 correct diagnostic produced - end of stream
+  Consumer->SetExpected(diag::err_hlsl_rootsig_unexpected_token_kind);
+  ASSERT_TRUE(Parser.Parse());
+
+  ASSERT_TRUE(Consumer->IsSatisfied());
+}
+
+} // anonymous namespace
diff --git a/llvm/include/llvm/Frontend/HLSL/HLSLRootSignature.h 
b/llvm/include/llvm/Frontend/HLSL/HLSLRootSignature.h
new file mode 100644
index 0000000000000..9bdd41e6dec7b
--- /dev/null
+++ b/llvm/include/llvm/Frontend/HLSL/HLSLRootSignature.h
@@ -0,0 +1,37 @@
+//===- HLSLRootSignature.h - 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 helper objects for working with HLSL Root
+/// Signatures.
+///
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_FRONTEND_HLSL_HLSLROOTSIGNATURE_H
+#define LLVM_FRONTEND_HLSL_HLSLROOTSIGNATURE_H
+
+#include <variant>
+
+namespace llvm {
+namespace hlsl {
+namespace rootsig {
+
+// Definitions of the in-memory data layout structures
+
+// Models the end of a descriptor table and stores its visibility
+struct DescriptorTable {
+  uint32_t NumClauses = 0; // The number of clauses in the table
+};
+
+// Models RootElement : DescriptorTable
+using RootElement = std::variant<DescriptorTable>;
+
+} // namespace rootsig
+} // namespace hlsl
+} // namespace llvm
+
+#endif // LLVM_FRONTEND_HLSL_HLSLROOTSIGNATURE_H

>From d444568345ff01da82e9170df3b37690c28a0ce9 Mon Sep 17 00:00:00 2001
From: Finn Plummer <canadienf...@gmail.com>
Date: Thu, 13 Feb 2025 23:17:21 +0000
Subject: [PATCH 02/15] add empty Descriptor Table Clause

---
 .../clang/Parse/ParseHLSLRootSignature.h      | 13 ++++
 clang/lib/Parse/ParseHLSLRootSignature.cpp    | 69 ++++++++++++++++++-
 .../Parse/ParseHLSLRootSignatureTest.cpp      | 25 +++++++
 .../llvm/Frontend/HLSL/HLSLRootSignature.h    | 11 ++-
 4 files changed, 114 insertions(+), 4 deletions(-)

diff --git a/clang/include/clang/Parse/ParseHLSLRootSignature.h 
b/clang/include/clang/Parse/ParseHLSLRootSignature.h
index fa46bdd663a2c..94acf5b0ecd94 100644
--- a/clang/include/clang/Parse/ParseHLSLRootSignature.h
+++ b/clang/include/clang/Parse/ParseHLSLRootSignature.h
@@ -43,10 +43,15 @@ class RootSignatureParser {
   // Root Element helpers
   bool ParseRootElement();
   bool ParseDescriptorTable();
+  bool ParseDescriptorTableClause();
 
   /// Invoke the Lexer to consume a token and update CurToken with the result
   void ConsumeNextToken() { CurToken = Lexer.ConsumeToken(); }
 
+  /// Return true if the next token one of the expected kinds
+  bool PeekExpectedToken(TokenKind Expected);
+  bool PeekExpectedToken(ArrayRef<TokenKind> AnyExpected);
+
   /// Consumes the next token and report an error if it is not of the expected
   /// kind.
   ///
@@ -54,6 +59,14 @@ class RootSignatureParser {
   bool ConsumeExpectedToken(TokenKind Expected);
   bool ConsumeExpectedToken(ArrayRef<TokenKind> AnyExpected);
 
+  /// Peek if the next token is of the expected kind and if it is then consume
+  /// it.
+  ///
+  /// Returns true if it successfully matches the expected kind and the token
+  /// was consumed.
+  bool TryConsumeExpectedToken(TokenKind Expected);
+  bool TryConsumeExpectedToken(ArrayRef<TokenKind> Expected);
+
 private:
   SmallVector<llvm::hlsl::rootsig::RootElement> &Elements;
   RootSignatureLexer &Lexer;
diff --git a/clang/lib/Parse/ParseHLSLRootSignature.cpp 
b/clang/lib/Parse/ParseHLSLRootSignature.cpp
index aeb33ded4d815..932a8a6263b05 100644
--- a/clang/lib/Parse/ParseHLSLRootSignature.cpp
+++ b/clang/lib/Parse/ParseHLSLRootSignature.cpp
@@ -100,12 +100,55 @@ bool RootSignatureParser::ParseDescriptorTable() {
     return true;
 
   // Empty case:
-  if (!ConsumeExpectedToken(TokenKind::pu_r_paren)) {
+  if (TryConsumeExpectedToken(TokenKind::pu_r_paren)) {
     Elements.push_back(Table);
     return false;
   }
 
-  return true;
+  // Iterate through all the defined clauses
+  do {
+    if (ParseDescriptorTableClause())
+      return true;
+    Table.NumClauses++;
+  } while (TryConsumeExpectedToken(TokenKind::pu_comma));
+
+  if (ConsumeExpectedToken(TokenKind::pu_r_paren))
+    return true;
+
+  Elements.push_back(Table);
+  return false;
+}
+
+bool RootSignatureParser::ParseDescriptorTableClause() {
+  if (ConsumeExpectedToken({TokenKind::kw_CBV, TokenKind::kw_SRV,
+                            TokenKind::kw_UAV, TokenKind::kw_Sampler}))
+    return true;
+
+  DescriptorTableClause Clause;
+  switch (CurToken.Kind) {
+  case TokenKind::kw_CBV:
+    Clause.Type = ClauseType::CBuffer;
+    break;
+  case TokenKind::kw_SRV:
+    Clause.Type = ClauseType::SRV;
+    break;
+  case TokenKind::kw_UAV:
+    Clause.Type = ClauseType::UAV;
+    break;
+  case TokenKind::kw_Sampler:
+    Clause.Type = ClauseType::Sampler;
+    break;
+  default:
+    llvm_unreachable("Switch for an expected token was not provided");
+  }
+  if (ConsumeExpectedToken(TokenKind::pu_l_paren))
+    return true;
+
+  if (ConsumeExpectedToken(TokenKind::pu_r_paren))
+    return true;
+
+  Elements.push_back(Clause);
+  return false;
 }
 
 // Is given token one of the expected kinds
@@ -116,6 +159,15 @@ static bool IsExpectedToken(TokenKind Kind, 
ArrayRef<TokenKind> AnyExpected) {
   return false;
 }
 
+bool RootSignatureParser::PeekExpectedToken(TokenKind Expected) {
+  return PeekExpectedToken(ArrayRef{Expected});
+}
+
+bool RootSignatureParser::PeekExpectedToken(ArrayRef<TokenKind> AnyExpected) {
+  RootSignatureToken Result = Lexer.PeekNextToken();
+  return IsExpectedToken(Result.Kind, AnyExpected);
+}
+
 bool RootSignatureParser::ConsumeExpectedToken(TokenKind Expected) {
   return ConsumeExpectedToken(ArrayRef{Expected});
 }
@@ -134,5 +186,18 @@ bool RootSignatureParser::ConsumeExpectedToken(
   return true;
 }
 
+bool RootSignatureParser::TryConsumeExpectedToken(TokenKind Expected) {
+  return TryConsumeExpectedToken(ArrayRef{Expected});
+}
+
+bool RootSignatureParser::TryConsumeExpectedToken(
+    ArrayRef<TokenKind> AnyExpected) {
+  // If not the expected token just return
+  if (!PeekExpectedToken(AnyExpected))
+    return false;
+  ConsumeNextToken();
+  return true;
+}
+
 } // namespace hlsl
 } // namespace clang
diff --git a/clang/unittests/Parse/ParseHLSLRootSignatureTest.cpp 
b/clang/unittests/Parse/ParseHLSLRootSignatureTest.cpp
index f2ca933b4f39e..8e13467f3dfe7 100644
--- a/clang/unittests/Parse/ParseHLSLRootSignatureTest.cpp
+++ b/clang/unittests/Parse/ParseHLSLRootSignatureTest.cpp
@@ -128,6 +128,12 @@ TEST_F(ParseHLSLRootSignatureTest, ValidParseEmptyTest) {
 
 TEST_F(ParseHLSLRootSignatureTest, ValidParseDTClausesTest) {
   const llvm::StringLiteral Source = R"cc(
+    DescriptorTable(
+      CBV(),
+      SRV(),
+      Sampler(),
+      UAV()
+    ),
     DescriptorTable()
   )cc";
 
@@ -144,7 +150,26 @@ TEST_F(ParseHLSLRootSignatureTest, 
ValidParseDTClausesTest) {
 
   ASSERT_FALSE(Parser.Parse());
   RootElement Elem = Elements[0];
+  ASSERT_TRUE(std::holds_alternative<DescriptorTableClause>(Elem));
+  ASSERT_EQ(std::get<DescriptorTableClause>(Elem).Type, ClauseType::CBuffer);
+
+  Elem = Elements[1];
+  ASSERT_TRUE(std::holds_alternative<DescriptorTableClause>(Elem));
+  ASSERT_EQ(std::get<DescriptorTableClause>(Elem).Type, ClauseType::SRV);
+
+  Elem = Elements[2];
+  ASSERT_TRUE(std::holds_alternative<DescriptorTableClause>(Elem));
+  ASSERT_EQ(std::get<DescriptorTableClause>(Elem).Type, ClauseType::Sampler);
+
+  Elem = Elements[3];
+  ASSERT_TRUE(std::holds_alternative<DescriptorTableClause>(Elem));
+  ASSERT_EQ(std::get<DescriptorTableClause>(Elem).Type, ClauseType::UAV);
+
+  Elem = Elements[4];
+  ASSERT_TRUE(std::holds_alternative<DescriptorTable>(Elem));
+  ASSERT_EQ(std::get<DescriptorTable>(Elem).NumClauses, (uint32_t)4);
 
+  Elem = Elements[5];
   // Test generated DescriptorTable start has correct default values
   ASSERT_TRUE(std::holds_alternative<DescriptorTable>(Elem));
   ASSERT_EQ(std::get<DescriptorTable>(Elem).NumClauses, 0u);
diff --git a/llvm/include/llvm/Frontend/HLSL/HLSLRootSignature.h 
b/llvm/include/llvm/Frontend/HLSL/HLSLRootSignature.h
index 9bdd41e6dec7b..c1b67844c747f 100644
--- a/llvm/include/llvm/Frontend/HLSL/HLSLRootSignature.h
+++ b/llvm/include/llvm/Frontend/HLSL/HLSLRootSignature.h
@@ -14,6 +14,7 @@
 #ifndef LLVM_FRONTEND_HLSL_HLSLROOTSIGNATURE_H
 #define LLVM_FRONTEND_HLSL_HLSLROOTSIGNATURE_H
 
+#include "llvm/Support/DXILABI.h"
 #include <variant>
 
 namespace llvm {
@@ -27,8 +28,14 @@ struct DescriptorTable {
   uint32_t NumClauses = 0; // The number of clauses in the table
 };
 
-// Models RootElement : DescriptorTable
-using RootElement = std::variant<DescriptorTable>;
+// Models DTClause : CBV | SRV | UAV | Sampler, by collecting like parameters
+using ClauseType = llvm::dxil::ResourceClass;
+struct DescriptorTableClause {
+  ClauseType Type;
+};
+
+// Models RootElement : DescriptorTable | DescriptorTableClause
+using RootElement = std::variant<DescriptorTable, DescriptorTableClause>;
 
 } // namespace rootsig
 } // namespace hlsl

>From a7e36bfb21a6db435f8eade235818bf2496a6efd Mon Sep 17 00:00:00 2001
From: Finn Plummer <canadienf...@gmail.com>
Date: Fri, 14 Feb 2025 00:21:28 +0000
Subject: [PATCH 03/15] add Register and implicitly unsigned integers

---
 .../clang/Basic/DiagnosticParseKinds.td       |  1 +
 .../clang/Parse/ParseHLSLRootSignature.h      |  5 ++
 clang/lib/Parse/ParseHLSLRootSignature.cpp    | 57 +++++++++++++++++++
 .../Parse/ParseHLSLRootSignatureTest.cpp      | 46 +++++++++++++--
 .../llvm/Frontend/HLSL/HLSLRootSignature.h    |  8 +++
 5 files changed, 113 insertions(+), 4 deletions(-)

diff --git a/clang/include/clang/Basic/DiagnosticParseKinds.td 
b/clang/include/clang/Basic/DiagnosticParseKinds.td
index 4c6adab80e60e..a5e19ddc75e02 100644
--- a/clang/include/clang/Basic/DiagnosticParseKinds.td
+++ b/clang/include/clang/Basic/DiagnosticParseKinds.td
@@ -1820,4 +1820,5 @@ def err_hlsl_packoffset_invalid_reg : Error<"invalid 
resource class specifier '%
 
 // HLSL Root Signature Parser Diagnostics
 def err_hlsl_rootsig_unexpected_token_kind : Error<"got %1 but expected 
%select{|one of}0 the following token kind%select{|s}0: %2">;
+def err_hlsl_number_literal_overflow : Error<"integer literal is too large to 
be represented as a 32-bit %select{signed |}0 integer type">;
 } // end of Parser diagnostics
diff --git a/clang/include/clang/Parse/ParseHLSLRootSignature.h 
b/clang/include/clang/Parse/ParseHLSLRootSignature.h
index 94acf5b0ecd94..01d38261f58ee 100644
--- a/clang/include/clang/Parse/ParseHLSLRootSignature.h
+++ b/clang/include/clang/Parse/ParseHLSLRootSignature.h
@@ -45,6 +45,11 @@ class RootSignatureParser {
   bool ParseDescriptorTable();
   bool ParseDescriptorTableClause();
 
+  /// Use NumericLiteralParser to convert CurToken.NumSpelling into a unsigned
+  /// 32-bit integer
+  bool HandleUIntLiteral(uint32_t &X);
+  bool ParseRegister(llvm::hlsl::rootsig::Register *Reg);
+
   /// Invoke the Lexer to consume a token and update CurToken with the result
   void ConsumeNextToken() { CurToken = Lexer.ConsumeToken(); }
 
diff --git a/clang/lib/Parse/ParseHLSLRootSignature.cpp 
b/clang/lib/Parse/ParseHLSLRootSignature.cpp
index 932a8a6263b05..f470126f5ed51 100644
--- a/clang/lib/Parse/ParseHLSLRootSignature.cpp
+++ b/clang/lib/Parse/ParseHLSLRootSignature.cpp
@@ -1,5 +1,7 @@
 #include "clang/Parse/ParseHLSLRootSignature.h"
 
+#include "clang/Lex/LiteralSupport.h"
+
 #include "llvm/Support/raw_ostream.h"
 
 using namespace llvm::hlsl::rootsig;
@@ -144,6 +146,10 @@ bool RootSignatureParser::ParseDescriptorTableClause() {
   if (ConsumeExpectedToken(TokenKind::pu_l_paren))
     return true;
 
+  // Consume mandatory Register paramater
+  if (ParseRegister(&Clause.Register))
+    return true;
+
   if (ConsumeExpectedToken(TokenKind::pu_r_paren))
     return true;
 
@@ -151,6 +157,57 @@ bool RootSignatureParser::ParseDescriptorTableClause() {
   return false;
 }
 
+bool RootSignatureParser::HandleUIntLiteral(uint32_t &X) {
+  // Parse the numeric value and do semantic checks on its specification
+  clang::NumericLiteralParser Literal(CurToken.NumSpelling, CurToken.TokLoc,
+                                      PP.getSourceManager(), PP.getLangOpts(),
+                                      PP.getTargetInfo(), PP.getDiagnostics());
+  if (Literal.hadError)
+    return true; // Error has already been reported so just return
+
+  assert(Literal.isIntegerLiteral() && "IsNumberChar will only support 
digits");
+
+  llvm::APSInt Val = llvm::APSInt(32, false);
+  if (Literal.GetIntegerValue(Val)) {
+    // Report that the value has overflowed
+    PP.getDiagnostics().Report(CurToken.TokLoc,
+                               diag::err_hlsl_number_literal_overflow)
+        << 0 << CurToken.NumSpelling;
+    return true;
+  }
+
+  X = Val.getExtValue();
+  return false;
+}
+
+bool RootSignatureParser::ParseRegister(Register *Register) {
+  if (ConsumeExpectedToken(
+          {TokenKind::bReg, TokenKind::tReg, TokenKind::uReg, 
TokenKind::sReg}))
+    return true;
+
+  switch (CurToken.Kind) {
+  case TokenKind::bReg:
+    Register->ViewType = RegisterType::BReg;
+    break;
+  case TokenKind::tReg:
+    Register->ViewType = RegisterType::TReg;
+    break;
+  case TokenKind::uReg:
+    Register->ViewType = RegisterType::UReg;
+    break;
+  case TokenKind::sReg:
+    Register->ViewType = RegisterType::SReg;
+    break;
+  default:
+    llvm_unreachable("Switch for an expected token was not provided");
+  }
+
+  if (HandleUIntLiteral(Register->Number))
+    return true; // propogate NumericLiteralParser error
+
+  return false;
+}
+
 // Is given token one of the expected kinds
 static bool IsExpectedToken(TokenKind Kind, ArrayRef<TokenKind> AnyExpected) {
   for (auto Expected : AnyExpected)
diff --git a/clang/unittests/Parse/ParseHLSLRootSignatureTest.cpp 
b/clang/unittests/Parse/ParseHLSLRootSignatureTest.cpp
index 8e13467f3dfe7..4beff9e6c9a42 100644
--- a/clang/unittests/Parse/ParseHLSLRootSignatureTest.cpp
+++ b/clang/unittests/Parse/ParseHLSLRootSignatureTest.cpp
@@ -129,10 +129,10 @@ TEST_F(ParseHLSLRootSignatureTest, ValidParseEmptyTest) {
 TEST_F(ParseHLSLRootSignatureTest, ValidParseDTClausesTest) {
   const llvm::StringLiteral Source = R"cc(
     DescriptorTable(
-      CBV(),
-      SRV(),
-      Sampler(),
-      UAV()
+      CBV(b0),
+      SRV(t42),
+      Sampler(s987),
+      UAV(u987234)
     ),
     DescriptorTable()
   )cc";
@@ -152,18 +152,33 @@ TEST_F(ParseHLSLRootSignatureTest, 
ValidParseDTClausesTest) {
   RootElement Elem = Elements[0];
   ASSERT_TRUE(std::holds_alternative<DescriptorTableClause>(Elem));
   ASSERT_EQ(std::get<DescriptorTableClause>(Elem).Type, ClauseType::CBuffer);
+  ASSERT_EQ(std::get<DescriptorTableClause>(Elem).Register.ViewType,
+            RegisterType::BReg);
+  ASSERT_EQ(std::get<DescriptorTableClause>(Elem).Register.Number, 
(uint32_t)0);
 
   Elem = Elements[1];
   ASSERT_TRUE(std::holds_alternative<DescriptorTableClause>(Elem));
   ASSERT_EQ(std::get<DescriptorTableClause>(Elem).Type, ClauseType::SRV);
+  ASSERT_EQ(std::get<DescriptorTableClause>(Elem).Register.ViewType,
+            RegisterType::TReg);
+  ASSERT_EQ(std::get<DescriptorTableClause>(Elem).Register.Number,
+            (uint32_t)42);
 
   Elem = Elements[2];
   ASSERT_TRUE(std::holds_alternative<DescriptorTableClause>(Elem));
   ASSERT_EQ(std::get<DescriptorTableClause>(Elem).Type, ClauseType::Sampler);
+  ASSERT_EQ(std::get<DescriptorTableClause>(Elem).Register.ViewType,
+            RegisterType::SReg);
+  ASSERT_EQ(std::get<DescriptorTableClause>(Elem).Register.Number,
+            (uint32_t)987);
 
   Elem = Elements[3];
   ASSERT_TRUE(std::holds_alternative<DescriptorTableClause>(Elem));
   ASSERT_EQ(std::get<DescriptorTableClause>(Elem).Type, ClauseType::UAV);
+  ASSERT_EQ(std::get<DescriptorTableClause>(Elem).Register.ViewType,
+            RegisterType::UReg);
+  ASSERT_EQ(std::get<DescriptorTableClause>(Elem).Register.Number,
+            (uint32_t)987234);
 
   Elem = Elements[4];
   ASSERT_TRUE(std::holds_alternative<DescriptorTable>(Elem));
@@ -239,4 +254,27 @@ TEST_F(ParseHLSLRootSignatureTest, 
InvalidParseUnexpectedEndOfStreamTest) {
   ASSERT_TRUE(Consumer->IsSatisfied());
 }
 
+TEST_F(ParseHLSLRootSignatureTest, InvalidLexOverflowedNumberTest) {
+  // This test will check that the lexing fails due to an integer overflow
+  const llvm::StringLiteral Source = R"cc(
+    DescriptorTable(
+      CBV(s4294967296)
+    )
+  )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 correct diagnostic produced
+  Consumer->SetExpected(diag::err_hlsl_number_literal_overflow);
+  ASSERT_TRUE(Parser.Parse());
+
+  ASSERT_TRUE(Consumer->IsSatisfied());
+}
+
 } // anonymous namespace
diff --git a/llvm/include/llvm/Frontend/HLSL/HLSLRootSignature.h 
b/llvm/include/llvm/Frontend/HLSL/HLSLRootSignature.h
index c1b67844c747f..93f83fc824c6e 100644
--- a/llvm/include/llvm/Frontend/HLSL/HLSLRootSignature.h
+++ b/llvm/include/llvm/Frontend/HLSL/HLSLRootSignature.h
@@ -23,6 +23,13 @@ namespace rootsig {
 
 // Definitions of the in-memory data layout structures
 
+// Models the different registers: bReg | tReg | uReg | sReg
+enum class RegisterType { BReg, TReg, UReg, SReg };
+struct Register {
+  RegisterType ViewType;
+  uint32_t Number;
+};
+
 // Models the end of a descriptor table and stores its visibility
 struct DescriptorTable {
   uint32_t NumClauses = 0; // The number of clauses in the table
@@ -32,6 +39,7 @@ struct DescriptorTable {
 using ClauseType = llvm::dxil::ResourceClass;
 struct DescriptorTableClause {
   ClauseType Type;
+  Register Register;
 };
 
 // Models RootElement : DescriptorTable | DescriptorTableClause

>From e8f60466ec90bde7a4064b873a91a726855c6b59 Mon Sep 17 00:00:00 2001
From: Finn Plummer <canadienf...@gmail.com>
Date: Tue, 28 Jan 2025 19:00:29 +0000
Subject: [PATCH 04/15] add support for optional parameters

- use `numDescriptors` as example
---
 .../clang/Basic/DiagnosticParseKinds.td       |  1 +
 .../clang/Parse/ParseHLSLRootSignature.h      | 14 ++++
 clang/lib/Parse/ParseHLSLRootSignature.cpp    | 65 +++++++++++++++++++
 .../Parse/ParseHLSLRootSignatureTest.cpp      | 26 +++++++-
 .../llvm/Frontend/HLSL/HLSLRootSignature.h    |  5 ++
 5 files changed, 110 insertions(+), 1 deletion(-)

diff --git a/clang/include/clang/Basic/DiagnosticParseKinds.td 
b/clang/include/clang/Basic/DiagnosticParseKinds.td
index a5e19ddc75e02..ce0da28df3976 100644
--- a/clang/include/clang/Basic/DiagnosticParseKinds.td
+++ b/clang/include/clang/Basic/DiagnosticParseKinds.td
@@ -1821,4 +1821,5 @@ def err_hlsl_packoffset_invalid_reg : Error<"invalid 
resource class specifier '%
 // HLSL Root Signature Parser Diagnostics
 def err_hlsl_rootsig_unexpected_token_kind : Error<"got %1 but expected 
%select{|one of}0 the following token kind%select{|s}0: %2">;
 def err_hlsl_number_literal_overflow : Error<"integer literal is too large to 
be represented as a 32-bit %select{signed |}0 integer type">;
+def err_hlsl_rootsig_repeat_param : Error<"specified the same parameter '%0' 
multiple times">;
 } // end of Parser diagnostics
diff --git a/clang/include/clang/Parse/ParseHLSLRootSignature.h 
b/clang/include/clang/Parse/ParseHLSLRootSignature.h
index 01d38261f58ee..3587d0acbd739 100644
--- a/clang/include/clang/Parse/ParseHLSLRootSignature.h
+++ b/clang/include/clang/Parse/ParseHLSLRootSignature.h
@@ -45,10 +45,24 @@ class RootSignatureParser {
   bool ParseDescriptorTable();
   bool ParseDescriptorTableClause();
 
+  /// It is helpful to have a generalized dispatch method so that when we need
+  /// to parse multiple optional parameters in any order, we can invoke this
+  /// method.
+  ///
+  /// Each unique ParamType is expected to define a custom Parse method. This
+  /// function will switch on the ParamType using std::visit and dispatch onto
+  /// the corresponding Parse method
+  bool ParseParam(llvm::hlsl::rootsig::ParamType Ref);
+
+  /// Parses as many optional parameters as possible in any order
+  bool ParseOptionalParams(
+      llvm::SmallDenseMap<TokenKind, llvm::hlsl::rootsig::ParamType> &RefMap);
+
   /// Use NumericLiteralParser to convert CurToken.NumSpelling into a unsigned
   /// 32-bit integer
   bool HandleUIntLiteral(uint32_t &X);
   bool ParseRegister(llvm::hlsl::rootsig::Register *Reg);
+  bool ParseUInt(uint32_t *X);
 
   /// Invoke the Lexer to consume a token and update CurToken with the result
   void ConsumeNextToken() { CurToken = Lexer.ConsumeToken(); }
diff --git a/clang/lib/Parse/ParseHLSLRootSignature.cpp 
b/clang/lib/Parse/ParseHLSLRootSignature.cpp
index f470126f5ed51..161ad6b71529b 100644
--- a/clang/lib/Parse/ParseHLSLRootSignature.cpp
+++ b/clang/lib/Parse/ParseHLSLRootSignature.cpp
@@ -150,6 +150,13 @@ bool RootSignatureParser::ParseDescriptorTableClause() {
   if (ParseRegister(&Clause.Register))
     return true;
 
+  // Define optional paramaters
+  llvm::SmallDenseMap<TokenKind, ParamType> RefMap = {
+      {TokenKind::kw_numDescriptors, &Clause.NumDescriptors},
+  };
+  if (ParseOptionalParams({RefMap}))
+    return true;
+
   if (ConsumeExpectedToken(TokenKind::pu_r_paren))
     return true;
 
@@ -157,6 +164,52 @@ bool RootSignatureParser::ParseDescriptorTableClause() {
   return false;
 }
 
+// Helper struct so that we can use the overloaded notation of std::visit
+template <class... Ts> struct ParseMethods : Ts... {
+  using Ts::operator()...;
+};
+template <class... Ts> ParseMethods(Ts...) -> ParseMethods<Ts...>;
+
+bool RootSignatureParser::ParseParam(ParamType Ref) {
+  if (ConsumeExpectedToken(TokenKind::pu_equal))
+    return true;
+
+  bool Error;
+  std::visit(ParseMethods{
+    [&](uint32_t *X) { Error = ParseUInt(X); },
+  }, Ref);
+
+  return Error;
+}
+
+bool RootSignatureParser::ParseOptionalParams(
+    llvm::SmallDenseMap<TokenKind, ParamType> &RefMap) {
+  SmallVector<TokenKind> ParamKeywords;
+  for (auto RefPair : RefMap)
+    ParamKeywords.push_back(RefPair.first);
+
+  // Keep track of which keywords have been seen to report duplicates
+  llvm::SmallDenseSet<TokenKind> Seen;
+
+  while (TryConsumeExpectedToken(TokenKind::pu_comma)) {
+    if (ConsumeExpectedToken(ParamKeywords))
+      return true;
+
+    TokenKind ParamKind = CurToken.Kind;
+    if (Seen.contains(ParamKind)) {
+      Diags().Report(CurToken.TokLoc, diag::err_hlsl_rootsig_repeat_param)
+          << FormatTokenKinds({ParamKind});
+      return true;
+    }
+    Seen.insert(ParamKind);
+
+    if (ParseParam(RefMap[ParamKind]))
+      return true;
+  }
+
+  return false;
+}
+
 bool RootSignatureParser::HandleUIntLiteral(uint32_t &X) {
   // Parse the numeric value and do semantic checks on its specification
   clang::NumericLiteralParser Literal(CurToken.NumSpelling, CurToken.TokLoc,
@@ -208,6 +261,18 @@ bool RootSignatureParser::ParseRegister(Register 
*Register) {
   return false;
 }
 
+bool RootSignatureParser::ParseUInt(uint32_t *X) {
+  // Treat a postively signed integer as though it is unsigned to match DXC
+  TryConsumeExpectedToken(TokenKind::pu_plus);
+  if (ConsumeExpectedToken(TokenKind::int_literal))
+    return true;
+
+  if (HandleUIntLiteral(*X))
+    return true; // propogate NumericLiteralParser error
+
+  return false;
+}
+
 // Is given token one of the expected kinds
 static bool IsExpectedToken(TokenKind Kind, ArrayRef<TokenKind> AnyExpected) {
   for (auto Expected : AnyExpected)
diff --git a/clang/unittests/Parse/ParseHLSLRootSignatureTest.cpp 
b/clang/unittests/Parse/ParseHLSLRootSignatureTest.cpp
index 4beff9e6c9a42..88182364ff708 100644
--- a/clang/unittests/Parse/ParseHLSLRootSignatureTest.cpp
+++ b/clang/unittests/Parse/ParseHLSLRootSignatureTest.cpp
@@ -130,7 +130,7 @@ TEST_F(ParseHLSLRootSignatureTest, ValidParseDTClausesTest) 
{
   const llvm::StringLiteral Source = R"cc(
     DescriptorTable(
       CBV(b0),
-      SRV(t42),
+      SRV(t42, numDescriptors = +4),
       Sampler(s987),
       UAV(u987234)
     ),
@@ -155,6 +155,7 @@ TEST_F(ParseHLSLRootSignatureTest, ValidParseDTClausesTest) 
{
   ASSERT_EQ(std::get<DescriptorTableClause>(Elem).Register.ViewType,
             RegisterType::BReg);
   ASSERT_EQ(std::get<DescriptorTableClause>(Elem).Register.Number, 
(uint32_t)0);
+  ASSERT_EQ(std::get<DescriptorTableClause>(Elem).NumDescriptors, (uint32_t)1);
 
   Elem = Elements[1];
   ASSERT_TRUE(std::holds_alternative<DescriptorTableClause>(Elem));
@@ -163,6 +164,7 @@ TEST_F(ParseHLSLRootSignatureTest, ValidParseDTClausesTest) 
{
             RegisterType::TReg);
   ASSERT_EQ(std::get<DescriptorTableClause>(Elem).Register.Number,
             (uint32_t)42);
+  ASSERT_EQ(std::get<DescriptorTableClause>(Elem).NumDescriptors, (uint32_t)4);
 
   Elem = Elements[2];
   ASSERT_TRUE(std::holds_alternative<DescriptorTableClause>(Elem));
@@ -171,6 +173,7 @@ TEST_F(ParseHLSLRootSignatureTest, ValidParseDTClausesTest) 
{
             RegisterType::SReg);
   ASSERT_EQ(std::get<DescriptorTableClause>(Elem).Register.Number,
             (uint32_t)987);
+  ASSERT_EQ(std::get<DescriptorTableClause>(Elem).NumDescriptors, (uint32_t)1);
 
   Elem = Elements[3];
   ASSERT_TRUE(std::holds_alternative<DescriptorTableClause>(Elem));
@@ -179,6 +182,7 @@ TEST_F(ParseHLSLRootSignatureTest, ValidParseDTClausesTest) 
{
             RegisterType::UReg);
   ASSERT_EQ(std::get<DescriptorTableClause>(Elem).Register.Number,
             (uint32_t)987234);
+  ASSERT_EQ(std::get<DescriptorTableClause>(Elem).NumDescriptors, (uint32_t)1);
 
   Elem = Elements[4];
   ASSERT_TRUE(std::holds_alternative<DescriptorTable>(Elem));
@@ -277,4 +281,24 @@ TEST_F(ParseHLSLRootSignatureTest, 
InvalidLexOverflowedNumberTest) {
   ASSERT_TRUE(Consumer->IsSatisfied());
 }
 
+TEST_F(ParseHLSLRootSignatureTest, InvalidParseRepeatedParamTest) {
+  const llvm::StringLiteral Source = R"cc(
+    DescriptorTable(
+      CBV(b0, numDescriptors = 3, numDescriptors = 1)
+    )
+  )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 correct diagnostic produced
+  Consumer->SetExpected(diag::err_hlsl_rootsig_repeat_param);
+  ASSERT_TRUE(Parser.Parse());
+
+  ASSERT_TRUE(Consumer->IsSatisfied());
+}
+
 } // anonymous namespace
diff --git a/llvm/include/llvm/Frontend/HLSL/HLSLRootSignature.h 
b/llvm/include/llvm/Frontend/HLSL/HLSLRootSignature.h
index 93f83fc824c6e..abc5fe28db32a 100644
--- a/llvm/include/llvm/Frontend/HLSL/HLSLRootSignature.h
+++ b/llvm/include/llvm/Frontend/HLSL/HLSLRootSignature.h
@@ -40,11 +40,16 @@ using ClauseType = llvm::dxil::ResourceClass;
 struct DescriptorTableClause {
   ClauseType Type;
   Register Register;
+  uint32_t NumDescriptors = 1;
 };
 
 // Models RootElement : DescriptorTable | DescriptorTableClause
 using RootElement = std::variant<DescriptorTable, DescriptorTableClause>;
 
+// Models a reference to all assignment parameter types that any RootElement
+// may have. Things of the form: Keyword = Param
+using ParamType = std::variant<uint32_t *>;
+
 } // namespace rootsig
 } // namespace hlsl
 } // namespace llvm

>From a8ddf47e7412179bc2ae8a8ef6f53c27b150fb11 Mon Sep 17 00:00:00 2001
From: Finn Plummer <canadienf...@gmail.com>
Date: Tue, 28 Jan 2025 19:23:50 +0000
Subject: [PATCH 05/15] add space optional parameter

- demonstrate can specify in any order
---
 clang/lib/Parse/ParseHLSLRootSignature.cpp           | 1 +
 clang/unittests/Parse/ParseHLSLRootSignatureTest.cpp | 8 ++++++--
 llvm/include/llvm/Frontend/HLSL/HLSLRootSignature.h  | 1 +
 3 files changed, 8 insertions(+), 2 deletions(-)

diff --git a/clang/lib/Parse/ParseHLSLRootSignature.cpp 
b/clang/lib/Parse/ParseHLSLRootSignature.cpp
index 161ad6b71529b..23731439c6766 100644
--- a/clang/lib/Parse/ParseHLSLRootSignature.cpp
+++ b/clang/lib/Parse/ParseHLSLRootSignature.cpp
@@ -153,6 +153,7 @@ bool RootSignatureParser::ParseDescriptorTableClause() {
   // Define optional paramaters
   llvm::SmallDenseMap<TokenKind, ParamType> RefMap = {
       {TokenKind::kw_numDescriptors, &Clause.NumDescriptors},
+      {TokenKind::kw_space, &Clause.Space},
   };
   if (ParseOptionalParams({RefMap}))
     return true;
diff --git a/clang/unittests/Parse/ParseHLSLRootSignatureTest.cpp 
b/clang/unittests/Parse/ParseHLSLRootSignatureTest.cpp
index 88182364ff708..5ddc068410a88 100644
--- a/clang/unittests/Parse/ParseHLSLRootSignatureTest.cpp
+++ b/clang/unittests/Parse/ParseHLSLRootSignatureTest.cpp
@@ -130,8 +130,8 @@ TEST_F(ParseHLSLRootSignatureTest, ValidParseDTClausesTest) 
{
   const llvm::StringLiteral Source = R"cc(
     DescriptorTable(
       CBV(b0),
-      SRV(t42, numDescriptors = +4),
-      Sampler(s987),
+      SRV(t42, space = 3, numDescriptors = +4),
+      Sampler(s987, space = 2),
       UAV(u987234)
     ),
     DescriptorTable()
@@ -156,6 +156,7 @@ TEST_F(ParseHLSLRootSignatureTest, ValidParseDTClausesTest) 
{
             RegisterType::BReg);
   ASSERT_EQ(std::get<DescriptorTableClause>(Elem).Register.Number, 
(uint32_t)0);
   ASSERT_EQ(std::get<DescriptorTableClause>(Elem).NumDescriptors, (uint32_t)1);
+  ASSERT_EQ(std::get<DescriptorTableClause>(Elem).Space, (uint32_t)0);
 
   Elem = Elements[1];
   ASSERT_TRUE(std::holds_alternative<DescriptorTableClause>(Elem));
@@ -165,6 +166,7 @@ TEST_F(ParseHLSLRootSignatureTest, ValidParseDTClausesTest) 
{
   ASSERT_EQ(std::get<DescriptorTableClause>(Elem).Register.Number,
             (uint32_t)42);
   ASSERT_EQ(std::get<DescriptorTableClause>(Elem).NumDescriptors, (uint32_t)4);
+  ASSERT_EQ(std::get<DescriptorTableClause>(Elem).Space, (uint32_t)3);
 
   Elem = Elements[2];
   ASSERT_TRUE(std::holds_alternative<DescriptorTableClause>(Elem));
@@ -174,6 +176,7 @@ TEST_F(ParseHLSLRootSignatureTest, ValidParseDTClausesTest) 
{
   ASSERT_EQ(std::get<DescriptorTableClause>(Elem).Register.Number,
             (uint32_t)987);
   ASSERT_EQ(std::get<DescriptorTableClause>(Elem).NumDescriptors, (uint32_t)1);
+  ASSERT_EQ(std::get<DescriptorTableClause>(Elem).Space, (uint32_t)2);
 
   Elem = Elements[3];
   ASSERT_TRUE(std::holds_alternative<DescriptorTableClause>(Elem));
@@ -183,6 +186,7 @@ TEST_F(ParseHLSLRootSignatureTest, ValidParseDTClausesTest) 
{
   ASSERT_EQ(std::get<DescriptorTableClause>(Elem).Register.Number,
             (uint32_t)987234);
   ASSERT_EQ(std::get<DescriptorTableClause>(Elem).NumDescriptors, (uint32_t)1);
+  ASSERT_EQ(std::get<DescriptorTableClause>(Elem).Space, (uint32_t)0);
 
   Elem = Elements[4];
   ASSERT_TRUE(std::holds_alternative<DescriptorTable>(Elem));
diff --git a/llvm/include/llvm/Frontend/HLSL/HLSLRootSignature.h 
b/llvm/include/llvm/Frontend/HLSL/HLSLRootSignature.h
index abc5fe28db32a..f3abbb5a917a3 100644
--- a/llvm/include/llvm/Frontend/HLSL/HLSLRootSignature.h
+++ b/llvm/include/llvm/Frontend/HLSL/HLSLRootSignature.h
@@ -41,6 +41,7 @@ struct DescriptorTableClause {
   ClauseType Type;
   Register Register;
   uint32_t NumDescriptors = 1;
+  uint32_t Space = 0;
 };
 
 // Models RootElement : DescriptorTable | DescriptorTableClause

>From 76817892625b9681d46ade8f767681c2284aaa81 Mon Sep 17 00:00:00 2001
From: Finn Plummer <canadienf...@gmail.com>
Date: Tue, 28 Jan 2025 19:29:21 +0000
Subject: [PATCH 06/15] define custom paramtype for param parsing - descriptor
 range offset

---
 .../clang/Parse/ParseHLSLRootSignature.h      |  2 ++
 clang/lib/Parse/ParseHLSLRootSignature.cpp    | 20 +++++++++++++++++++
 .../Parse/ParseHLSLRootSignatureTest.cpp      | 12 +++++++++--
 .../llvm/Frontend/HLSL/HLSLRootSignature.h    |  9 ++++++++-
 4 files changed, 40 insertions(+), 3 deletions(-)

diff --git a/clang/include/clang/Parse/ParseHLSLRootSignature.h 
b/clang/include/clang/Parse/ParseHLSLRootSignature.h
index 3587d0acbd739..7e0f190695cb6 100644
--- a/clang/include/clang/Parse/ParseHLSLRootSignature.h
+++ b/clang/include/clang/Parse/ParseHLSLRootSignature.h
@@ -63,6 +63,8 @@ class RootSignatureParser {
   bool HandleUIntLiteral(uint32_t &X);
   bool ParseRegister(llvm::hlsl::rootsig::Register *Reg);
   bool ParseUInt(uint32_t *X);
+  bool
+  ParseDescriptorRangeOffset(llvm::hlsl::rootsig::DescriptorRangeOffset *X);
 
   /// Invoke the Lexer to consume a token and update CurToken with the result
   void ConsumeNextToken() { CurToken = Lexer.ConsumeToken(); }
diff --git a/clang/lib/Parse/ParseHLSLRootSignature.cpp 
b/clang/lib/Parse/ParseHLSLRootSignature.cpp
index 23731439c6766..b6d6efd8fd2d2 100644
--- a/clang/lib/Parse/ParseHLSLRootSignature.cpp
+++ b/clang/lib/Parse/ParseHLSLRootSignature.cpp
@@ -154,6 +154,7 @@ bool RootSignatureParser::ParseDescriptorTableClause() {
   llvm::SmallDenseMap<TokenKind, ParamType> RefMap = {
       {TokenKind::kw_numDescriptors, &Clause.NumDescriptors},
       {TokenKind::kw_space, &Clause.Space},
+      {TokenKind::kw_offset, &Clause.Offset},
   };
   if (ParseOptionalParams({RefMap}))
     return true;
@@ -178,6 +179,7 @@ bool RootSignatureParser::ParseParam(ParamType Ref) {
   bool Error;
   std::visit(ParseMethods{
     [&](uint32_t *X) { Error = ParseUInt(X); },
+    [&](DescriptorRangeOffset *X) { Error = ParseDescriptorRangeOffset(X); },
   }, Ref);
 
   return Error;
@@ -274,6 +276,24 @@ bool RootSignatureParser::ParseUInt(uint32_t *X) {
   return false;
 }
 
+bool RootSignatureParser::ParseDescriptorRangeOffset(DescriptorRangeOffset *X) 
{
+  if (ConsumeExpectedToken(
+          {TokenKind::int_literal, TokenKind::en_DescriptorRangeOffsetAppend}))
+    return true;
+
+  // Edge case for the offset enum -> static value
+  if (CurToken.Kind == TokenKind::en_DescriptorRangeOffsetAppend) {
+    *X = DescriptorTableOffsetAppend;
+    return false;
+  }
+
+  uint32_t Temp;
+  if (HandleUIntLiteral(Temp))
+    return true; // propogate NumericLiteralParser error
+  *X = DescriptorRangeOffset(Temp);
+  return false;
+}
+
 // Is given token one of the expected kinds
 static bool IsExpectedToken(TokenKind Kind, ArrayRef<TokenKind> AnyExpected) {
   for (auto Expected : AnyExpected)
diff --git a/clang/unittests/Parse/ParseHLSLRootSignatureTest.cpp 
b/clang/unittests/Parse/ParseHLSLRootSignatureTest.cpp
index 5ddc068410a88..1198a37223b87 100644
--- a/clang/unittests/Parse/ParseHLSLRootSignatureTest.cpp
+++ b/clang/unittests/Parse/ParseHLSLRootSignatureTest.cpp
@@ -130,8 +130,8 @@ TEST_F(ParseHLSLRootSignatureTest, ValidParseDTClausesTest) 
{
   const llvm::StringLiteral Source = R"cc(
     DescriptorTable(
       CBV(b0),
-      SRV(t42, space = 3, numDescriptors = +4),
-      Sampler(s987, space = 2),
+      SRV(t42, space = 3, offset = 32, numDescriptors = +4),
+      Sampler(s987, space = 2, offset = DESCRIPTOR_RANGE_OFFSET_APPEND),
       UAV(u987234)
     ),
     DescriptorTable()
@@ -157,6 +157,8 @@ TEST_F(ParseHLSLRootSignatureTest, ValidParseDTClausesTest) 
{
   ASSERT_EQ(std::get<DescriptorTableClause>(Elem).Register.Number, 
(uint32_t)0);
   ASSERT_EQ(std::get<DescriptorTableClause>(Elem).NumDescriptors, (uint32_t)1);
   ASSERT_EQ(std::get<DescriptorTableClause>(Elem).Space, (uint32_t)0);
+  ASSERT_EQ(std::get<DescriptorTableClause>(Elem).Offset,
+            DescriptorRangeOffset(DescriptorTableOffsetAppend));
 
   Elem = Elements[1];
   ASSERT_TRUE(std::holds_alternative<DescriptorTableClause>(Elem));
@@ -167,6 +169,8 @@ TEST_F(ParseHLSLRootSignatureTest, ValidParseDTClausesTest) 
{
             (uint32_t)42);
   ASSERT_EQ(std::get<DescriptorTableClause>(Elem).NumDescriptors, (uint32_t)4);
   ASSERT_EQ(std::get<DescriptorTableClause>(Elem).Space, (uint32_t)3);
+  ASSERT_EQ(std::get<DescriptorTableClause>(Elem).Offset,
+            DescriptorRangeOffset(32));
 
   Elem = Elements[2];
   ASSERT_TRUE(std::holds_alternative<DescriptorTableClause>(Elem));
@@ -177,6 +181,8 @@ TEST_F(ParseHLSLRootSignatureTest, ValidParseDTClausesTest) 
{
             (uint32_t)987);
   ASSERT_EQ(std::get<DescriptorTableClause>(Elem).NumDescriptors, (uint32_t)1);
   ASSERT_EQ(std::get<DescriptorTableClause>(Elem).Space, (uint32_t)2);
+  ASSERT_EQ(std::get<DescriptorTableClause>(Elem).Offset,
+            DescriptorRangeOffset(DescriptorTableOffsetAppend));
 
   Elem = Elements[3];
   ASSERT_TRUE(std::holds_alternative<DescriptorTableClause>(Elem));
@@ -187,6 +193,8 @@ TEST_F(ParseHLSLRootSignatureTest, ValidParseDTClausesTest) 
{
             (uint32_t)987234);
   ASSERT_EQ(std::get<DescriptorTableClause>(Elem).NumDescriptors, (uint32_t)1);
   ASSERT_EQ(std::get<DescriptorTableClause>(Elem).Space, (uint32_t)0);
+  ASSERT_EQ(std::get<DescriptorTableClause>(Elem).Offset,
+            DescriptorRangeOffset(DescriptorTableOffsetAppend));
 
   Elem = Elements[4];
   ASSERT_TRUE(std::holds_alternative<DescriptorTable>(Elem));
diff --git a/llvm/include/llvm/Frontend/HLSL/HLSLRootSignature.h 
b/llvm/include/llvm/Frontend/HLSL/HLSLRootSignature.h
index f3abbb5a917a3..1b23fed12ea14 100644
--- a/llvm/include/llvm/Frontend/HLSL/HLSLRootSignature.h
+++ b/llvm/include/llvm/Frontend/HLSL/HLSLRootSignature.h
@@ -21,6 +21,10 @@ namespace llvm {
 namespace hlsl {
 namespace rootsig {
 
+// Definition of the various enumerations and flags
+
+enum class DescriptorRangeOffset : uint32_t;
+
 // Definitions of the in-memory data layout structures
 
 // Models the different registers: bReg | tReg | uReg | sReg
@@ -35,6 +39,8 @@ struct DescriptorTable {
   uint32_t NumClauses = 0; // The number of clauses in the table
 };
 
+static const DescriptorRangeOffset DescriptorTableOffsetAppend =
+    DescriptorRangeOffset(0xffffffff);
 // Models DTClause : CBV | SRV | UAV | Sampler, by collecting like parameters
 using ClauseType = llvm::dxil::ResourceClass;
 struct DescriptorTableClause {
@@ -42,6 +48,7 @@ struct DescriptorTableClause {
   Register Register;
   uint32_t NumDescriptors = 1;
   uint32_t Space = 0;
+  DescriptorRangeOffset Offset = DescriptorTableOffsetAppend;
 };
 
 // Models RootElement : DescriptorTable | DescriptorTableClause
@@ -49,7 +56,7 @@ using RootElement = std::variant<DescriptorTable, 
DescriptorTableClause>;
 
 // Models a reference to all assignment parameter types that any RootElement
 // may have. Things of the form: Keyword = Param
-using ParamType = std::variant<uint32_t *>;
+using ParamType = std::variant<uint32_t *, DescriptorRangeOffset *>;
 
 } // namespace rootsig
 } // namespace hlsl

>From c3297af5f026c0d8be6e3c09f87dfb6780f3a25d Mon Sep 17 00:00:00 2001
From: Finn Plummer <canadienf...@gmail.com>
Date: Tue, 28 Jan 2025 19:38:57 +0000
Subject: [PATCH 07/15] add support for parsing enums

- uses Shader Visibility as an example for demonstrated test cases
---
 .../clang/Parse/ParseHLSLRootSignature.h      | 13 +++++
 clang/lib/Parse/ParseHLSLRootSignature.cpp    | 48 +++++++++++++++++++
 .../Parse/ParseHLSLRootSignatureTest.cpp      | 28 +++++++++++
 .../llvm/Frontend/HLSL/HLSLRootSignature.h    | 15 +++++-
 4 files changed, 103 insertions(+), 1 deletion(-)

diff --git a/clang/include/clang/Parse/ParseHLSLRootSignature.h 
b/clang/include/clang/Parse/ParseHLSLRootSignature.h
index 7e0f190695cb6..51048c077836c 100644
--- a/clang/include/clang/Parse/ParseHLSLRootSignature.h
+++ b/clang/include/clang/Parse/ParseHLSLRootSignature.h
@@ -66,6 +66,19 @@ class RootSignatureParser {
   bool
   ParseDescriptorRangeOffset(llvm::hlsl::rootsig::DescriptorRangeOffset *X);
 
+  /// Method for parsing any type of the ENUM defined token kinds (from
+  /// HLSLRootSignatureTokenKinds.def)
+  ///
+  /// EnumMap provides a mapping from the unique TokenKind to the in-memory
+  /// enum value
+  template <typename EnumType>
+  bool ParseEnum(llvm::SmallDenseMap<TokenKind, EnumType> &EnumMap,
+                 EnumType *Enum);
+
+  /// Helper methods that define the mappings and invoke ParseEnum for
+  /// different enum types
+  bool ParseShaderVisibility(llvm::hlsl::rootsig::ShaderVisibility *Enum);
+
   /// Invoke the Lexer to consume a token and update CurToken with the result
   void ConsumeNextToken() { CurToken = Lexer.ConsumeToken(); }
 
diff --git a/clang/lib/Parse/ParseHLSLRootSignature.cpp 
b/clang/lib/Parse/ParseHLSLRootSignature.cpp
index b6d6efd8fd2d2..c5cdf5fa6ce92 100644
--- a/clang/lib/Parse/ParseHLSLRootSignature.cpp
+++ b/clang/lib/Parse/ParseHLSLRootSignature.cpp
@@ -107,8 +107,23 @@ bool RootSignatureParser::ParseDescriptorTable() {
     return false;
   }
 
+  bool SeenVisibility = false;
   // Iterate through all the defined clauses
   do {
+    // Handle the visibility parameter
+    if (TryConsumeExpectedToken(TokenKind::kw_visibility)) {
+      if (SeenVisibility) {
+        Diags().Report(CurToken.TokLoc, diag::err_hlsl_rootsig_repeat_param)
+            << FormatTokenKinds(CurToken.Kind);
+        return true;
+      }
+      SeenVisibility = true;
+      if (ParseParam(&Table.Visibility))
+        return true;
+      continue;
+    }
+
+    // Otherwise, we expect a clause
     if (ParseDescriptorTableClause())
       return true;
     Table.NumClauses++;
@@ -180,6 +195,7 @@ bool RootSignatureParser::ParseParam(ParamType Ref) {
   std::visit(ParseMethods{
     [&](uint32_t *X) { Error = ParseUInt(X); },
     [&](DescriptorRangeOffset *X) { Error = ParseDescriptorRangeOffset(X); },
+    [&](ShaderVisibility *Enum) { Error = ParseShaderVisibility(Enum); },
   }, Ref);
 
   return Error;
@@ -294,6 +310,38 @@ bool 
RootSignatureParser::ParseDescriptorRangeOffset(DescriptorRangeOffset *X) {
   return false;
 }
 
+template <typename EnumType>
+bool RootSignatureParser::ParseEnum(
+    llvm::SmallDenseMap<TokenKind, EnumType> &EnumMap, EnumType *Enum) {
+  SmallVector<TokenKind> EnumToks;
+  for (auto EnumPair : EnumMap)
+    EnumToks.push_back(EnumPair.first);
+
+  // If invoked we expect to have an enum
+  if (ConsumeExpectedToken(EnumToks))
+    return true;
+
+  // Effectively a switch statement on the token kinds
+  for (auto EnumPair : EnumMap)
+    if (CurToken.Kind == EnumPair.first) {
+      *Enum = EnumPair.second;
+      return false;
+    }
+
+  llvm_unreachable("Switch for an expected token was not provided");
+}
+
+bool RootSignatureParser::ParseShaderVisibility(ShaderVisibility *Enum) {
+  // Define the possible flag kinds
+  llvm::SmallDenseMap<TokenKind, ShaderVisibility> EnumMap = {
+#define SHADER_VISIBILITY_ENUM(NAME, LIT)                                      
\
+  {TokenKind::en_##NAME, ShaderVisibility::NAME},
+#include "clang/Lex/HLSLRootSignatureTokenKinds.def"
+  };
+
+  return ParseEnum(EnumMap, Enum);
+}
+
 // Is given token one of the expected kinds
 static bool IsExpectedToken(TokenKind Kind, ArrayRef<TokenKind> AnyExpected) {
   for (auto Expected : AnyExpected)
diff --git a/clang/unittests/Parse/ParseHLSLRootSignatureTest.cpp 
b/clang/unittests/Parse/ParseHLSLRootSignatureTest.cpp
index 1198a37223b87..a4b783a7a83fa 100644
--- a/clang/unittests/Parse/ParseHLSLRootSignatureTest.cpp
+++ b/clang/unittests/Parse/ParseHLSLRootSignatureTest.cpp
@@ -129,6 +129,7 @@ TEST_F(ParseHLSLRootSignatureTest, ValidParseEmptyTest) {
 TEST_F(ParseHLSLRootSignatureTest, ValidParseDTClausesTest) {
   const llvm::StringLiteral Source = R"cc(
     DescriptorTable(
+      visibility = SHADER_VISIBILITY_PIXEL,
       CBV(b0),
       SRV(t42, space = 3, offset = 32, numDescriptors = +4),
       Sampler(s987, space = 2, offset = DESCRIPTOR_RANGE_OFFSET_APPEND),
@@ -199,11 +200,15 @@ TEST_F(ParseHLSLRootSignatureTest, 
ValidParseDTClausesTest) {
   Elem = Elements[4];
   ASSERT_TRUE(std::holds_alternative<DescriptorTable>(Elem));
   ASSERT_EQ(std::get<DescriptorTable>(Elem).NumClauses, (uint32_t)4);
+  ASSERT_EQ(std::get<DescriptorTable>(Elem).Visibility,
+            ShaderVisibility::Pixel);
 
   Elem = Elements[5];
   // Test generated DescriptorTable start has correct default values
   ASSERT_TRUE(std::holds_alternative<DescriptorTable>(Elem));
   ASSERT_EQ(std::get<DescriptorTable>(Elem).NumClauses, 0u);
+  ASSERT_EQ(std::get<DescriptorTable>(Elem).Visibility, ShaderVisibility::All);
+
   ASSERT_TRUE(Consumer->IsSatisfied());
 }
 
@@ -313,4 +318,27 @@ TEST_F(ParseHLSLRootSignatureTest, 
InvalidParseRepeatedParamTest) {
   ASSERT_TRUE(Consumer->IsSatisfied());
 }
 
+TEST_F(ParseHLSLRootSignatureTest, InvalidParseRepeatedVisibilityTest) {
+  const llvm::StringLiteral Source = R"cc(
+    DescriptorTable(
+      visibility = SHADER_VISIBILITY_GEOMETRY,
+      visibility = SHADER_VISIBILITY_HULL
+    )
+  )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 correct diagnostic produced
+  Consumer->SetExpected(diag::err_hlsl_rootsig_repeat_param);
+  ASSERT_TRUE(Parser.Parse());
+
+  ASSERT_TRUE(Consumer->IsSatisfied());
+}
+
 } // anonymous namespace
diff --git a/llvm/include/llvm/Frontend/HLSL/HLSLRootSignature.h 
b/llvm/include/llvm/Frontend/HLSL/HLSLRootSignature.h
index 1b23fed12ea14..a405c75f8c343 100644
--- a/llvm/include/llvm/Frontend/HLSL/HLSLRootSignature.h
+++ b/llvm/include/llvm/Frontend/HLSL/HLSLRootSignature.h
@@ -25,6 +25,17 @@ namespace rootsig {
 
 enum class DescriptorRangeOffset : uint32_t;
 
+enum class ShaderVisibility {
+  All = 0,
+  Vertex = 1,
+  Hull = 2,
+  Domain = 3,
+  Geometry = 4,
+  Pixel = 5,
+  Amplification = 6,
+  Mesh = 7,
+};
+
 // Definitions of the in-memory data layout structures
 
 // Models the different registers: bReg | tReg | uReg | sReg
@@ -36,6 +47,7 @@ struct Register {
 
 // 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
 };
 
@@ -56,7 +68,8 @@ using RootElement = std::variant<DescriptorTable, 
DescriptorTableClause>;
 
 // Models a reference to all assignment parameter types that any RootElement
 // may have. Things of the form: Keyword = Param
-using ParamType = std::variant<uint32_t *, DescriptorRangeOffset *>;
+using ParamType = std::variant<uint32_t *, DescriptorRangeOffset *,
+                               ShaderVisibility *>;
 
 } // namespace rootsig
 } // namespace hlsl

>From 8a902fd5a6f4bb82b8e570ab22eb8cf273ce9723 Mon Sep 17 00:00:00 2001
From: Finn Plummer <canadienf...@gmail.com>
Date: Tue, 28 Jan 2025 19:46:34 +0000
Subject: [PATCH 08/15] add support for parsing flags

- use descriptor range flags as an example
---
 .../clang/Basic/DiagnosticParseKinds.td       |  2 +
 .../clang/Parse/ParseHLSLRootSignature.h      | 16 +++++-
 clang/lib/Parse/ParseHLSLRootSignature.cpp    | 51 +++++++++++++++++-
 .../Parse/ParseHLSLRootSignatureTest.cpp      | 38 ++++++++++++-
 .../llvm/Frontend/HLSL/HLSLRootSignature.h    | 53 ++++++++++++++++++-
 5 files changed, 155 insertions(+), 5 deletions(-)

diff --git a/clang/include/clang/Basic/DiagnosticParseKinds.td 
b/clang/include/clang/Basic/DiagnosticParseKinds.td
index ce0da28df3976..fe1b0dd0b91cb 100644
--- a/clang/include/clang/Basic/DiagnosticParseKinds.td
+++ b/clang/include/clang/Basic/DiagnosticParseKinds.td
@@ -1822,4 +1822,6 @@ def err_hlsl_packoffset_invalid_reg : Error<"invalid 
resource class specifier '%
 def err_hlsl_rootsig_unexpected_token_kind : Error<"got %1 but expected 
%select{|one of}0 the following token kind%select{|s}0: %2">;
 def err_hlsl_number_literal_overflow : Error<"integer literal is too large to 
be represented as a 32-bit %select{signed |}0 integer type">;
 def err_hlsl_rootsig_repeat_param : Error<"specified the same parameter '%0' 
multiple times">;
+def err_hlsl_rootsig_non_zero_flag : Error<"specified a non-zero integer as a 
flag">;
+
 } // end of Parser diagnostics
diff --git a/clang/include/clang/Parse/ParseHLSLRootSignature.h 
b/clang/include/clang/Parse/ParseHLSLRootSignature.h
index 51048c077836c..c4fb03a3bc3ed 100644
--- a/clang/include/clang/Parse/ParseHLSLRootSignature.h
+++ b/clang/include/clang/Parse/ParseHLSLRootSignature.h
@@ -71,7 +71,10 @@ class RootSignatureParser {
   ///
   /// EnumMap provides a mapping from the unique TokenKind to the in-memory
   /// enum value
-  template <typename EnumType>
+  ///
+  /// If AllowZero is true, then the Enum is used as a flag and can also have
+  /// the value of '0' to denote no flag
+  template <bool AllowZero = false, typename EnumType>
   bool ParseEnum(llvm::SmallDenseMap<TokenKind, EnumType> &EnumMap,
                  EnumType *Enum);
 
@@ -79,6 +82,17 @@ class RootSignatureParser {
   /// different enum types
   bool ParseShaderVisibility(llvm::hlsl::rootsig::ShaderVisibility *Enum);
 
+  /// A wrapper method around ParseEnum that will parse an 'or' chain of
+  /// enums, with AllowZero = true
+  template <typename FlagType>
+  bool ParseFlags(llvm::SmallDenseMap<TokenKind, FlagType> &EnumMap,
+                  FlagType *Enum);
+
+  /// Helper methods that define the mappings and invoke ParseFlags for
+  /// different enum types
+  bool
+  ParseDescriptorRangeFlags(llvm::hlsl::rootsig::DescriptorRangeFlags *Enum);
+
   /// Invoke the Lexer to consume a token and update CurToken with the result
   void ConsumeNextToken() { CurToken = Lexer.ConsumeToken(); }
 
diff --git a/clang/lib/Parse/ParseHLSLRootSignature.cpp 
b/clang/lib/Parse/ParseHLSLRootSignature.cpp
index c5cdf5fa6ce92..e2564228de897 100644
--- a/clang/lib/Parse/ParseHLSLRootSignature.cpp
+++ b/clang/lib/Parse/ParseHLSLRootSignature.cpp
@@ -158,6 +158,8 @@ bool RootSignatureParser::ParseDescriptorTableClause() {
   default:
     llvm_unreachable("Switch for an expected token was not provided");
   }
+  Clause.SetDefaultFlags();
+
   if (ConsumeExpectedToken(TokenKind::pu_l_paren))
     return true;
 
@@ -170,6 +172,7 @@ bool RootSignatureParser::ParseDescriptorTableClause() {
       {TokenKind::kw_numDescriptors, &Clause.NumDescriptors},
       {TokenKind::kw_space, &Clause.Space},
       {TokenKind::kw_offset, &Clause.Offset},
+      {TokenKind::kw_flags, &Clause.Flags},
   };
   if (ParseOptionalParams({RefMap}))
     return true;
@@ -196,6 +199,7 @@ bool RootSignatureParser::ParseParam(ParamType Ref) {
     [&](uint32_t *X) { Error = ParseUInt(X); },
     [&](DescriptorRangeOffset *X) { Error = ParseDescriptorRangeOffset(X); },
     [&](ShaderVisibility *Enum) { Error = ParseShaderVisibility(Enum); },
+    [&](DescriptorRangeFlags *Flags) { Error = 
ParseDescriptorRangeFlags(Flags); },
   }, Ref);
 
   return Error;
@@ -310,10 +314,12 @@ bool 
RootSignatureParser::ParseDescriptorRangeOffset(DescriptorRangeOffset *X) {
   return false;
 }
 
-template <typename EnumType>
+template <bool AllowZero, typename EnumType>
 bool RootSignatureParser::ParseEnum(
     llvm::SmallDenseMap<TokenKind, EnumType> &EnumMap, EnumType *Enum) {
   SmallVector<TokenKind> EnumToks;
+  if (AllowZero)
+    EnumToks.push_back(TokenKind::int_literal); //  '0' is a valid flag value
   for (auto EnumPair : EnumMap)
     EnumToks.push_back(EnumPair.first);
 
@@ -321,6 +327,20 @@ bool RootSignatureParser::ParseEnum(
   if (ConsumeExpectedToken(EnumToks))
     return true;
 
+  // Handle the edge case when '0' is used to specify None
+  if (CurToken.Kind == TokenKind::int_literal) {
+    uint32_t Temp;
+    if (HandleUIntLiteral(Temp))
+      return true; // propogate NumericLiteralParser error
+    if (Temp != 0) {
+      Diags().Report(CurToken.TokLoc, diag::err_hlsl_rootsig_non_zero_flag);
+      return true;
+    }
+    // Set enum to None equivalent
+    *Enum = EnumType(0);
+    return false;
+  }
+
   // Effectively a switch statement on the token kinds
   for (auto EnumPair : EnumMap)
     if (CurToken.Kind == EnumPair.first) {
@@ -342,6 +362,35 @@ bool 
RootSignatureParser::ParseShaderVisibility(ShaderVisibility *Enum) {
   return ParseEnum(EnumMap, Enum);
 }
 
+template <typename FlagType>
+bool RootSignatureParser::ParseFlags(
+    llvm::SmallDenseMap<TokenKind, FlagType> &FlagMap, FlagType *Flags) {
+  // Override the default value to 0 so that we can correctly 'or' the values
+  *Flags = FlagType(0);
+
+  do {
+    FlagType Flag;
+    if (ParseEnum<true>(FlagMap, &Flag))
+      return true;
+    // Store the 'or'
+    *Flags |= Flag;
+  } while (TryConsumeExpectedToken(TokenKind::pu_or));
+
+  return false;
+}
+
+bool RootSignatureParser::ParseDescriptorRangeFlags(
+    DescriptorRangeFlags *Flags) {
+  // Define the possible flag kinds
+  llvm::SmallDenseMap<TokenKind, DescriptorRangeFlags> FlagMap = {
+#define DESCRIPTOR_RANGE_FLAG_ENUM(NAME, LIT, ON)                              
\
+  {TokenKind::en_##NAME, DescriptorRangeFlags::NAME},
+#include "clang/Lex/HLSLRootSignatureTokenKinds.def"
+  };
+
+  return ParseFlags(FlagMap, Flags);
+}
+
 // Is given token one of the expected kinds
 static bool IsExpectedToken(TokenKind Kind, ArrayRef<TokenKind> AnyExpected) {
   for (auto Expected : AnyExpected)
diff --git a/clang/unittests/Parse/ParseHLSLRootSignatureTest.cpp 
b/clang/unittests/Parse/ParseHLSLRootSignatureTest.cpp
index a4b783a7a83fa..8fe57244142b0 100644
--- a/clang/unittests/Parse/ParseHLSLRootSignatureTest.cpp
+++ b/clang/unittests/Parse/ParseHLSLRootSignatureTest.cpp
@@ -131,9 +131,13 @@ TEST_F(ParseHLSLRootSignatureTest, 
ValidParseDTClausesTest) {
     DescriptorTable(
       visibility = SHADER_VISIBILITY_PIXEL,
       CBV(b0),
-      SRV(t42, space = 3, offset = 32, numDescriptors = +4),
+      SRV(t42, space = 3, offset = 32, numDescriptors = +4, flags = 0),
       Sampler(s987, space = 2, offset = DESCRIPTOR_RANGE_OFFSET_APPEND),
-      UAV(u987234)
+      UAV(u987234,
+        flags = Descriptors_Volatile | Data_Volatile
+                      | Data_Static_While_Set_At_Execute | Data_Static
+                      | Descriptors_Static_Keeping_Buffer_Bounds_Checks
+      )
     ),
     DescriptorTable()
   )cc";
@@ -160,6 +164,8 @@ TEST_F(ParseHLSLRootSignatureTest, ValidParseDTClausesTest) 
{
   ASSERT_EQ(std::get<DescriptorTableClause>(Elem).Space, (uint32_t)0);
   ASSERT_EQ(std::get<DescriptorTableClause>(Elem).Offset,
             DescriptorRangeOffset(DescriptorTableOffsetAppend));
+  ASSERT_EQ(std::get<DescriptorTableClause>(Elem).Flags,
+            DescriptorRangeFlags::DataStaticWhileSetAtExecute);
 
   Elem = Elements[1];
   ASSERT_TRUE(std::holds_alternative<DescriptorTableClause>(Elem));
@@ -172,6 +178,8 @@ TEST_F(ParseHLSLRootSignatureTest, ValidParseDTClausesTest) 
{
   ASSERT_EQ(std::get<DescriptorTableClause>(Elem).Space, (uint32_t)3);
   ASSERT_EQ(std::get<DescriptorTableClause>(Elem).Offset,
             DescriptorRangeOffset(32));
+  ASSERT_EQ(std::get<DescriptorTableClause>(Elem).Flags,
+            DescriptorRangeFlags::None);
 
   Elem = Elements[2];
   ASSERT_TRUE(std::holds_alternative<DescriptorTableClause>(Elem));
@@ -184,6 +192,8 @@ TEST_F(ParseHLSLRootSignatureTest, ValidParseDTClausesTest) 
{
   ASSERT_EQ(std::get<DescriptorTableClause>(Elem).Space, (uint32_t)2);
   ASSERT_EQ(std::get<DescriptorTableClause>(Elem).Offset,
             DescriptorRangeOffset(DescriptorTableOffsetAppend));
+  ASSERT_EQ(std::get<DescriptorTableClause>(Elem).Flags,
+            DescriptorRangeFlags::None);
 
   Elem = Elements[3];
   ASSERT_TRUE(std::holds_alternative<DescriptorTableClause>(Elem));
@@ -196,6 +206,8 @@ TEST_F(ParseHLSLRootSignatureTest, ValidParseDTClausesTest) 
{
   ASSERT_EQ(std::get<DescriptorTableClause>(Elem).Space, (uint32_t)0);
   ASSERT_EQ(std::get<DescriptorTableClause>(Elem).Offset,
             DescriptorRangeOffset(DescriptorTableOffsetAppend));
+  ASSERT_EQ(std::get<DescriptorTableClause>(Elem).Flags,
+            DescriptorRangeFlags::ValidFlags);
 
   Elem = Elements[4];
   ASSERT_TRUE(std::holds_alternative<DescriptorTable>(Elem));
@@ -341,4 +353,26 @@ TEST_F(ParseHLSLRootSignatureTest, 
InvalidParseRepeatedVisibilityTest) {
   ASSERT_TRUE(Consumer->IsSatisfied());
 }
 
+TEST_F(ParseHLSLRootSignatureTest, InvalidParseNonZeroFlagTest) {
+  const llvm::StringLiteral Source = R"cc(
+    DescriptorTable(
+      CBV(b0, flags = 3)
+    )
+  )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 correct diagnostic produced
+  Consumer->SetExpected(diag::err_hlsl_rootsig_non_zero_flag);
+  ASSERT_TRUE(Parser.Parse());
+
+  ASSERT_TRUE(Consumer->IsSatisfied());
+}
+
 } // anonymous namespace
diff --git a/llvm/include/llvm/Frontend/HLSL/HLSLRootSignature.h 
b/llvm/include/llvm/Frontend/HLSL/HLSLRootSignature.h
index a405c75f8c343..f999a0b5eef33 100644
--- a/llvm/include/llvm/Frontend/HLSL/HLSLRootSignature.h
+++ b/llvm/include/llvm/Frontend/HLSL/HLSLRootSignature.h
@@ -21,10 +21,43 @@ namespace llvm {
 namespace hlsl {
 namespace rootsig {
 
+#define RS_DEFINE_ENUM_CLASS_FLAGS_OPERATORS(Class)                            
\
+  inline Class operator|(Class a, Class b) {                                   
\
+    return static_cast<Class>(llvm::to_underlying(a) |                         
\
+                              llvm::to_underlying(b));                         
\
+  }                                                                            
\
+  inline Class operator&(Class a, Class b) {                                   
\
+    return static_cast<Class>(llvm::to_underlying(a) &                         
\
+                              llvm::to_underlying(b));                         
\
+  }                                                                            
\
+  inline Class operator~(Class a) {                                            
\
+    return static_cast<Class>(~llvm::to_underlying(a));                        
\
+  }                                                                            
\
+  inline Class &operator|=(Class &a, Class b) {                                
\
+    a = a | b;                                                                 
\
+    return a;                                                                  
\
+  }                                                                            
\
+  inline Class &operator&=(Class &a, Class b) {                                
\
+    a = a & b;                                                                 
\
+    return a;                                                                  
\
+  }
+
 // Definition of the various enumerations and flags
 
 enum class DescriptorRangeOffset : uint32_t;
 
+enum class DescriptorRangeFlags : unsigned {
+  None = 0,
+  DescriptorsVolatile = 0x1,
+  DataVolatile = 0x2,
+  DataStaticWhileSetAtExecute = 0x4,
+  DataStatic = 0x8,
+  DescriptorsStaticKeepingBufferBoundsChecks = 0x10000,
+  ValidFlags = 0x1000f,
+  ValidSamplerFlags = DescriptorsVolatile,
+};
+RS_DEFINE_ENUM_CLASS_FLAGS_OPERATORS(DescriptorRangeFlags)
+
 enum class ShaderVisibility {
   All = 0,
   Vertex = 1,
@@ -61,6 +94,24 @@ struct DescriptorTableClause {
   uint32_t NumDescriptors = 1;
   uint32_t Space = 0;
   DescriptorRangeOffset Offset = DescriptorTableOffsetAppend;
+  DescriptorRangeFlags Flags;
+
+  void SetDefaultFlags() {
+    switch (Type) {
+    case ClauseType::CBuffer:
+      Flags = DescriptorRangeFlags::DataStaticWhileSetAtExecute;
+      break;
+    case ClauseType::SRV:
+      Flags = DescriptorRangeFlags::DataStaticWhileSetAtExecute;
+      break;
+    case ClauseType::UAV:
+      Flags = DescriptorRangeFlags::DataVolatile;
+      break;
+    case ClauseType::Sampler:
+      Flags = DescriptorRangeFlags::None;
+      break;
+    }
+  }
 };
 
 // Models RootElement : DescriptorTable | DescriptorTableClause
@@ -69,7 +120,7 @@ using RootElement = std::variant<DescriptorTable, 
DescriptorTableClause>;
 // Models a reference to all assignment parameter types that any RootElement
 // may have. Things of the form: Keyword = Param
 using ParamType = std::variant<uint32_t *, DescriptorRangeOffset *,
-                               ShaderVisibility *>;
+                               DescriptorRangeFlags *, ShaderVisibility *>;
 
 } // namespace rootsig
 } // namespace hlsl

>From 2d763fe285d44c1165366d5104727e71d9da9f3f Mon Sep 17 00:00:00 2001
From: Finn Plummer <canadienf...@gmail.com>
Date: Fri, 14 Feb 2025 19:03:33 +0000
Subject: [PATCH 09/15] clang formatting

---
 .../clang/Parse/ParseHLSLRootSignature.h      |  2 +-
 clang/lib/Parse/ParseHLSLRootSignature.cpp    | 25 +++++++++++--------
 2 files changed, 15 insertions(+), 12 deletions(-)

diff --git a/clang/include/clang/Parse/ParseHLSLRootSignature.h 
b/clang/include/clang/Parse/ParseHLSLRootSignature.h
index c4fb03a3bc3ed..8ba5ceaceac98 100644
--- a/clang/include/clang/Parse/ParseHLSLRootSignature.h
+++ b/clang/include/clang/Parse/ParseHLSLRootSignature.h
@@ -14,8 +14,8 @@
 #define LLVM_CLANG_PARSE_PARSEHLSLROOTSIGNATURE_H
 
 #include "clang/Basic/DiagnosticParse.h"
-#include "clang/Lex/Preprocessor.h"
 #include "clang/Lex/LexHLSLRootSignature.h"
+#include "clang/Lex/Preprocessor.h"
 
 #include "llvm/ADT/SmallVector.h"
 #include "llvm/ADT/StringRef.h"
diff --git a/clang/lib/Parse/ParseHLSLRootSignature.cpp 
b/clang/lib/Parse/ParseHLSLRootSignature.cpp
index e2564228de897..707a37dbad802 100644
--- a/clang/lib/Parse/ParseHLSLRootSignature.cpp
+++ b/clang/lib/Parse/ParseHLSLRootSignature.cpp
@@ -185,9 +185,7 @@ bool RootSignatureParser::ParseDescriptorTableClause() {
 }
 
 // Helper struct so that we can use the overloaded notation of std::visit
-template <class... Ts> struct ParseMethods : Ts... {
-  using Ts::operator()...;
-};
+template <class... Ts> struct ParseMethods : Ts... { using Ts::operator()...; 
};
 template <class... Ts> ParseMethods(Ts...) -> ParseMethods<Ts...>;
 
 bool RootSignatureParser::ParseParam(ParamType Ref) {
@@ -195,12 +193,18 @@ bool RootSignatureParser::ParseParam(ParamType Ref) {
     return true;
 
   bool Error;
-  std::visit(ParseMethods{
-    [&](uint32_t *X) { Error = ParseUInt(X); },
-    [&](DescriptorRangeOffset *X) { Error = ParseDescriptorRangeOffset(X); },
-    [&](ShaderVisibility *Enum) { Error = ParseShaderVisibility(Enum); },
-    [&](DescriptorRangeFlags *Flags) { Error = 
ParseDescriptorRangeFlags(Flags); },
-  }, Ref);
+  std::visit(
+      ParseMethods{
+          [&](uint32_t *X) { Error = ParseUInt(X); },
+          [&](DescriptorRangeOffset *X) {
+            Error = ParseDescriptorRangeOffset(X);
+          },
+          [&](ShaderVisibility *Enum) { Error = ParseShaderVisibility(Enum); },
+          [&](DescriptorRangeFlags *Flags) {
+            Error = ParseDescriptorRangeFlags(Flags);
+          },
+      },
+      Ref);
 
   return Error;
 }
@@ -421,8 +425,7 @@ bool RootSignatureParser::ConsumeExpectedToken(
   // Report unexpected token kind error
   Diags().Report(CurToken.TokLoc, diag::err_hlsl_rootsig_unexpected_token_kind)
       << (unsigned)(AnyExpected.size() != 1)
-      << FormatTokenKinds({CurToken.Kind})
-      << FormatTokenKinds(AnyExpected);
+      << FormatTokenKinds({CurToken.Kind}) << FormatTokenKinds(AnyExpected);
   return true;
 }
 

>From 1d078242ac1f025f209d97268473c12a75d13ef7 Mon Sep 17 00:00:00 2001
From: Finn Plummer <canadienf...@gmail.com>
Date: Fri, 14 Feb 2025 19:04:17 +0000
Subject: [PATCH 10/15] review: remove unreachable return true

---
 clang/lib/Parse/ParseHLSLRootSignature.cpp | 5 ++---
 1 file changed, 2 insertions(+), 3 deletions(-)

diff --git a/clang/lib/Parse/ParseHLSLRootSignature.cpp 
b/clang/lib/Parse/ParseHLSLRootSignature.cpp
index 707a37dbad802..e8e637c1b7977 100644
--- a/clang/lib/Parse/ParseHLSLRootSignature.cpp
+++ b/clang/lib/Parse/ParseHLSLRootSignature.cpp
@@ -89,10 +89,9 @@ bool RootSignatureParser::ParseRootElement() {
   switch (CurToken.Kind) {
   case TokenKind::kw_DescriptorTable:
     return ParseDescriptorTable();
-  default:
-    llvm_unreachable("Switch for an expected token was not provided");
+  default: break;
   }
-  return true;
+  llvm_unreachable("Switch for an expected token was not provided");
 }
 
 bool RootSignatureParser::ParseDescriptorTable() {

>From f78fdfab5d2ce89b24173c51f8ea56cd086eea85 Mon Sep 17 00:00:00 2001
From: Finn Plummer <canadienf...@gmail.com>
Date: Fri, 14 Feb 2025 19:08:24 +0000
Subject: [PATCH 11/15] review: clean-up casting of test values

---
 clang/lib/Parse/ParseHLSLRootSignature.cpp    |  3 +-
 .../Parse/ParseHLSLRootSignatureTest.cpp      | 31 +++++++++----------
 2 files changed, 16 insertions(+), 18 deletions(-)

diff --git a/clang/lib/Parse/ParseHLSLRootSignature.cpp 
b/clang/lib/Parse/ParseHLSLRootSignature.cpp
index e8e637c1b7977..5bbb35875ceb5 100644
--- a/clang/lib/Parse/ParseHLSLRootSignature.cpp
+++ b/clang/lib/Parse/ParseHLSLRootSignature.cpp
@@ -89,7 +89,8 @@ bool RootSignatureParser::ParseRootElement() {
   switch (CurToken.Kind) {
   case TokenKind::kw_DescriptorTable:
     return ParseDescriptorTable();
-  default: break;
+  default:
+    break;
   }
   llvm_unreachable("Switch for an expected token was not provided");
 }
diff --git a/clang/unittests/Parse/ParseHLSLRootSignatureTest.cpp 
b/clang/unittests/Parse/ParseHLSLRootSignatureTest.cpp
index 8fe57244142b0..224e16bfa372b 100644
--- a/clang/unittests/Parse/ParseHLSLRootSignatureTest.cpp
+++ b/clang/unittests/Parse/ParseHLSLRootSignatureTest.cpp
@@ -121,7 +121,7 @@ TEST_F(ParseHLSLRootSignatureTest, ValidParseEmptyTest) {
   Consumer->SetNoDiag();
 
   ASSERT_FALSE(Parser.Parse());
-  ASSERT_EQ((int)Elements.size(), 0);
+  ASSERT_EQ(Elements.size(), 0u);
 
   ASSERT_TRUE(Consumer->IsSatisfied());
 }
@@ -159,9 +159,9 @@ TEST_F(ParseHLSLRootSignatureTest, ValidParseDTClausesTest) 
{
   ASSERT_EQ(std::get<DescriptorTableClause>(Elem).Type, ClauseType::CBuffer);
   ASSERT_EQ(std::get<DescriptorTableClause>(Elem).Register.ViewType,
             RegisterType::BReg);
-  ASSERT_EQ(std::get<DescriptorTableClause>(Elem).Register.Number, 
(uint32_t)0);
-  ASSERT_EQ(std::get<DescriptorTableClause>(Elem).NumDescriptors, (uint32_t)1);
-  ASSERT_EQ(std::get<DescriptorTableClause>(Elem).Space, (uint32_t)0);
+  ASSERT_EQ(std::get<DescriptorTableClause>(Elem).Register.Number, 0u);
+  ASSERT_EQ(std::get<DescriptorTableClause>(Elem).NumDescriptors, 1u);
+  ASSERT_EQ(std::get<DescriptorTableClause>(Elem).Space, 0u);
   ASSERT_EQ(std::get<DescriptorTableClause>(Elem).Offset,
             DescriptorRangeOffset(DescriptorTableOffsetAppend));
   ASSERT_EQ(std::get<DescriptorTableClause>(Elem).Flags,
@@ -172,10 +172,9 @@ TEST_F(ParseHLSLRootSignatureTest, 
ValidParseDTClausesTest) {
   ASSERT_EQ(std::get<DescriptorTableClause>(Elem).Type, ClauseType::SRV);
   ASSERT_EQ(std::get<DescriptorTableClause>(Elem).Register.ViewType,
             RegisterType::TReg);
-  ASSERT_EQ(std::get<DescriptorTableClause>(Elem).Register.Number,
-            (uint32_t)42);
-  ASSERT_EQ(std::get<DescriptorTableClause>(Elem).NumDescriptors, (uint32_t)4);
-  ASSERT_EQ(std::get<DescriptorTableClause>(Elem).Space, (uint32_t)3);
+  ASSERT_EQ(std::get<DescriptorTableClause>(Elem).Register.Number, 42u);
+  ASSERT_EQ(std::get<DescriptorTableClause>(Elem).NumDescriptors, 4u);
+  ASSERT_EQ(std::get<DescriptorTableClause>(Elem).Space, 3u);
   ASSERT_EQ(std::get<DescriptorTableClause>(Elem).Offset,
             DescriptorRangeOffset(32));
   ASSERT_EQ(std::get<DescriptorTableClause>(Elem).Flags,
@@ -186,10 +185,9 @@ TEST_F(ParseHLSLRootSignatureTest, 
ValidParseDTClausesTest) {
   ASSERT_EQ(std::get<DescriptorTableClause>(Elem).Type, ClauseType::Sampler);
   ASSERT_EQ(std::get<DescriptorTableClause>(Elem).Register.ViewType,
             RegisterType::SReg);
-  ASSERT_EQ(std::get<DescriptorTableClause>(Elem).Register.Number,
-            (uint32_t)987);
-  ASSERT_EQ(std::get<DescriptorTableClause>(Elem).NumDescriptors, (uint32_t)1);
-  ASSERT_EQ(std::get<DescriptorTableClause>(Elem).Space, (uint32_t)2);
+  ASSERT_EQ(std::get<DescriptorTableClause>(Elem).Register.Number, 987u);
+  ASSERT_EQ(std::get<DescriptorTableClause>(Elem).NumDescriptors, 1u);
+  ASSERT_EQ(std::get<DescriptorTableClause>(Elem).Space, 2u);
   ASSERT_EQ(std::get<DescriptorTableClause>(Elem).Offset,
             DescriptorRangeOffset(DescriptorTableOffsetAppend));
   ASSERT_EQ(std::get<DescriptorTableClause>(Elem).Flags,
@@ -200,10 +198,9 @@ TEST_F(ParseHLSLRootSignatureTest, 
ValidParseDTClausesTest) {
   ASSERT_EQ(std::get<DescriptorTableClause>(Elem).Type, ClauseType::UAV);
   ASSERT_EQ(std::get<DescriptorTableClause>(Elem).Register.ViewType,
             RegisterType::UReg);
-  ASSERT_EQ(std::get<DescriptorTableClause>(Elem).Register.Number,
-            (uint32_t)987234);
-  ASSERT_EQ(std::get<DescriptorTableClause>(Elem).NumDescriptors, (uint32_t)1);
-  ASSERT_EQ(std::get<DescriptorTableClause>(Elem).Space, (uint32_t)0);
+  ASSERT_EQ(std::get<DescriptorTableClause>(Elem).Register.Number, 987234u);
+  ASSERT_EQ(std::get<DescriptorTableClause>(Elem).NumDescriptors, 1u);
+  ASSERT_EQ(std::get<DescriptorTableClause>(Elem).Space, 0u);
   ASSERT_EQ(std::get<DescriptorTableClause>(Elem).Offset,
             DescriptorRangeOffset(DescriptorTableOffsetAppend));
   ASSERT_EQ(std::get<DescriptorTableClause>(Elem).Flags,
@@ -211,7 +208,7 @@ TEST_F(ParseHLSLRootSignatureTest, ValidParseDTClausesTest) 
{
 
   Elem = Elements[4];
   ASSERT_TRUE(std::holds_alternative<DescriptorTable>(Elem));
-  ASSERT_EQ(std::get<DescriptorTable>(Elem).NumClauses, (uint32_t)4);
+  ASSERT_EQ(std::get<DescriptorTable>(Elem).NumClauses, 4u);
   ASSERT_EQ(std::get<DescriptorTable>(Elem).Visibility,
             ShaderVisibility::Pixel);
 

>From fda500ca8ebe693caa18b434d86ef07c225a90a9 Mon Sep 17 00:00:00 2001
From: Finn Plummer <canadienf...@gmail.com>
Date: Fri, 14 Feb 2025 19:18:55 +0000
Subject: [PATCH 12/15] self-review: update doc

---
 clang/include/clang/Parse/ParseHLSLRootSignature.h | 12 +++++++++++-
 1 file changed, 11 insertions(+), 1 deletion(-)

diff --git a/clang/include/clang/Parse/ParseHLSLRootSignature.h 
b/clang/include/clang/Parse/ParseHLSLRootSignature.h
index 8ba5ceaceac98..89a02d88d6dfc 100644
--- a/clang/include/clang/Parse/ParseHLSLRootSignature.h
+++ b/clang/include/clang/Parse/ParseHLSLRootSignature.h
@@ -40,7 +40,17 @@ class RootSignatureParser {
   DiagnosticsEngine &Diags() { return PP.getDiagnostics(); }
 
 private:
-  // Root Element helpers
+  /// All private Parse.* methods follow a similar pattern:
+  ///   - Each method will expect that the the next token is of a certain kind
+  /// and will invoke `ConsumeExpectedToken`
+  ///   - As such, an error will be raised if the proceeding tokens are not
+  /// what is expected
+  ///   - Therefore, it is the callers responsibility to ensure that you are
+  /// expecting the next element type. Or equivalently, the methods should not
+  /// be called as a way to try and parse an element
+  ///   - All methods return true if a parsing error is encountered. It is the
+  /// callers responsibility to propogate this error up, or deal with it
+  /// otherwise
   bool ParseRootElement();
   bool ParseDescriptorTable();
   bool ParseDescriptorTableClause();

>From d99c599a0b144336243a3788d107bc6e057c7504 Mon Sep 17 00:00:00 2001
From: Finn Plummer <canadienf...@gmail.com>
Date: Fri, 14 Feb 2025 19:44:36 +0000
Subject: [PATCH 13/15] self-review: move token spellings to definition

---
 .../clang/Lex/HLSLRootSignatureTokenKinds.def | 22 ++++++------
 .../include/clang/Lex/LexHLSLRootSignature.h  |  2 +-
 clang/lib/Parse/ParseHLSLRootSignature.cpp    | 35 ++-----------------
 .../Lex/LexHLSLRootSignatureTest.cpp          |  2 +-
 4 files changed, 16 insertions(+), 45 deletions(-)

diff --git a/clang/include/clang/Lex/HLSLRootSignatureTokenKinds.def 
b/clang/include/clang/Lex/HLSLRootSignatureTokenKinds.def
index e6df763920430..697c6abc54efa 100644
--- a/clang/include/clang/Lex/HLSLRootSignatureTokenKinds.def
+++ b/clang/include/clang/Lex/HLSLRootSignatureTokenKinds.def
@@ -14,16 +14,16 @@
 
//===----------------------------------------------------------------------===//
 
 #ifndef TOK
-#define TOK(X)
+#define TOK(X, SPELLING)
 #endif
 #ifndef PUNCTUATOR
-#define PUNCTUATOR(X,Y) TOK(pu_ ## X)
+#define PUNCTUATOR(X,Y) TOK(pu_ ## X, Y)
 #endif
 #ifndef KEYWORD
-#define KEYWORD(X) TOK(kw_ ## X)
+#define KEYWORD(X) TOK(kw_ ## X, #X)
 #endif
 #ifndef ENUM
-#define ENUM(NAME, LIT) TOK(en_ ## NAME)
+#define ENUM(NAME, LIT) TOK(en_ ## NAME, LIT)
 #endif
 
 // Defines the various types of enum
@@ -49,15 +49,15 @@
 #endif
 
 // General Tokens:
-TOK(invalid)
-TOK(end_of_stream)
-TOK(int_literal)
+TOK(invalid, "invalid identifier")
+TOK(end_of_stream, "end of stream")
+TOK(int_literal, "integer literal")
 
 // Register Tokens:
-TOK(bReg)
-TOK(tReg)
-TOK(uReg)
-TOK(sReg)
+TOK(bReg, "b register")
+TOK(tReg, "t register")
+TOK(uReg, "u register")
+TOK(sReg, "s register")
 
 // Punctuators:
 PUNCTUATOR(l_paren, '(')
diff --git a/clang/include/clang/Lex/LexHLSLRootSignature.h 
b/clang/include/clang/Lex/LexHLSLRootSignature.h
index 21c44e0351d9e..b82237411b2ab 100644
--- a/clang/include/clang/Lex/LexHLSLRootSignature.h
+++ b/clang/include/clang/Lex/LexHLSLRootSignature.h
@@ -24,7 +24,7 @@ namespace hlsl {
 
 struct RootSignatureToken {
   enum Kind {
-#define TOK(X) X,
+#define TOK(X, SPELLING) X,
 #include "clang/Lex/HLSLRootSignatureTokenKinds.def"
   };
 
diff --git a/clang/lib/Parse/ParseHLSLRootSignature.cpp 
b/clang/lib/Parse/ParseHLSLRootSignature.cpp
index 5bbb35875ceb5..40d6921037f9e 100644
--- a/clang/lib/Parse/ParseHLSLRootSignature.cpp
+++ b/clang/lib/Parse/ParseHLSLRootSignature.cpp
@@ -17,38 +17,9 @@ static std::string FormatTokenKinds(ArrayRef<TokenKind> 
Kinds) {
     if (!First)
       Out << ", ";
     switch (Kind) {
-    case TokenKind::invalid:
-      Out << "invalid identifier";
-      break;
-    case TokenKind::end_of_stream:
-      Out << "end of stream";
-      break;
-    case TokenKind::int_literal:
-      Out << "integer literal";
-      break;
-    case TokenKind::bReg:
-      Out << "b register";
-      break;
-    case TokenKind::tReg:
-      Out << "t register";
-      break;
-    case TokenKind::uReg:
-      Out << "u register";
-      break;
-    case TokenKind::sReg:
-      Out << "s register";
-      break;
-#define PUNCTUATOR(X, Y)                                                       
\
-  case TokenKind::pu_##X:                                                      
\
-    Out << #Y;                                                                 
\
-    break;
-#define KEYWORD(NAME)                                                          
\
-  case TokenKind::kw_##NAME:                                                   
\
-    Out << #NAME;                                                              
\
-    break;
-#define ENUM(NAME, LIT)                                                        
\
-  case TokenKind::en_##NAME:                                                   
\
-    Out << LIT;                                                                
\
+#define TOK(X, SPELLING)                                                       
\
+  case TokenKind::X:                                                           
\
+    Out << SPELLING;                                                           
\
     break;
 #include "clang/Lex/HLSLRootSignatureTokenKinds.def"
     }
diff --git a/clang/unittests/Lex/LexHLSLRootSignatureTest.cpp 
b/clang/unittests/Lex/LexHLSLRootSignatureTest.cpp
index 0576f08c4c276..1e014f6c41c57 100644
--- a/clang/unittests/Lex/LexHLSLRootSignatureTest.cpp
+++ b/clang/unittests/Lex/LexHLSLRootSignatureTest.cpp
@@ -113,7 +113,7 @@ TEST_F(LexHLSLRootSignatureTest, ValidLexAllTokensTest) {
 
   SmallVector<hlsl::RootSignatureToken> Tokens;
   SmallVector<hlsl::TokenKind> Expected = {
-#define TOK(NAME) hlsl::TokenKind::NAME,
+#define TOK(NAME, SPELLING) hlsl::TokenKind::NAME,
 #include "clang/Lex/HLSLRootSignatureTokenKinds.def"
   };
 

>From 3146ebad1269b5580d5e2fd268c6dc5075aaff6c Mon Sep 17 00:00:00 2001
From: Finn Plummer <canadienf...@gmail.com>
Date: Wed, 5 Mar 2025 18:17:45 +0000
Subject: [PATCH 14/15] review: add liscence

---
 clang/lib/Parse/ParseHLSLRootSignature.cpp | 8 ++++++++
 1 file changed, 8 insertions(+)

diff --git a/clang/lib/Parse/ParseHLSLRootSignature.cpp 
b/clang/lib/Parse/ParseHLSLRootSignature.cpp
index 40d6921037f9e..b68bc935f3581 100644
--- a/clang/lib/Parse/ParseHLSLRootSignature.cpp
+++ b/clang/lib/Parse/ParseHLSLRootSignature.cpp
@@ -1,3 +1,11 @@
+//=== ParseHLSLRootSignature.cpp - Parse Root Signature 
-------------------===//
+//
+// 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 "clang/Parse/ParseHLSLRootSignature.h"
 
 #include "clang/Lex/LiteralSupport.h"

>From f457b38e8bc4bc342e12e81fb4ad1123b92b97f5 Mon Sep 17 00:00:00 2001
From: Finn Plummer <canadienf...@gmail.com>
Date: Wed, 5 Mar 2025 22:20:52 +0000
Subject: [PATCH 15/15] review prototype: allow for more context to
 ConsumeNextToken error

---
 .../clang/Basic/DiagnosticParseKinds.td       |  2 +-
 .../clang/Parse/ParseHLSLRootSignature.h      |  8 ++-
 clang/lib/Parse/ParseHLSLRootSignature.cpp    | 70 +++++++++++++------
 .../Parse/ParseHLSLRootSignatureTest.cpp      |  6 +-
 4 files changed, 58 insertions(+), 28 deletions(-)

diff --git a/clang/include/clang/Basic/DiagnosticParseKinds.td 
b/clang/include/clang/Basic/DiagnosticParseKinds.td
index fe1b0dd0b91cb..f2a5eaba48952 100644
--- a/clang/include/clang/Basic/DiagnosticParseKinds.td
+++ b/clang/include/clang/Basic/DiagnosticParseKinds.td
@@ -1819,7 +1819,7 @@ def err_hlsl_unsupported_component : Error<"invalid 
component '%0' used; expecte
 def err_hlsl_packoffset_invalid_reg : Error<"invalid resource class specifier 
'%0' for packoffset, expected 'c'">;
 
 // HLSL Root Signature Parser Diagnostics
-def err_hlsl_rootsig_unexpected_token_kind : Error<"got %1 but expected 
%select{|one of}0 the following token kind%select{|s}0: %2">;
+def err_hlsl_expected : Error<"expected %0 as %1">;
 def err_hlsl_number_literal_overflow : Error<"integer literal is too large to 
be represented as a 32-bit %select{signed |}0 integer type">;
 def err_hlsl_rootsig_repeat_param : Error<"specified the same parameter '%0' 
multiple times">;
 def err_hlsl_rootsig_non_zero_flag : Error<"specified a non-zero integer as a 
flag">;
diff --git a/clang/include/clang/Parse/ParseHLSLRootSignature.h 
b/clang/include/clang/Parse/ParseHLSLRootSignature.h
index 89a02d88d6dfc..9d141b0ebfd4f 100644
--- a/clang/include/clang/Parse/ParseHLSLRootSignature.h
+++ b/clang/include/clang/Parse/ParseHLSLRootSignature.h
@@ -114,8 +114,12 @@ class RootSignatureParser {
   /// kind.
   ///
   /// Returns true if there was an error reported.
-  bool ConsumeExpectedToken(TokenKind Expected);
-  bool ConsumeExpectedToken(ArrayRef<TokenKind> AnyExpected);
+  bool ConsumeExpectedToken(TokenKind Expected,
+                            unsigned DiagID = diag::err_expected,
+                            StringRef DiagMsg = "");
+  bool ConsumeExpectedToken(ArrayRef<TokenKind> AnyExpected,
+                            unsigned DiagID = diag::err_expected,
+                            StringRef DiagMsg = "");
 
   /// Peek if the next token is of the expected kind and if it is then consume
   /// it.
diff --git a/clang/lib/Parse/ParseHLSLRootSignature.cpp 
b/clang/lib/Parse/ParseHLSLRootSignature.cpp
index b68bc935f3581..732d37d310750 100644
--- a/clang/lib/Parse/ParseHLSLRootSignature.cpp
+++ b/clang/lib/Parse/ParseHLSLRootSignature.cpp
@@ -53,7 +53,8 @@ bool RootSignatureParser::Parse() {
   while (!ParseRootElement()) {
     if (Lexer.EndOfBuffer())
       return false;
-    if (ConsumeExpectedToken(TokenKind::pu_comma))
+    if (ConsumeExpectedToken(TokenKind::pu_comma, diag::err_expected_either,
+                             "end of root signature string"))
       return true;
   }
 
@@ -61,7 +62,8 @@ bool RootSignatureParser::Parse() {
 }
 
 bool RootSignatureParser::ParseRootElement() {
-  if (ConsumeExpectedToken(TokenKind::kw_DescriptorTable))
+  if (ConsumeExpectedToken(TokenKind::kw_DescriptorTable,
+                           diag::err_hlsl_expected, "root element"))
     return true;
 
   // Dispatch onto the correct parse method
@@ -77,7 +79,8 @@ bool RootSignatureParser::ParseRootElement() {
 bool RootSignatureParser::ParseDescriptorTable() {
   DescriptorTable Table;
 
-  if (ConsumeExpectedToken(TokenKind::pu_l_paren))
+  if (ConsumeExpectedToken(TokenKind::pu_l_paren, diag::err_expected_after,
+                           "DescriptorTable"))
     return true;
 
   // Empty case:
@@ -108,7 +111,8 @@ bool RootSignatureParser::ParseDescriptorTable() {
     Table.NumClauses++;
   } while (TryConsumeExpectedToken(TokenKind::pu_comma));
 
-  if (ConsumeExpectedToken(TokenKind::pu_r_paren))
+  if (ConsumeExpectedToken(TokenKind::pu_r_paren, diag::err_expected_after,
+                           "descriptor table clauses"))
     return true;
 
   Elements.push_back(Table);
@@ -117,7 +121,8 @@ bool RootSignatureParser::ParseDescriptorTable() {
 
 bool RootSignatureParser::ParseDescriptorTableClause() {
   if (ConsumeExpectedToken({TokenKind::kw_CBV, TokenKind::kw_SRV,
-                            TokenKind::kw_UAV, TokenKind::kw_Sampler}))
+                            TokenKind::kw_UAV, TokenKind::kw_Sampler},
+                           diag::err_hlsl_expected, "descriptor table clause"))
     return true;
 
   DescriptorTableClause Clause;
@@ -139,7 +144,8 @@ bool RootSignatureParser::ParseDescriptorTableClause() {
   }
   Clause.SetDefaultFlags();
 
-  if (ConsumeExpectedToken(TokenKind::pu_l_paren))
+  if (ConsumeExpectedToken(TokenKind::pu_l_paren, diag::err_expected_after,
+                           FormatTokenKinds({CurToken.Kind})))
     return true;
 
   // Consume mandatory Register paramater
@@ -156,7 +162,8 @@ bool RootSignatureParser::ParseDescriptorTableClause() {
   if (ParseOptionalParams({RefMap}))
     return true;
 
-  if (ConsumeExpectedToken(TokenKind::pu_r_paren))
+  if (ConsumeExpectedToken(TokenKind::pu_r_paren, diag::err_expected_after,
+                           "clause parameters"))
     return true;
 
   Elements.push_back(Clause);
@@ -168,7 +175,8 @@ template <class... Ts> struct ParseMethods : Ts... { using 
Ts::operator()...; };
 template <class... Ts> ParseMethods(Ts...) -> ParseMethods<Ts...>;
 
 bool RootSignatureParser::ParseParam(ParamType Ref) {
-  if (ConsumeExpectedToken(TokenKind::pu_equal))
+  if (ConsumeExpectedToken(TokenKind::pu_equal, diag::err_expected_after,
+                           FormatTokenKinds(CurToken.Kind)))
     return true;
 
   bool Error;
@@ -198,7 +206,8 @@ bool RootSignatureParser::ParseOptionalParams(
   llvm::SmallDenseSet<TokenKind> Seen;
 
   while (TryConsumeExpectedToken(TokenKind::pu_comma)) {
-    if (ConsumeExpectedToken(ParamKeywords))
+    if (ConsumeExpectedToken(ParamKeywords, diag::err_hlsl_expected,
+                             "optional parameter"))
       return true;
 
     TokenKind ParamKind = CurToken.Kind;
@@ -241,7 +250,8 @@ bool RootSignatureParser::HandleUIntLiteral(uint32_t &X) {
 
 bool RootSignatureParser::ParseRegister(Register *Register) {
   if (ConsumeExpectedToken(
-          {TokenKind::bReg, TokenKind::tReg, TokenKind::uReg, 
TokenKind::sReg}))
+          {TokenKind::bReg, TokenKind::tReg, TokenKind::uReg, TokenKind::sReg},
+          diag::err_hlsl_expected, "a register"))
     return true;
 
   switch (CurToken.Kind) {
@@ -270,7 +280,8 @@ bool RootSignatureParser::ParseRegister(Register *Register) 
{
 bool RootSignatureParser::ParseUInt(uint32_t *X) {
   // Treat a postively signed integer as though it is unsigned to match DXC
   TryConsumeExpectedToken(TokenKind::pu_plus);
-  if (ConsumeExpectedToken(TokenKind::int_literal))
+  if (ConsumeExpectedToken(TokenKind::int_literal, diag::err_hlsl_expected,
+                           "unsigned integer"))
     return true;
 
   if (HandleUIntLiteral(*X))
@@ -281,7 +292,8 @@ bool RootSignatureParser::ParseUInt(uint32_t *X) {
 
 bool RootSignatureParser::ParseDescriptorRangeOffset(DescriptorRangeOffset *X) 
{
   if (ConsumeExpectedToken(
-          {TokenKind::int_literal, TokenKind::en_DescriptorRangeOffsetAppend}))
+          {TokenKind::int_literal, TokenKind::en_DescriptorRangeOffsetAppend},
+          diag::err_hlsl_expected, "descriptor range offset"))
     return true;
 
   // Edge case for the offset enum -> static value
@@ -307,7 +319,8 @@ bool RootSignatureParser::ParseEnum(
     EnumToks.push_back(EnumPair.first);
 
   // If invoked we expect to have an enum
-  if (ConsumeExpectedToken(EnumToks))
+  if (ConsumeExpectedToken(EnumToks, diag::err_hlsl_expected,
+                           "parameter value"))
     return true;
 
   // Handle the edge case when '0' is used to specify None
@@ -391,20 +404,33 @@ bool 
RootSignatureParser::PeekExpectedToken(ArrayRef<TokenKind> AnyExpected) {
   return IsExpectedToken(Result.Kind, AnyExpected);
 }
 
-bool RootSignatureParser::ConsumeExpectedToken(TokenKind Expected) {
-  return ConsumeExpectedToken(ArrayRef{Expected});
+bool RootSignatureParser::ConsumeExpectedToken(TokenKind Expected,
+                                               unsigned DiagID,
+                                               StringRef DiagMsg) {
+  return ConsumeExpectedToken(ArrayRef{Expected}, DiagID, DiagMsg);
 }
 
-bool RootSignatureParser::ConsumeExpectedToken(
-    ArrayRef<TokenKind> AnyExpected) {
-  ConsumeNextToken();
-  if (IsExpectedToken(CurToken.Kind, AnyExpected))
+bool RootSignatureParser::ConsumeExpectedToken(ArrayRef<TokenKind> AnyExpected,
+                                               unsigned DiagID,
+                                               StringRef DiagMsg) {
+  if (TryConsumeExpectedToken(AnyExpected))
     return false;
 
   // Report unexpected token kind error
-  Diags().Report(CurToken.TokLoc, diag::err_hlsl_rootsig_unexpected_token_kind)
-      << (unsigned)(AnyExpected.size() != 1)
-      << FormatTokenKinds({CurToken.Kind}) << FormatTokenKinds(AnyExpected);
+  DiagnosticBuilder DB = Diags().Report(CurToken.TokLoc, DiagID);
+  switch (DiagID) {
+  case diag::err_expected:
+    DB << FormatTokenKinds(AnyExpected);
+    break;
+  case diag::err_hlsl_expected:
+  case diag::err_expected_either:
+  case diag::err_expected_after:
+    DB << FormatTokenKinds(AnyExpected) << DiagMsg;
+    break;
+  default:
+    DB << DiagMsg;
+    break;
+  }
   return true;
 }
 
diff --git a/clang/unittests/Parse/ParseHLSLRootSignatureTest.cpp 
b/clang/unittests/Parse/ParseHLSLRootSignatureTest.cpp
index 224e16bfa372b..35ad4bfff14d0 100644
--- a/clang/unittests/Parse/ParseHLSLRootSignatureTest.cpp
+++ b/clang/unittests/Parse/ParseHLSLRootSignatureTest.cpp
@@ -238,7 +238,7 @@ TEST_F(ParseHLSLRootSignatureTest, 
InvalidParseUnexpectedTokenTest) {
   hlsl::RootSignatureParser Parser(Elements, Lexer, *PP);
 
   // Test correct diagnostic produced
-  Consumer->SetExpected(diag::err_hlsl_rootsig_unexpected_token_kind);
+  Consumer->SetExpected(diag::err_expected_either);
   ASSERT_TRUE(Parser.Parse());
 
   ASSERT_TRUE(Consumer->IsSatisfied());
@@ -258,7 +258,7 @@ TEST_F(ParseHLSLRootSignatureTest, 
InvalidParseInvalidTokenTest) {
   hlsl::RootSignatureParser Parser(Elements, Lexer, *PP);
 
   // Test correct diagnostic produced - invalid token
-  Consumer->SetExpected(diag::err_hlsl_rootsig_unexpected_token_kind);
+  Consumer->SetExpected(diag::err_hlsl_expected);
   ASSERT_TRUE(Parser.Parse());
 
   ASSERT_TRUE(Consumer->IsSatisfied());
@@ -278,7 +278,7 @@ TEST_F(ParseHLSLRootSignatureTest, 
InvalidParseUnexpectedEndOfStreamTest) {
   hlsl::RootSignatureParser Parser(Elements, Lexer, *PP);
 
   // Test correct diagnostic produced - end of stream
-  Consumer->SetExpected(diag::err_hlsl_rootsig_unexpected_token_kind);
+  Consumer->SetExpected(diag::err_hlsl_expected);
   ASSERT_TRUE(Parser.Parse());
 
   ASSERT_TRUE(Consumer->IsSatisfied());

_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to