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

This pr breaks-up `HLSLRootSignatureUtils` into separate orthogonal and 
meaningful libraries. This prevents it end up as a dumping grounds of many 
different parts.

- Creates a library `RootSignatureMetadata` to contain helper functions for 
interacting the root signatures in their metadata representation
- Create a library `RootSignatureValidations` to contain helper functions that 
will validation various values of root signatures
- Move the serialization of root signature elements to `HLSLRootSignature`

Resolves https://github.com/llvm/llvm-project/issues/145946

>From 7154ac74021f99fbb20fe0781fecb2f02c5a3c36 Mon Sep 17 00:00:00 2001
From: Finn Plummer <canadienf...@gmail.com>
Date: Fri, 27 Jun 2025 16:56:24 +0000
Subject: [PATCH 1/5] nfc: move resource range analysis to `HLSLRootSignature`

---
 clang/lib/Sema/SemaHLSL.cpp                   |  2 +-
 .../llvm/Frontend/HLSL/HLSLRootSignature.h    | 64 ++++++++++++++
 .../Frontend/HLSL/HLSLRootSignatureUtils.h    | 63 --------------
 llvm/lib/Frontend/HLSL/CMakeLists.txt         |  1 +
 llvm/lib/Frontend/HLSL/HLSLRootSignature.cpp  | 84 +++++++++++++++++++
 .../Frontend/HLSL/HLSLRootSignatureUtils.cpp  | 63 --------------
 6 files changed, 150 insertions(+), 127 deletions(-)
 create mode 100644 llvm/lib/Frontend/HLSL/HLSLRootSignature.cpp

diff --git a/clang/lib/Sema/SemaHLSL.cpp b/clang/lib/Sema/SemaHLSL.cpp
index 3bab0da5edea8..f2043657694ed 100644
--- a/clang/lib/Sema/SemaHLSL.cpp
+++ b/clang/lib/Sema/SemaHLSL.cpp
@@ -39,7 +39,7 @@
 #include "llvm/ADT/StringExtras.h"
 #include "llvm/ADT/StringRef.h"
 #include "llvm/ADT/Twine.h"
-#include "llvm/Frontend/HLSL/HLSLRootSignatureUtils.h"
+#include "llvm/Frontend/HLSL/HLSLRootSignature.h"
 #include "llvm/Support/Casting.h"
 #include "llvm/Support/DXILABI.h"
 #include "llvm/Support/ErrorHandling.h"
diff --git a/llvm/include/llvm/Frontend/HLSL/HLSLRootSignature.h 
b/llvm/include/llvm/Frontend/HLSL/HLSLRootSignature.h
index f552040ab31cc..858d3c8551615 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/ADT/IntervalMap.h"
 #include "llvm/BinaryFormat/DXContainer.h"
 #include "llvm/Support/Compiler.h"
 #include "llvm/Support/DXILABI.h"
@@ -135,6 +136,69 @@ using RootElement =
     std::variant<dxbc::RootFlags, RootConstants, RootDescriptor,
                  DescriptorTable, DescriptorTableClause, StaticSampler>;
 
+struct RangeInfo {
+  const static uint32_t Unbounded = ~0u;
+
+  // Interval information
+  uint32_t LowerBound;
+  uint32_t UpperBound;
+
+  // Information retained for diagnostics
+  llvm::dxil::ResourceClass Class;
+  uint32_t Space;
+  llvm::dxbc::ShaderVisibility Visibility;
+};
+
+class ResourceRange {
+public:
+  using MapT = llvm::IntervalMap<uint32_t, const RangeInfo *, 16,
+                                 llvm::IntervalMapInfo<uint32_t>>;
+
+private:
+  MapT Intervals;
+
+public:
+  ResourceRange(MapT::Allocator &Allocator) : Intervals(MapT(Allocator)) {}
+
+  // Returns a reference to the first RangeInfo that overlaps with
+  // [Info.LowerBound;Info.UpperBound], or, std::nullopt if there is no overlap
+  std::optional<const RangeInfo *> getOverlapping(const RangeInfo &Info) const;
+
+  // Return the mapped RangeInfo at X or nullptr if no mapping exists
+  const RangeInfo *lookup(uint32_t X) const;
+
+  // Removes all entries of the ResourceRange
+  void clear();
+
+  // Insert the required (sub-)intervals such that the interval of [a;b] =
+  // [Info.LowerBound, Info.UpperBound] is covered and points to a valid
+  // RangeInfo &.
+  //
+  // For instance consider the following chain of inserting RangeInfos with the
+  // intervals denoting the Lower/Upper-bounds:
+  //
+  // A = [0;2]
+  //   insert(A) -> false
+  //   intervals: [0;2] -> &A
+  // B = [5;7]
+  //   insert(B) -> false
+  //   intervals: [0;2] -> &A, [5;7] -> &B
+  // C = [4;7]
+  //   insert(C) -> true
+  //   intervals: [0;2] -> &A, [4;7] -> &C
+  // D = [1;5]
+  //   insert(D) -> true
+  //   intervals: [0;2] -> &A, [3;3] -> &D, [4;7] -> &C
+  // E = [0;unbounded]
+  //   insert(E) -> true
+  //   intervals: [0;unbounded] -> E
+  //
+  // Returns a reference to the first RangeInfo that overlaps with
+  // [Info.LowerBound;Info.UpperBound], or, std::nullopt if there is no overlap
+  // (equivalent to getOverlapping)
+  std::optional<const RangeInfo *> insert(const RangeInfo &Info);
+};
+
 } // namespace rootsig
 } // namespace hlsl
 } // namespace llvm
diff --git a/llvm/include/llvm/Frontend/HLSL/HLSLRootSignatureUtils.h 
b/llvm/include/llvm/Frontend/HLSL/HLSLRootSignatureUtils.h
index 4fa080e949d54..842d959ffaaff 100644
--- a/llvm/include/llvm/Frontend/HLSL/HLSLRootSignatureUtils.h
+++ b/llvm/include/llvm/Frontend/HLSL/HLSLRootSignatureUtils.h
@@ -73,69 +73,6 @@ class MetadataBuilder {
   SmallVector<Metadata *> GeneratedMetadata;
 };
 
-struct RangeInfo {
-  const static uint32_t Unbounded = ~0u;
-
-  // Interval information
-  uint32_t LowerBound;
-  uint32_t UpperBound;
-
-  // Information retained for diagnostics
-  llvm::dxil::ResourceClass Class;
-  uint32_t Space;
-  llvm::dxbc::ShaderVisibility Visibility;
-};
-
-class ResourceRange {
-public:
-  using MapT = llvm::IntervalMap<uint32_t, const RangeInfo *, 16,
-                                 llvm::IntervalMapInfo<uint32_t>>;
-
-private:
-  MapT Intervals;
-
-public:
-  ResourceRange(MapT::Allocator &Allocator) : Intervals(MapT(Allocator)) {}
-
-  // Returns a reference to the first RangeInfo that overlaps with
-  // [Info.LowerBound;Info.UpperBound], or, std::nullopt if there is no overlap
-  std::optional<const RangeInfo *> getOverlapping(const RangeInfo &Info) const;
-
-  // Return the mapped RangeInfo at X or nullptr if no mapping exists
-  const RangeInfo *lookup(uint32_t X) const;
-
-  // Removes all entries of the ResourceRange
-  void clear();
-
-  // Insert the required (sub-)intervals such that the interval of [a;b] =
-  // [Info.LowerBound, Info.UpperBound] is covered and points to a valid
-  // RangeInfo &.
-  //
-  // For instance consider the following chain of inserting RangeInfos with the
-  // intervals denoting the Lower/Upper-bounds:
-  //
-  // A = [0;2]
-  //   insert(A) -> false
-  //   intervals: [0;2] -> &A
-  // B = [5;7]
-  //   insert(B) -> false
-  //   intervals: [0;2] -> &A, [5;7] -> &B
-  // C = [4;7]
-  //   insert(C) -> true
-  //   intervals: [0;2] -> &A, [4;7] -> &C
-  // D = [1;5]
-  //   insert(D) -> true
-  //   intervals: [0;2] -> &A, [3;3] -> &D, [4;7] -> &C
-  // E = [0;unbounded]
-  //   insert(E) -> true
-  //   intervals: [0;unbounded] -> E
-  //
-  // Returns a reference to the first RangeInfo that overlaps with
-  // [Info.LowerBound;Info.UpperBound], or, std::nullopt if there is no overlap
-  // (equivalent to getOverlapping)
-  std::optional<const RangeInfo *> insert(const RangeInfo &Info);
-};
-
 } // namespace rootsig
 } // namespace hlsl
 } // namespace llvm
diff --git a/llvm/lib/Frontend/HLSL/CMakeLists.txt 
b/llvm/lib/Frontend/HLSL/CMakeLists.txt
index 8928144730477..e790eb889a406 100644
--- a/llvm/lib/Frontend/HLSL/CMakeLists.txt
+++ b/llvm/lib/Frontend/HLSL/CMakeLists.txt
@@ -1,6 +1,7 @@
 add_llvm_component_library(LLVMFrontendHLSL
   CBuffer.cpp
   HLSLResource.cpp
+  HLSLRootSignature.cpp
   HLSLRootSignatureUtils.cpp
 
   ADDITIONAL_HEADER_DIRS
diff --git a/llvm/lib/Frontend/HLSL/HLSLRootSignature.cpp 
b/llvm/lib/Frontend/HLSL/HLSLRootSignature.cpp
new file mode 100644
index 0000000000000..8b446b3ab36b4
--- /dev/null
+++ b/llvm/lib/Frontend/HLSL/HLSLRootSignature.cpp
@@ -0,0 +1,84 @@
+//===- HLSLRootSignature.cpp - HLSL Root Signature helpers 
----------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM 
Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+///
+/// \file This file contains helpers for working with HLSL Root Signatures.
+///
+//===----------------------------------------------------------------------===//
+
+#include "llvm/Frontend/HLSL/HLSLRootSignature.h"
+
+namespace llvm {
+namespace hlsl {
+namespace rootsig {
+
+std::optional<const RangeInfo *>
+ResourceRange::getOverlapping(const RangeInfo &Info) const {
+  MapT::const_iterator Interval = Intervals.find(Info.LowerBound);
+  if (!Interval.valid() || Info.UpperBound < Interval.start())
+    return std::nullopt;
+  return Interval.value();
+}
+
+const RangeInfo *ResourceRange::lookup(uint32_t X) const {
+  return Intervals.lookup(X, nullptr);
+}
+
+void ResourceRange::clear() { return Intervals.clear(); }
+
+std::optional<const RangeInfo *> ResourceRange::insert(const RangeInfo &Info) {
+  uint32_t LowerBound = Info.LowerBound;
+  uint32_t UpperBound = Info.UpperBound;
+
+  std::optional<const RangeInfo *> Res = std::nullopt;
+  MapT::iterator Interval = Intervals.begin();
+
+  while (true) {
+    if (UpperBound < LowerBound)
+      break;
+
+    Interval.advanceTo(LowerBound);
+    if (!Interval.valid()) // No interval found
+      break;
+
+    // Let Interval = [x;y] and [LowerBound;UpperBound] = [a;b] and note that
+    // a <= y implicitly from Intervals.find(LowerBound)
+    if (UpperBound < Interval.start())
+      break; // found interval does not overlap with inserted one
+
+    if (!Res.has_value()) // Update to be the first found intersection
+      Res = Interval.value();
+
+    if (Interval.start() <= LowerBound && UpperBound <= Interval.stop()) {
+      // x <= a <= b <= y implies that [a;b] is covered by [x;y]
+      //  -> so we don't need to insert this, report an overlap
+      return Res;
+    } else if (LowerBound <= Interval.start() &&
+               Interval.stop() <= UpperBound) {
+      // a <= x <= y <= b implies that [x;y] is covered by [a;b]
+      //  -> so remove the existing interval that we will cover with the
+      //  overwrite
+      Interval.erase();
+    } else if (LowerBound < Interval.start() && UpperBound <= Interval.stop()) 
{
+      // a < x <= b <= y implies that [a; x] is not covered but [x;b] is
+      //  -> so set b = x - 1 such that [a;x-1] is now the interval to insert
+      UpperBound = Interval.start() - 1;
+    } else if (Interval.start() <= LowerBound && Interval.stop() < UpperBound) 
{
+      // a < x <= b <= y implies that [y; b] is not covered but [a;y] is
+      //  -> so set a = y + 1 such that [y+1;b] is now the interval to insert
+      LowerBound = Interval.stop() + 1;
+    }
+  }
+
+  assert(LowerBound <= UpperBound && "Attempting to insert an empty interval");
+  Intervals.insert(LowerBound, UpperBound, &Info);
+  return Res;
+}
+
+} // namespace rootsig
+} // namespace hlsl
+} // namespace llvm
diff --git a/llvm/lib/Frontend/HLSL/HLSLRootSignatureUtils.cpp 
b/llvm/lib/Frontend/HLSL/HLSLRootSignatureUtils.cpp
index 67f512008b069..ab0f31397e0d3 100644
--- a/llvm/lib/Frontend/HLSL/HLSLRootSignatureUtils.cpp
+++ b/llvm/lib/Frontend/HLSL/HLSLRootSignatureUtils.cpp
@@ -389,69 +389,6 @@ MDNode *MetadataBuilder::BuildStaticSampler(const 
StaticSampler &Sampler) {
   return MDNode::get(Ctx, Operands);
 }
 
-std::optional<const RangeInfo *>
-ResourceRange::getOverlapping(const RangeInfo &Info) const {
-  MapT::const_iterator Interval = Intervals.find(Info.LowerBound);
-  if (!Interval.valid() || Info.UpperBound < Interval.start())
-    return std::nullopt;
-  return Interval.value();
-}
-
-const RangeInfo *ResourceRange::lookup(uint32_t X) const {
-  return Intervals.lookup(X, nullptr);
-}
-
-void ResourceRange::clear() { return Intervals.clear(); }
-
-std::optional<const RangeInfo *> ResourceRange::insert(const RangeInfo &Info) {
-  uint32_t LowerBound = Info.LowerBound;
-  uint32_t UpperBound = Info.UpperBound;
-
-  std::optional<const RangeInfo *> Res = std::nullopt;
-  MapT::iterator Interval = Intervals.begin();
-
-  while (true) {
-    if (UpperBound < LowerBound)
-      break;
-
-    Interval.advanceTo(LowerBound);
-    if (!Interval.valid()) // No interval found
-      break;
-
-    // Let Interval = [x;y] and [LowerBound;UpperBound] = [a;b] and note that
-    // a <= y implicitly from Intervals.find(LowerBound)
-    if (UpperBound < Interval.start())
-      break; // found interval does not overlap with inserted one
-
-    if (!Res.has_value()) // Update to be the first found intersection
-      Res = Interval.value();
-
-    if (Interval.start() <= LowerBound && UpperBound <= Interval.stop()) {
-      // x <= a <= b <= y implies that [a;b] is covered by [x;y]
-      //  -> so we don't need to insert this, report an overlap
-      return Res;
-    } else if (LowerBound <= Interval.start() &&
-               Interval.stop() <= UpperBound) {
-      // a <= x <= y <= b implies that [x;y] is covered by [a;b]
-      //  -> so remove the existing interval that we will cover with the
-      //  overwrite
-      Interval.erase();
-    } else if (LowerBound < Interval.start() && UpperBound <= Interval.stop()) 
{
-      // a < x <= b <= y implies that [a; x] is not covered but [x;b] is
-      //  -> so set b = x - 1 such that [a;x-1] is now the interval to insert
-      UpperBound = Interval.start() - 1;
-    } else if (Interval.start() <= LowerBound && Interval.stop() < UpperBound) 
{
-      // a < x <= b <= y implies that [y; b] is not covered but [a;y] is
-      //  -> so set a = y + 1 such that [y+1;b] is now the interval to insert
-      LowerBound = Interval.stop() + 1;
-    }
-  }
-
-  assert(LowerBound <= UpperBound && "Attempting to insert an empty interval");
-  Intervals.insert(LowerBound, UpperBound, &Info);
-  return Res;
-}
-
 } // namespace rootsig
 } // namespace hlsl
 } // namespace llvm

>From 6f9ed0386ecd3ebda16b5475cca0397415a5a1a8 Mon Sep 17 00:00:00 2001
From: Finn Plummer <canadienf...@gmail.com>
Date: Fri, 27 Jun 2025 17:31:44 +0000
Subject: [PATCH 2/5] nfc: move `MetadataBuilder` to `RootSignatureMetadata`
 library

---
 clang/lib/CodeGen/CGHLSLRuntime.cpp           |   2 +-
 .../Frontend/HLSL/HLSLRootSignatureUtils.h    |  25 ---
 .../Frontend/HLSL/RootSignatureMetadata.h     |  56 +++++
 llvm/lib/Frontend/HLSL/CMakeLists.txt         |   1 +
 .../Frontend/HLSL/HLSLRootSignatureUtils.cpp  | 150 +-------------
 .../Frontend/HLSL/RootSignatureMetadata.cpp   | 194 ++++++++++++++++++
 6 files changed, 253 insertions(+), 175 deletions(-)
 create mode 100644 llvm/include/llvm/Frontend/HLSL/RootSignatureMetadata.h
 create mode 100644 llvm/lib/Frontend/HLSL/RootSignatureMetadata.cpp

diff --git a/clang/lib/CodeGen/CGHLSLRuntime.cpp 
b/clang/lib/CodeGen/CGHLSLRuntime.cpp
index f2e992fb7fa69..73843247ce7f2 100644
--- a/clang/lib/CodeGen/CGHLSLRuntime.cpp
+++ b/clang/lib/CodeGen/CGHLSLRuntime.cpp
@@ -23,7 +23,7 @@
 #include "clang/AST/Type.h"
 #include "clang/Basic/TargetOptions.h"
 #include "llvm/ADT/SmallVector.h"
-#include "llvm/Frontend/HLSL/HLSLRootSignatureUtils.h"
+#include "llvm/Frontend/HLSL/RootSignatureMetadata.h"
 #include "llvm/IR/Constants.h"
 #include "llvm/IR/DerivedTypes.h"
 #include "llvm/IR/GlobalVariable.h"
diff --git a/llvm/include/llvm/Frontend/HLSL/HLSLRootSignatureUtils.h 
b/llvm/include/llvm/Frontend/HLSL/HLSLRootSignatureUtils.h
index 842d959ffaaff..debca37429fb8 100644
--- a/llvm/include/llvm/Frontend/HLSL/HLSLRootSignatureUtils.h
+++ b/llvm/include/llvm/Frontend/HLSL/HLSLRootSignatureUtils.h
@@ -48,31 +48,6 @@ LLVM_ABI raw_ostream &operator<<(raw_ostream &OS, const 
RootElement &Element);
 
 LLVM_ABI void dumpRootElements(raw_ostream &OS, ArrayRef<RootElement> 
Elements);
 
-class MetadataBuilder {
-public:
-  MetadataBuilder(llvm::LLVMContext &Ctx, ArrayRef<RootElement> Elements)
-      : Ctx(Ctx), Elements(Elements) {}
-
-  /// Iterates through the elements and dispatches onto the correct Build 
method
-  ///
-  /// Accumulates the root signature and returns the Metadata node that is just
-  /// a list of all the elements
-  LLVM_ABI MDNode *BuildRootSignature();
-
-private:
-  /// Define the various builders for the different metadata types
-  MDNode *BuildRootFlags(const dxbc::RootFlags &Flags);
-  MDNode *BuildRootConstants(const RootConstants &Constants);
-  MDNode *BuildRootDescriptor(const RootDescriptor &Descriptor);
-  MDNode *BuildDescriptorTable(const DescriptorTable &Table);
-  MDNode *BuildDescriptorTableClause(const DescriptorTableClause &Clause);
-  MDNode *BuildStaticSampler(const StaticSampler &Sampler);
-
-  llvm::LLVMContext &Ctx;
-  ArrayRef<RootElement> Elements;
-  SmallVector<Metadata *> GeneratedMetadata;
-};
-
 } // namespace rootsig
 } // namespace hlsl
 } // namespace llvm
diff --git a/llvm/include/llvm/Frontend/HLSL/RootSignatureMetadata.h 
b/llvm/include/llvm/Frontend/HLSL/RootSignatureMetadata.h
new file mode 100644
index 0000000000000..c473a7f1e02e5
--- /dev/null
+++ b/llvm/include/llvm/Frontend/HLSL/RootSignatureMetadata.h
@@ -0,0 +1,56 @@
+//===- RootSignatureMetadata.h - HLSL Root Signature helpers 
--------------===//
+//
+// 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 a library for working with HLSL Root Signatures 
and
+/// their metadata representation.
+///
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_FRONTEND_HLSL_ROOTSIGNATUREMETADATA_H
+#define LLVM_FRONTEND_HLSL_ROOTSIGNATUREMETADATA_H
+
+#include "llvm/Frontend/HLSL/HLSLRootSignature.h"
+
+namespace llvm {
+class LLVMContext;
+class MDNode;
+class Metadata;
+
+namespace hlsl {
+namespace rootsig {
+
+class MetadataBuilder {
+public:
+  MetadataBuilder(llvm::LLVMContext &Ctx, ArrayRef<RootElement> Elements)
+      : Ctx(Ctx), Elements(Elements) {}
+
+  /// Iterates through the elements and dispatches onto the correct Build 
method
+  ///
+  /// Accumulates the root signature and returns the Metadata node that is just
+  /// a list of all the elements
+  LLVM_ABI MDNode *BuildRootSignature();
+
+private:
+  /// Define the various builders for the different metadata types
+  MDNode *BuildRootFlags(const dxbc::RootFlags &Flags);
+  MDNode *BuildRootConstants(const RootConstants &Constants);
+  MDNode *BuildRootDescriptor(const RootDescriptor &Descriptor);
+  MDNode *BuildDescriptorTable(const DescriptorTable &Table);
+  MDNode *BuildDescriptorTableClause(const DescriptorTableClause &Clause);
+  MDNode *BuildStaticSampler(const StaticSampler &Sampler);
+
+  llvm::LLVMContext &Ctx;
+  ArrayRef<RootElement> Elements;
+  SmallVector<Metadata *> GeneratedMetadata;
+};
+
+} // namespace rootsig
+} // namespace hlsl
+} // namespace llvm
+
+#endif // LLVM_FRONTEND_HLSL_ROOTSIGNATUREMETADATA_H
diff --git a/llvm/lib/Frontend/HLSL/CMakeLists.txt 
b/llvm/lib/Frontend/HLSL/CMakeLists.txt
index e790eb889a406..a4fa2572ebb0a 100644
--- a/llvm/lib/Frontend/HLSL/CMakeLists.txt
+++ b/llvm/lib/Frontend/HLSL/CMakeLists.txt
@@ -3,6 +3,7 @@ add_llvm_component_library(LLVMFrontendHLSL
   HLSLResource.cpp
   HLSLRootSignature.cpp
   HLSLRootSignatureUtils.cpp
+  RootSignatureMetadata.cpp
 
   ADDITIONAL_HEADER_DIRS
   ${LLVM_MAIN_INCLUDE_DIR}/llvm/Frontend
diff --git a/llvm/lib/Frontend/HLSL/HLSLRootSignatureUtils.cpp 
b/llvm/lib/Frontend/HLSL/HLSLRootSignatureUtils.cpp
index ab0f31397e0d3..ef16463b136ef 100644
--- a/llvm/lib/Frontend/HLSL/HLSLRootSignatureUtils.cpp
+++ b/llvm/lib/Frontend/HLSL/HLSLRootSignatureUtils.cpp
@@ -13,8 +13,6 @@
 #include "llvm/Frontend/HLSL/HLSLRootSignatureUtils.h"
 #include "llvm/ADT/SmallString.h"
 #include "llvm/ADT/bit.h"
-#include "llvm/IR/IRBuilder.h"
-#include "llvm/IR/Metadata.h"
 #include "llvm/Support/ScopedPrinter.h"
 
 namespace llvm {
@@ -210,8 +208,7 @@ raw_ostream &operator<<(raw_ostream &OS, const 
StaticSampler &Sampler) {
 namespace {
 
 // We use the OverloadVisit with std::visit to ensure the compiler catches if a
-// new RootElement variant type is added but it's operator<< or metadata
-// generation isn't handled.
+// new RootElement variant type is added but it's operator<< isn't handled.
 template <class... Ts> struct OverloadedVisit : Ts... {
   using Ts::operator()...;
 };
@@ -244,151 +241,6 @@ void dumpRootElements(raw_ostream &OS, 
ArrayRef<RootElement> Elements) {
   OS << "}";
 }
 
-MDNode *MetadataBuilder::BuildRootSignature() {
-  const auto Visitor = OverloadedVisit{
-      [this](const dxbc::RootFlags &Flags) -> MDNode * {
-        return BuildRootFlags(Flags);
-      },
-      [this](const RootConstants &Constants) -> MDNode * {
-        return BuildRootConstants(Constants);
-      },
-      [this](const RootDescriptor &Descriptor) -> MDNode * {
-        return BuildRootDescriptor(Descriptor);
-      },
-      [this](const DescriptorTableClause &Clause) -> MDNode * {
-        return BuildDescriptorTableClause(Clause);
-      },
-      [this](const DescriptorTable &Table) -> MDNode * {
-        return BuildDescriptorTable(Table);
-      },
-      [this](const StaticSampler &Sampler) -> MDNode * {
-        return BuildStaticSampler(Sampler);
-      },
-  };
-
-  for (const RootElement &Element : Elements) {
-    MDNode *ElementMD = std::visit(Visitor, Element);
-    assert(ElementMD != nullptr &&
-           "Root Element must be initialized and validated");
-    GeneratedMetadata.push_back(ElementMD);
-  }
-
-  return MDNode::get(Ctx, GeneratedMetadata);
-}
-
-MDNode *MetadataBuilder::BuildRootFlags(const dxbc::RootFlags &Flags) {
-  IRBuilder<> Builder(Ctx);
-  Metadata *Operands[] = {
-      MDString::get(Ctx, "RootFlags"),
-      ConstantAsMetadata::get(Builder.getInt32(llvm::to_underlying(Flags))),
-  };
-  return MDNode::get(Ctx, Operands);
-}
-
-MDNode *MetadataBuilder::BuildRootConstants(const RootConstants &Constants) {
-  IRBuilder<> Builder(Ctx);
-  Metadata *Operands[] = {
-      MDString::get(Ctx, "RootConstants"),
-      ConstantAsMetadata::get(
-          Builder.getInt32(llvm::to_underlying(Constants.Visibility))),
-      ConstantAsMetadata::get(Builder.getInt32(Constants.Reg.Number)),
-      ConstantAsMetadata::get(Builder.getInt32(Constants.Space)),
-      ConstantAsMetadata::get(Builder.getInt32(Constants.Num32BitConstants)),
-  };
-  return MDNode::get(Ctx, Operands);
-}
-
-MDNode *MetadataBuilder::BuildRootDescriptor(const RootDescriptor &Descriptor) 
{
-  IRBuilder<> Builder(Ctx);
-  std::optional<StringRef> TypeName =
-      getEnumName(dxil::ResourceClass(llvm::to_underlying(Descriptor.Type)),
-                  ArrayRef(ResourceClassNames));
-  assert(TypeName && "Provided an invalid Resource Class");
-  llvm::SmallString<7> Name({"Root", *TypeName});
-  Metadata *Operands[] = {
-      MDString::get(Ctx, Name),
-      ConstantAsMetadata::get(
-          Builder.getInt32(llvm::to_underlying(Descriptor.Visibility))),
-      ConstantAsMetadata::get(Builder.getInt32(Descriptor.Reg.Number)),
-      ConstantAsMetadata::get(Builder.getInt32(Descriptor.Space)),
-      ConstantAsMetadata::get(
-          Builder.getInt32(llvm::to_underlying(Descriptor.Flags))),
-  };
-  return MDNode::get(Ctx, Operands);
-}
-
-MDNode *MetadataBuilder::BuildDescriptorTable(const DescriptorTable &Table) {
-  IRBuilder<> Builder(Ctx);
-  SmallVector<Metadata *> TableOperands;
-  // Set the mandatory arguments
-  TableOperands.push_back(MDString::get(Ctx, "DescriptorTable"));
-  TableOperands.push_back(ConstantAsMetadata::get(
-      Builder.getInt32(llvm::to_underlying(Table.Visibility))));
-
-  // Remaining operands are references to the table's clauses. The in-memory
-  // representation of the Root Elements created from parsing will ensure that
-  // the previous N elements are the clauses for this table.
-  assert(Table.NumClauses <= GeneratedMetadata.size() &&
-         "Table expected all owned clauses to be generated already");
-  // So, add a refence to each clause to our operands
-  TableOperands.append(GeneratedMetadata.end() - Table.NumClauses,
-                       GeneratedMetadata.end());
-  // Then, remove those clauses from the general list of Root Elements
-  GeneratedMetadata.pop_back_n(Table.NumClauses);
-
-  return MDNode::get(Ctx, TableOperands);
-}
-
-MDNode *MetadataBuilder::BuildDescriptorTableClause(
-    const DescriptorTableClause &Clause) {
-  IRBuilder<> Builder(Ctx);
-  std::optional<StringRef> Name =
-      getEnumName(dxil::ResourceClass(llvm::to_underlying(Clause.Type)),
-                  ArrayRef(ResourceClassNames));
-  assert(Name && "Provided an invalid Resource Class");
-  Metadata *Operands[] = {
-      MDString::get(Ctx, *Name),
-      ConstantAsMetadata::get(Builder.getInt32(Clause.NumDescriptors)),
-      ConstantAsMetadata::get(Builder.getInt32(Clause.Reg.Number)),
-      ConstantAsMetadata::get(Builder.getInt32(Clause.Space)),
-      ConstantAsMetadata::get(Builder.getInt32(Clause.Offset)),
-      ConstantAsMetadata::get(
-          Builder.getInt32(llvm::to_underlying(Clause.Flags))),
-  };
-  return MDNode::get(Ctx, Operands);
-}
-
-MDNode *MetadataBuilder::BuildStaticSampler(const StaticSampler &Sampler) {
-  IRBuilder<> Builder(Ctx);
-  Metadata *Operands[] = {
-      MDString::get(Ctx, "StaticSampler"),
-      ConstantAsMetadata::get(
-          Builder.getInt32(llvm::to_underlying(Sampler.Filter))),
-      ConstantAsMetadata::get(
-          Builder.getInt32(llvm::to_underlying(Sampler.AddressU))),
-      ConstantAsMetadata::get(
-          Builder.getInt32(llvm::to_underlying(Sampler.AddressV))),
-      ConstantAsMetadata::get(
-          Builder.getInt32(llvm::to_underlying(Sampler.AddressW))),
-      
ConstantAsMetadata::get(llvm::ConstantFP::get(llvm::Type::getFloatTy(Ctx),
-                                                    Sampler.MipLODBias)),
-      ConstantAsMetadata::get(Builder.getInt32(Sampler.MaxAnisotropy)),
-      ConstantAsMetadata::get(
-          Builder.getInt32(llvm::to_underlying(Sampler.CompFunc))),
-      ConstantAsMetadata::get(
-          Builder.getInt32(llvm::to_underlying(Sampler.BorderColor))),
-      ConstantAsMetadata::get(
-          llvm::ConstantFP::get(llvm::Type::getFloatTy(Ctx), Sampler.MinLOD)),
-      ConstantAsMetadata::get(
-          llvm::ConstantFP::get(llvm::Type::getFloatTy(Ctx), Sampler.MaxLOD)),
-      ConstantAsMetadata::get(Builder.getInt32(Sampler.Reg.Number)),
-      ConstantAsMetadata::get(Builder.getInt32(Sampler.Space)),
-      ConstantAsMetadata::get(
-          Builder.getInt32(llvm::to_underlying(Sampler.Visibility))),
-  };
-  return MDNode::get(Ctx, Operands);
-}
-
 } // namespace rootsig
 } // namespace hlsl
 } // namespace llvm
diff --git a/llvm/lib/Frontend/HLSL/RootSignatureMetadata.cpp 
b/llvm/lib/Frontend/HLSL/RootSignatureMetadata.cpp
new file mode 100644
index 0000000000000..f7669f09dcecc
--- /dev/null
+++ b/llvm/lib/Frontend/HLSL/RootSignatureMetadata.cpp
@@ -0,0 +1,194 @@
+//===- RootSignatureMetadata.h - HLSL Root Signature helpers 
--------------===//
+//
+// 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 implements a library for working with HLSL Root Signatures
+/// and their metadata representation.
+///
+//===----------------------------------------------------------------------===//
+
+#include "llvm/Frontend/HLSL/RootSignatureMetadata.h"
+#include "llvm/IR/IRBuilder.h"
+#include "llvm/IR/Metadata.h"
+#include "llvm/Support/ScopedPrinter.h"
+
+namespace llvm {
+namespace hlsl {
+namespace rootsig {
+
+static const EnumEntry<dxil::ResourceClass> ResourceClassNames[] = {
+    {"CBV", dxil::ResourceClass::CBuffer},
+    {"SRV", dxil::ResourceClass::SRV},
+    {"UAV", dxil::ResourceClass::UAV},
+    {"Sampler", dxil::ResourceClass::Sampler},
+};
+
+static std::optional<StringRef> getResourceName(dxil::ResourceClass Class) {
+  for (const auto &ClassEnum : ResourceClassNames)
+    if (ClassEnum.Value == Class)
+      return ClassEnum.Name;
+  return std::nullopt;
+}
+
+namespace {
+
+// We use the OverloadVisit with std::visit to ensure the compiler catches if a
+// new RootElement variant type is added but it's metadata generation isn't
+// handled.
+template <class... Ts> struct OverloadedVisit : Ts... {
+  using Ts::operator()...;
+};
+template <class... Ts> OverloadedVisit(Ts...) -> OverloadedVisit<Ts...>;
+
+} // namespace
+
+MDNode *MetadataBuilder::BuildRootSignature() {
+  const auto Visitor = OverloadedVisit{
+      [this](const dxbc::RootFlags &Flags) -> MDNode * {
+        return BuildRootFlags(Flags);
+      },
+      [this](const RootConstants &Constants) -> MDNode * {
+        return BuildRootConstants(Constants);
+      },
+      [this](const RootDescriptor &Descriptor) -> MDNode * {
+        return BuildRootDescriptor(Descriptor);
+      },
+      [this](const DescriptorTableClause &Clause) -> MDNode * {
+        return BuildDescriptorTableClause(Clause);
+      },
+      [this](const DescriptorTable &Table) -> MDNode * {
+        return BuildDescriptorTable(Table);
+      },
+      [this](const StaticSampler &Sampler) -> MDNode * {
+        return BuildStaticSampler(Sampler);
+      },
+  };
+
+  for (const RootElement &Element : Elements) {
+    MDNode *ElementMD = std::visit(Visitor, Element);
+    assert(ElementMD != nullptr &&
+           "Root Element must be initialized and validated");
+    GeneratedMetadata.push_back(ElementMD);
+  }
+
+  return MDNode::get(Ctx, GeneratedMetadata);
+}
+
+MDNode *MetadataBuilder::BuildRootFlags(const dxbc::RootFlags &Flags) {
+  IRBuilder<> Builder(Ctx);
+  Metadata *Operands[] = {
+      MDString::get(Ctx, "RootFlags"),
+      ConstantAsMetadata::get(Builder.getInt32(llvm::to_underlying(Flags))),
+  };
+  return MDNode::get(Ctx, Operands);
+}
+
+MDNode *MetadataBuilder::BuildRootConstants(const RootConstants &Constants) {
+  IRBuilder<> Builder(Ctx);
+  Metadata *Operands[] = {
+      MDString::get(Ctx, "RootConstants"),
+      ConstantAsMetadata::get(
+          Builder.getInt32(llvm::to_underlying(Constants.Visibility))),
+      ConstantAsMetadata::get(Builder.getInt32(Constants.Reg.Number)),
+      ConstantAsMetadata::get(Builder.getInt32(Constants.Space)),
+      ConstantAsMetadata::get(Builder.getInt32(Constants.Num32BitConstants)),
+  };
+  return MDNode::get(Ctx, Operands);
+}
+
+MDNode *MetadataBuilder::BuildRootDescriptor(const RootDescriptor &Descriptor) 
{
+  IRBuilder<> Builder(Ctx);
+  std::optional<StringRef> ResName = getResourceName(
+      dxil::ResourceClass(llvm::to_underlying(Descriptor.Type)));
+  assert(ResName && "Provided an invalid Resource Class");
+  llvm::SmallString<7> Name({"Root", *ResName});
+  Metadata *Operands[] = {
+      MDString::get(Ctx, Name),
+      ConstantAsMetadata::get(
+          Builder.getInt32(llvm::to_underlying(Descriptor.Visibility))),
+      ConstantAsMetadata::get(Builder.getInt32(Descriptor.Reg.Number)),
+      ConstantAsMetadata::get(Builder.getInt32(Descriptor.Space)),
+      ConstantAsMetadata::get(
+          Builder.getInt32(llvm::to_underlying(Descriptor.Flags))),
+  };
+  return MDNode::get(Ctx, Operands);
+}
+
+MDNode *MetadataBuilder::BuildDescriptorTable(const DescriptorTable &Table) {
+  IRBuilder<> Builder(Ctx);
+  SmallVector<Metadata *> TableOperands;
+  // Set the mandatory arguments
+  TableOperands.push_back(MDString::get(Ctx, "DescriptorTable"));
+  TableOperands.push_back(ConstantAsMetadata::get(
+      Builder.getInt32(llvm::to_underlying(Table.Visibility))));
+
+  // Remaining operands are references to the table's clauses. The in-memory
+  // representation of the Root Elements created from parsing will ensure that
+  // the previous N elements are the clauses for this table.
+  assert(Table.NumClauses <= GeneratedMetadata.size() &&
+         "Table expected all owned clauses to be generated already");
+  // So, add a refence to each clause to our operands
+  TableOperands.append(GeneratedMetadata.end() - Table.NumClauses,
+                       GeneratedMetadata.end());
+  // Then, remove those clauses from the general list of Root Elements
+  GeneratedMetadata.pop_back_n(Table.NumClauses);
+
+  return MDNode::get(Ctx, TableOperands);
+}
+
+MDNode *MetadataBuilder::BuildDescriptorTableClause(
+    const DescriptorTableClause &Clause) {
+  IRBuilder<> Builder(Ctx);
+  std::optional<StringRef> ResName =
+      getResourceName(dxil::ResourceClass(llvm::to_underlying(Clause.Type)));
+  assert(ResName && "Provided an invalid Resource Class");
+  Metadata *Operands[] = {
+      MDString::get(Ctx, *ResName),
+      ConstantAsMetadata::get(Builder.getInt32(Clause.NumDescriptors)),
+      ConstantAsMetadata::get(Builder.getInt32(Clause.Reg.Number)),
+      ConstantAsMetadata::get(Builder.getInt32(Clause.Space)),
+      ConstantAsMetadata::get(Builder.getInt32(Clause.Offset)),
+      ConstantAsMetadata::get(
+          Builder.getInt32(llvm::to_underlying(Clause.Flags))),
+  };
+  return MDNode::get(Ctx, Operands);
+}
+
+MDNode *MetadataBuilder::BuildStaticSampler(const StaticSampler &Sampler) {
+  IRBuilder<> Builder(Ctx);
+  Metadata *Operands[] = {
+      MDString::get(Ctx, "StaticSampler"),
+      ConstantAsMetadata::get(
+          Builder.getInt32(llvm::to_underlying(Sampler.Filter))),
+      ConstantAsMetadata::get(
+          Builder.getInt32(llvm::to_underlying(Sampler.AddressU))),
+      ConstantAsMetadata::get(
+          Builder.getInt32(llvm::to_underlying(Sampler.AddressV))),
+      ConstantAsMetadata::get(
+          Builder.getInt32(llvm::to_underlying(Sampler.AddressW))),
+      
ConstantAsMetadata::get(llvm::ConstantFP::get(llvm::Type::getFloatTy(Ctx),
+                                                    Sampler.MipLODBias)),
+      ConstantAsMetadata::get(Builder.getInt32(Sampler.MaxAnisotropy)),
+      ConstantAsMetadata::get(
+          Builder.getInt32(llvm::to_underlying(Sampler.CompFunc))),
+      ConstantAsMetadata::get(
+          Builder.getInt32(llvm::to_underlying(Sampler.BorderColor))),
+      ConstantAsMetadata::get(
+          llvm::ConstantFP::get(llvm::Type::getFloatTy(Ctx), Sampler.MinLOD)),
+      ConstantAsMetadata::get(
+          llvm::ConstantFP::get(llvm::Type::getFloatTy(Ctx), Sampler.MaxLOD)),
+      ConstantAsMetadata::get(Builder.getInt32(Sampler.Reg.Number)),
+      ConstantAsMetadata::get(Builder.getInt32(Sampler.Space)),
+      ConstantAsMetadata::get(
+          Builder.getInt32(llvm::to_underlying(Sampler.Visibility))),
+  };
+  return MDNode::get(Ctx, Operands);
+}
+
+} // namespace rootsig
+} // namespace hlsl
+} // namespace llvm

>From 9b24d290c92fe5b86cddffdfd322073f8c0d7976 Mon Sep 17 00:00:00 2001
From: Finn Plummer <canadienf...@gmail.com>
Date: Fri, 27 Jun 2025 17:38:31 +0000
Subject: [PATCH 3/5] nfc: move serialization interface to `HLSLRootSignature`

---
 clang/lib/AST/TextNodeDumper.cpp              |   2 +-
 .../llvm/Frontend/HLSL/HLSLRootSignature.h    |  17 ++
 .../Frontend/HLSL/HLSLRootSignatureUtils.h    |  20 --
 llvm/lib/Frontend/HLSL/HLSLRootSignature.cpp  | 223 ++++++++++++++++++
 .../Frontend/HLSL/HLSLRootSignatureUtils.cpp  | 222 -----------------
 .../Frontend/HLSLRootSignatureDumpTest.cpp    |   2 +-
 .../Frontend/HLSLRootSignatureRangesTest.cpp  |   2 +-
 7 files changed, 243 insertions(+), 245 deletions(-)

diff --git a/clang/lib/AST/TextNodeDumper.cpp b/clang/lib/AST/TextNodeDumper.cpp
index bb860a8f76742..9d7c2757d6ee4 100644
--- a/clang/lib/AST/TextNodeDumper.cpp
+++ b/clang/lib/AST/TextNodeDumper.cpp
@@ -24,7 +24,7 @@
 #include "clang/Basic/Specifiers.h"
 #include "clang/Basic/TypeTraits.h"
 #include "llvm/ADT/StringExtras.h"
-#include "llvm/Frontend/HLSL/HLSLRootSignatureUtils.h"
+#include "llvm/Frontend/HLSL/HLSLRootSignature.h"
 
 #include <algorithm>
 #include <utility>
diff --git a/llvm/include/llvm/Frontend/HLSL/HLSLRootSignature.h 
b/llvm/include/llvm/Frontend/HLSL/HLSLRootSignature.h
index 858d3c8551615..7e599745afb67 100644
--- a/llvm/include/llvm/Frontend/HLSL/HLSLRootSignature.h
+++ b/llvm/include/llvm/Frontend/HLSL/HLSLRootSignature.h
@@ -18,6 +18,7 @@
 #include "llvm/BinaryFormat/DXContainer.h"
 #include "llvm/Support/Compiler.h"
 #include "llvm/Support/DXILABI.h"
+#include "llvm/Support/raw_ostream.h"
 #include <limits>
 #include <variant>
 
@@ -136,6 +137,22 @@ using RootElement =
     std::variant<dxbc::RootFlags, RootConstants, RootDescriptor,
                  DescriptorTable, DescriptorTableClause, StaticSampler>;
 
+/// The following contains the serialization interface for root elements
+LLVM_ABI raw_ostream &operator<<(raw_ostream &OS, const dxbc::RootFlags 
&Flags);
+LLVM_ABI raw_ostream &operator<<(raw_ostream &OS,
+                                 const RootConstants &Constants);
+LLVM_ABI raw_ostream &operator<<(raw_ostream &OS,
+                                 const DescriptorTableClause &Clause);
+LLVM_ABI raw_ostream &operator<<(raw_ostream &OS, const DescriptorTable 
&Table);
+LLVM_ABI raw_ostream &operator<<(raw_ostream &OS,
+                                 const RootDescriptor &Descriptor);
+LLVM_ABI raw_ostream &operator<<(raw_ostream &OS,
+                                 const StaticSampler &StaticSampler);
+LLVM_ABI raw_ostream &operator<<(raw_ostream &OS, const RootElement &Element);
+
+LLVM_ABI void dumpRootElements(raw_ostream &OS, ArrayRef<RootElement> 
Elements);
+
+/// The following contains the validation interface of root elements
 struct RangeInfo {
   const static uint32_t Unbounded = ~0u;
 
diff --git a/llvm/include/llvm/Frontend/HLSL/HLSLRootSignatureUtils.h 
b/llvm/include/llvm/Frontend/HLSL/HLSLRootSignatureUtils.h
index debca37429fb8..7adef4765bfcf 100644
--- a/llvm/include/llvm/Frontend/HLSL/HLSLRootSignatureUtils.h
+++ b/llvm/include/llvm/Frontend/HLSL/HLSLRootSignatureUtils.h
@@ -28,26 +28,6 @@ class Metadata;
 namespace hlsl {
 namespace rootsig {
 
-LLVM_ABI raw_ostream &operator<<(raw_ostream &OS, const dxbc::RootFlags 
&Flags);
-
-LLVM_ABI raw_ostream &operator<<(raw_ostream &OS,
-                                 const RootConstants &Constants);
-
-LLVM_ABI raw_ostream &operator<<(raw_ostream &OS,
-                                 const DescriptorTableClause &Clause);
-
-LLVM_ABI raw_ostream &operator<<(raw_ostream &OS, const DescriptorTable 
&Table);
-
-LLVM_ABI raw_ostream &operator<<(raw_ostream &OS,
-                                 const RootDescriptor &Descriptor);
-
-LLVM_ABI raw_ostream &operator<<(raw_ostream &OS,
-                                 const StaticSampler &StaticSampler);
-
-LLVM_ABI raw_ostream &operator<<(raw_ostream &OS, const RootElement &Element);
-
-LLVM_ABI void dumpRootElements(raw_ostream &OS, ArrayRef<RootElement> 
Elements);
-
 } // namespace rootsig
 } // namespace hlsl
 } // namespace llvm
diff --git a/llvm/lib/Frontend/HLSL/HLSLRootSignature.cpp 
b/llvm/lib/Frontend/HLSL/HLSLRootSignature.cpp
index 8b446b3ab36b4..ead017945eefe 100644
--- a/llvm/lib/Frontend/HLSL/HLSLRootSignature.cpp
+++ b/llvm/lib/Frontend/HLSL/HLSLRootSignature.cpp
@@ -11,11 +11,234 @@
 
//===----------------------------------------------------------------------===//
 
 #include "llvm/Frontend/HLSL/HLSLRootSignature.h"
+#include "llvm/Support/ScopedPrinter.h"
 
 namespace llvm {
 namespace hlsl {
 namespace rootsig {
 
+template <typename T>
+static std::optional<StringRef> getEnumName(const T Value,
+                                            ArrayRef<EnumEntry<T>> Enums) {
+  for (const auto &EnumItem : Enums)
+    if (EnumItem.Value == Value)
+      return EnumItem.Name;
+  return std::nullopt;
+}
+
+template <typename T>
+static raw_ostream &printEnum(raw_ostream &OS, const T Value,
+                              ArrayRef<EnumEntry<T>> Enums) {
+  auto MaybeName = getEnumName(Value, Enums);
+  if (MaybeName)
+    OS << *MaybeName;
+  return OS;
+}
+
+template <typename T>
+static raw_ostream &printFlags(raw_ostream &OS, const T Value,
+                               ArrayRef<EnumEntry<T>> Flags) {
+  bool FlagSet = false;
+  unsigned Remaining = llvm::to_underlying(Value);
+  while (Remaining) {
+    unsigned Bit = 1u << llvm::countr_zero(Remaining);
+    if (Remaining & Bit) {
+      if (FlagSet)
+        OS << " | ";
+
+      auto MaybeFlag = getEnumName(T(Bit), Flags);
+      if (MaybeFlag)
+        OS << *MaybeFlag;
+      else
+        OS << "invalid: " << Bit;
+
+      FlagSet = true;
+    }
+    Remaining &= ~Bit;
+  }
+
+  if (!FlagSet)
+    OS << "None";
+  return OS;
+}
+
+static const EnumEntry<RegisterType> RegisterNames[] = {
+    {"b", RegisterType::BReg},
+    {"t", RegisterType::TReg},
+    {"u", RegisterType::UReg},
+    {"s", RegisterType::SReg},
+};
+
+static raw_ostream &operator<<(raw_ostream &OS, const Register &Reg) {
+  printEnum(OS, Reg.ViewType, ArrayRef(RegisterNames));
+  OS << Reg.Number;
+
+  return OS;
+}
+
+static raw_ostream &operator<<(raw_ostream &OS,
+                               const llvm::dxbc::ShaderVisibility &Visibility) 
{
+  printEnum(OS, Visibility, dxbc::getShaderVisibility());
+
+  return OS;
+}
+
+static raw_ostream &operator<<(raw_ostream &OS,
+                               const llvm::dxbc::SamplerFilter &Filter) {
+  printEnum(OS, Filter, dxbc::getSamplerFilters());
+
+  return OS;
+}
+
+static raw_ostream &operator<<(raw_ostream &OS,
+                               const dxbc::TextureAddressMode &Address) {
+  printEnum(OS, Address, dxbc::getTextureAddressModes());
+
+  return OS;
+}
+
+static raw_ostream &operator<<(raw_ostream &OS,
+                               const dxbc::ComparisonFunc &CompFunc) {
+  printEnum(OS, CompFunc, dxbc::getComparisonFuncs());
+
+  return OS;
+}
+
+static raw_ostream &operator<<(raw_ostream &OS,
+                               const dxbc::StaticBorderColor &BorderColor) {
+  printEnum(OS, BorderColor, dxbc::getStaticBorderColors());
+
+  return OS;
+}
+
+static const EnumEntry<dxil::ResourceClass> ResourceClassNames[] = {
+    {"CBV", dxil::ResourceClass::CBuffer},
+    {"SRV", dxil::ResourceClass::SRV},
+    {"UAV", dxil::ResourceClass::UAV},
+    {"Sampler", dxil::ResourceClass::Sampler},
+};
+
+static raw_ostream &operator<<(raw_ostream &OS, const ClauseType &Type) {
+  printEnum(OS, dxil::ResourceClass(llvm::to_underlying(Type)),
+            ArrayRef(ResourceClassNames));
+
+  return OS;
+}
+
+static raw_ostream &operator<<(raw_ostream &OS,
+                               const dxbc::RootDescriptorFlags &Flags) {
+  printFlags(OS, Flags, dxbc::getRootDescriptorFlags());
+
+  return OS;
+}
+
+static raw_ostream &operator<<(raw_ostream &OS,
+                               const llvm::dxbc::DescriptorRangeFlags &Flags) {
+  printFlags(OS, Flags, dxbc::getDescriptorRangeFlags());
+
+  return OS;
+}
+
+raw_ostream &operator<<(raw_ostream &OS, const dxbc::RootFlags &Flags) {
+  OS << "RootFlags(";
+  printFlags(OS, Flags, dxbc::getRootFlags());
+  OS << ")";
+
+  return OS;
+}
+
+raw_ostream &operator<<(raw_ostream &OS, const RootConstants &Constants) {
+  OS << "RootConstants(num32BitConstants = " << Constants.Num32BitConstants
+     << ", " << Constants.Reg << ", space = " << Constants.Space
+     << ", visibility = " << Constants.Visibility << ")";
+
+  return OS;
+}
+
+raw_ostream &operator<<(raw_ostream &OS, const DescriptorTable &Table) {
+  OS << "DescriptorTable(numClauses = " << Table.NumClauses
+     << ", visibility = " << Table.Visibility << ")";
+
+  return OS;
+}
+
+raw_ostream &operator<<(raw_ostream &OS, const DescriptorTableClause &Clause) {
+  OS << Clause.Type << "(" << Clause.Reg << ", numDescriptors = ";
+  if (Clause.NumDescriptors == NumDescriptorsUnbounded)
+    OS << "unbounded";
+  else
+    OS << Clause.NumDescriptors;
+  OS << ", space = " << Clause.Space << ", offset = ";
+  if (Clause.Offset == DescriptorTableOffsetAppend)
+    OS << "DescriptorTableOffsetAppend";
+  else
+    OS << Clause.Offset;
+  OS << ", flags = " << Clause.Flags << ")";
+
+  return OS;
+}
+
+raw_ostream &operator<<(raw_ostream &OS, const RootDescriptor &Descriptor) {
+  ClauseType Type = ClauseType(llvm::to_underlying(Descriptor.Type));
+  OS << "Root" << Type << "(" << Descriptor.Reg
+     << ", space = " << Descriptor.Space
+     << ", visibility = " << Descriptor.Visibility
+     << ", flags = " << Descriptor.Flags << ")";
+
+  return OS;
+}
+
+raw_ostream &operator<<(raw_ostream &OS, const StaticSampler &Sampler) {
+  OS << "StaticSampler(" << Sampler.Reg << ", filter = " << Sampler.Filter
+     << ", addressU = " << Sampler.AddressU
+     << ", addressV = " << Sampler.AddressV
+     << ", addressW = " << Sampler.AddressW
+     << ", mipLODBias = " << Sampler.MipLODBias
+     << ", maxAnisotropy = " << Sampler.MaxAnisotropy
+     << ", comparisonFunc = " << Sampler.CompFunc
+     << ", borderColor = " << Sampler.BorderColor
+     << ", minLOD = " << Sampler.MinLOD << ", maxLOD = " << Sampler.MaxLOD
+     << ", space = " << Sampler.Space << ", visibility = " << 
Sampler.Visibility
+     << ")";
+  return OS;
+}
+
+namespace {
+
+// We use the OverloadVisit with std::visit to ensure the compiler catches if a
+// new RootElement variant type is added but it's operator<< isn't handled.
+template <class... Ts> struct OverloadedVisit : Ts... {
+  using Ts::operator()...;
+};
+template <class... Ts> OverloadedVisit(Ts...) -> OverloadedVisit<Ts...>;
+
+} // namespace
+
+raw_ostream &operator<<(raw_ostream &OS, const RootElement &Element) {
+  const auto Visitor = OverloadedVisit{
+      [&OS](const dxbc::RootFlags &Flags) { OS << Flags; },
+      [&OS](const RootConstants &Constants) { OS << Constants; },
+      [&OS](const RootDescriptor &Descriptor) { OS << Descriptor; },
+      [&OS](const DescriptorTableClause &Clause) { OS << Clause; },
+      [&OS](const DescriptorTable &Table) { OS << Table; },
+      [&OS](const StaticSampler &Sampler) { OS << Sampler; },
+  };
+  std::visit(Visitor, Element);
+  return OS;
+}
+
+void dumpRootElements(raw_ostream &OS, ArrayRef<RootElement> Elements) {
+  OS << " RootElements{";
+  bool First = true;
+  for (const RootElement &Element : Elements) {
+    if (!First)
+      OS << ",";
+    OS << " " << Element;
+    First = false;
+  }
+  OS << "}";
+}
+
 std::optional<const RangeInfo *>
 ResourceRange::getOverlapping(const RangeInfo &Info) const {
   MapT::const_iterator Interval = Intervals.find(Info.LowerBound);
diff --git a/llvm/lib/Frontend/HLSL/HLSLRootSignatureUtils.cpp 
b/llvm/lib/Frontend/HLSL/HLSLRootSignatureUtils.cpp
index ef16463b136ef..146aaa1802675 100644
--- a/llvm/lib/Frontend/HLSL/HLSLRootSignatureUtils.cpp
+++ b/llvm/lib/Frontend/HLSL/HLSLRootSignatureUtils.cpp
@@ -19,228 +19,6 @@ namespace llvm {
 namespace hlsl {
 namespace rootsig {
 
-template <typename T>
-static std::optional<StringRef> getEnumName(const T Value,
-                                            ArrayRef<EnumEntry<T>> Enums) {
-  for (const auto &EnumItem : Enums)
-    if (EnumItem.Value == Value)
-      return EnumItem.Name;
-  return std::nullopt;
-}
-
-template <typename T>
-static raw_ostream &printEnum(raw_ostream &OS, const T Value,
-                              ArrayRef<EnumEntry<T>> Enums) {
-  auto MaybeName = getEnumName(Value, Enums);
-  if (MaybeName)
-    OS << *MaybeName;
-  return OS;
-}
-
-template <typename T>
-static raw_ostream &printFlags(raw_ostream &OS, const T Value,
-                               ArrayRef<EnumEntry<T>> Flags) {
-  bool FlagSet = false;
-  unsigned Remaining = llvm::to_underlying(Value);
-  while (Remaining) {
-    unsigned Bit = 1u << llvm::countr_zero(Remaining);
-    if (Remaining & Bit) {
-      if (FlagSet)
-        OS << " | ";
-
-      auto MaybeFlag = getEnumName(T(Bit), Flags);
-      if (MaybeFlag)
-        OS << *MaybeFlag;
-      else
-        OS << "invalid: " << Bit;
-
-      FlagSet = true;
-    }
-    Remaining &= ~Bit;
-  }
-
-  if (!FlagSet)
-    OS << "None";
-  return OS;
-}
-
-static const EnumEntry<RegisterType> RegisterNames[] = {
-    {"b", RegisterType::BReg},
-    {"t", RegisterType::TReg},
-    {"u", RegisterType::UReg},
-    {"s", RegisterType::SReg},
-};
-
-static raw_ostream &operator<<(raw_ostream &OS, const Register &Reg) {
-  printEnum(OS, Reg.ViewType, ArrayRef(RegisterNames));
-  OS << Reg.Number;
-
-  return OS;
-}
-
-static raw_ostream &operator<<(raw_ostream &OS,
-                               const llvm::dxbc::ShaderVisibility &Visibility) 
{
-  printEnum(OS, Visibility, dxbc::getShaderVisibility());
-
-  return OS;
-}
-
-static raw_ostream &operator<<(raw_ostream &OS,
-                               const llvm::dxbc::SamplerFilter &Filter) {
-  printEnum(OS, Filter, dxbc::getSamplerFilters());
-
-  return OS;
-}
-
-static raw_ostream &operator<<(raw_ostream &OS,
-                               const dxbc::TextureAddressMode &Address) {
-  printEnum(OS, Address, dxbc::getTextureAddressModes());
-
-  return OS;
-}
-
-static raw_ostream &operator<<(raw_ostream &OS,
-                               const dxbc::ComparisonFunc &CompFunc) {
-  printEnum(OS, CompFunc, dxbc::getComparisonFuncs());
-
-  return OS;
-}
-
-static raw_ostream &operator<<(raw_ostream &OS,
-                               const dxbc::StaticBorderColor &BorderColor) {
-  printEnum(OS, BorderColor, dxbc::getStaticBorderColors());
-
-  return OS;
-}
-
-static const EnumEntry<dxil::ResourceClass> ResourceClassNames[] = {
-    {"CBV", dxil::ResourceClass::CBuffer},
-    {"SRV", dxil::ResourceClass::SRV},
-    {"UAV", dxil::ResourceClass::UAV},
-    {"Sampler", dxil::ResourceClass::Sampler},
-};
-
-static raw_ostream &operator<<(raw_ostream &OS, const ClauseType &Type) {
-  printEnum(OS, dxil::ResourceClass(llvm::to_underlying(Type)),
-            ArrayRef(ResourceClassNames));
-
-  return OS;
-}
-
-static raw_ostream &operator<<(raw_ostream &OS,
-                               const dxbc::RootDescriptorFlags &Flags) {
-  printFlags(OS, Flags, dxbc::getRootDescriptorFlags());
-
-  return OS;
-}
-
-static raw_ostream &operator<<(raw_ostream &OS,
-                               const llvm::dxbc::DescriptorRangeFlags &Flags) {
-  printFlags(OS, Flags, dxbc::getDescriptorRangeFlags());
-
-  return OS;
-}
-
-raw_ostream &operator<<(raw_ostream &OS, const dxbc::RootFlags &Flags) {
-  OS << "RootFlags(";
-  printFlags(OS, Flags, dxbc::getRootFlags());
-  OS << ")";
-
-  return OS;
-}
-
-raw_ostream &operator<<(raw_ostream &OS, const RootConstants &Constants) {
-  OS << "RootConstants(num32BitConstants = " << Constants.Num32BitConstants
-     << ", " << Constants.Reg << ", space = " << Constants.Space
-     << ", visibility = " << Constants.Visibility << ")";
-
-  return OS;
-}
-
-raw_ostream &operator<<(raw_ostream &OS, const DescriptorTable &Table) {
-  OS << "DescriptorTable(numClauses = " << Table.NumClauses
-     << ", visibility = " << Table.Visibility << ")";
-
-  return OS;
-}
-
-raw_ostream &operator<<(raw_ostream &OS, const DescriptorTableClause &Clause) {
-  OS << Clause.Type << "(" << Clause.Reg << ", numDescriptors = ";
-  if (Clause.NumDescriptors == NumDescriptorsUnbounded)
-    OS << "unbounded";
-  else
-    OS << Clause.NumDescriptors;
-  OS << ", space = " << Clause.Space << ", offset = ";
-  if (Clause.Offset == DescriptorTableOffsetAppend)
-    OS << "DescriptorTableOffsetAppend";
-  else
-    OS << Clause.Offset;
-  OS << ", flags = " << Clause.Flags << ")";
-
-  return OS;
-}
-
-raw_ostream &operator<<(raw_ostream &OS, const RootDescriptor &Descriptor) {
-  ClauseType Type = ClauseType(llvm::to_underlying(Descriptor.Type));
-  OS << "Root" << Type << "(" << Descriptor.Reg
-     << ", space = " << Descriptor.Space
-     << ", visibility = " << Descriptor.Visibility
-     << ", flags = " << Descriptor.Flags << ")";
-
-  return OS;
-}
-
-raw_ostream &operator<<(raw_ostream &OS, const StaticSampler &Sampler) {
-  OS << "StaticSampler(" << Sampler.Reg << ", filter = " << Sampler.Filter
-     << ", addressU = " << Sampler.AddressU
-     << ", addressV = " << Sampler.AddressV
-     << ", addressW = " << Sampler.AddressW
-     << ", mipLODBias = " << Sampler.MipLODBias
-     << ", maxAnisotropy = " << Sampler.MaxAnisotropy
-     << ", comparisonFunc = " << Sampler.CompFunc
-     << ", borderColor = " << Sampler.BorderColor
-     << ", minLOD = " << Sampler.MinLOD << ", maxLOD = " << Sampler.MaxLOD
-     << ", space = " << Sampler.Space << ", visibility = " << 
Sampler.Visibility
-     << ")";
-  return OS;
-}
-
-namespace {
-
-// We use the OverloadVisit with std::visit to ensure the compiler catches if a
-// new RootElement variant type is added but it's operator<< isn't handled.
-template <class... Ts> struct OverloadedVisit : Ts... {
-  using Ts::operator()...;
-};
-template <class... Ts> OverloadedVisit(Ts...) -> OverloadedVisit<Ts...>;
-
-} // namespace
-
-raw_ostream &operator<<(raw_ostream &OS, const RootElement &Element) {
-  const auto Visitor = OverloadedVisit{
-      [&OS](const dxbc::RootFlags &Flags) { OS << Flags; },
-      [&OS](const RootConstants &Constants) { OS << Constants; },
-      [&OS](const RootDescriptor &Descriptor) { OS << Descriptor; },
-      [&OS](const DescriptorTableClause &Clause) { OS << Clause; },
-      [&OS](const DescriptorTable &Table) { OS << Table; },
-      [&OS](const StaticSampler &Sampler) { OS << Sampler; },
-  };
-  std::visit(Visitor, Element);
-  return OS;
-}
-
-void dumpRootElements(raw_ostream &OS, ArrayRef<RootElement> Elements) {
-  OS << " RootElements{";
-  bool First = true;
-  for (const RootElement &Element : Elements) {
-    if (!First)
-      OS << ",";
-    OS << " " << Element;
-    First = false;
-  }
-  OS << "}";
-}
-
 } // namespace rootsig
 } // namespace hlsl
 } // namespace llvm
diff --git a/llvm/unittests/Frontend/HLSLRootSignatureDumpTest.cpp 
b/llvm/unittests/Frontend/HLSLRootSignatureDumpTest.cpp
index e090f6bae470f..73a1fc67e6d28 100644
--- a/llvm/unittests/Frontend/HLSLRootSignatureDumpTest.cpp
+++ b/llvm/unittests/Frontend/HLSLRootSignatureDumpTest.cpp
@@ -6,7 +6,7 @@
 //
 
//===----------------------------------------------------------------------===//
 
-#include "llvm/Frontend/HLSL/HLSLRootSignatureUtils.h"
+#include "llvm/Frontend/HLSL/HLSLRootSignature.h"
 #include "gtest/gtest.h"
 
 using namespace llvm::hlsl::rootsig;
diff --git a/llvm/unittests/Frontend/HLSLRootSignatureRangesTest.cpp 
b/llvm/unittests/Frontend/HLSLRootSignatureRangesTest.cpp
index 0ef6fe84f0ec9..d026b03b4803f 100644
--- a/llvm/unittests/Frontend/HLSLRootSignatureRangesTest.cpp
+++ b/llvm/unittests/Frontend/HLSLRootSignatureRangesTest.cpp
@@ -6,7 +6,7 @@
 //
 
//===----------------------------------------------------------------------===//
 
-#include "llvm/Frontend/HLSL/HLSLRootSignatureUtils.h"
+#include "llvm/Frontend/HLSL/HLSLRootSignature.h"
 #include "gtest/gtest.h"
 
 using namespace llvm::hlsl::rootsig;

>From 9ec32f12f03721c20b1ab0939279944dc75ba675 Mon Sep 17 00:00:00 2001
From: Finn Plummer <canadienf...@gmail.com>
Date: Fri, 27 Jun 2025 17:40:14 +0000
Subject: [PATCH 4/5] nfc: remove `HLSLRootSignatureUtils` library

---
 .../Frontend/HLSL/HLSLRootSignatureUtils.h    | 35 -------------------
 llvm/lib/Frontend/HLSL/CMakeLists.txt         |  1 -
 .../Frontend/HLSL/HLSLRootSignatureUtils.cpp  | 24 -------------
 3 files changed, 60 deletions(-)
 delete mode 100644 llvm/include/llvm/Frontend/HLSL/HLSLRootSignatureUtils.h
 delete mode 100644 llvm/lib/Frontend/HLSL/HLSLRootSignatureUtils.cpp

diff --git a/llvm/include/llvm/Frontend/HLSL/HLSLRootSignatureUtils.h 
b/llvm/include/llvm/Frontend/HLSL/HLSLRootSignatureUtils.h
deleted file mode 100644
index 7adef4765bfcf..0000000000000
--- a/llvm/include/llvm/Frontend/HLSL/HLSLRootSignatureUtils.h
+++ /dev/null
@@ -1,35 +0,0 @@
-//===- HLSLRootSignatureUtils.h - HLSL Root Signature helpers 
-------------===//
-//
-// 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 obejcts for working with HLSL Root
-/// Signatures.
-///
-//===----------------------------------------------------------------------===//
-
-#ifndef LLVM_FRONTEND_HLSL_HLSLROOTSIGNATUREUTILS_H
-#define LLVM_FRONTEND_HLSL_HLSLROOTSIGNATUREUTILS_H
-
-#include "llvm/ADT/ArrayRef.h"
-#include "llvm/ADT/IntervalMap.h"
-#include "llvm/Frontend/HLSL/HLSLRootSignature.h"
-#include "llvm/Support/Compiler.h"
-#include "llvm/Support/raw_ostream.h"
-
-namespace llvm {
-class LLVMContext;
-class MDNode;
-class Metadata;
-
-namespace hlsl {
-namespace rootsig {
-
-} // namespace rootsig
-} // namespace hlsl
-} // namespace llvm
-
-#endif // LLVM_FRONTEND_HLSL_HLSLROOTSIGNATUREUTILS_H
diff --git a/llvm/lib/Frontend/HLSL/CMakeLists.txt 
b/llvm/lib/Frontend/HLSL/CMakeLists.txt
index a4fa2572ebb0a..8b337363b9f84 100644
--- a/llvm/lib/Frontend/HLSL/CMakeLists.txt
+++ b/llvm/lib/Frontend/HLSL/CMakeLists.txt
@@ -2,7 +2,6 @@ add_llvm_component_library(LLVMFrontendHLSL
   CBuffer.cpp
   HLSLResource.cpp
   HLSLRootSignature.cpp
-  HLSLRootSignatureUtils.cpp
   RootSignatureMetadata.cpp
 
   ADDITIONAL_HEADER_DIRS
diff --git a/llvm/lib/Frontend/HLSL/HLSLRootSignatureUtils.cpp 
b/llvm/lib/Frontend/HLSL/HLSLRootSignatureUtils.cpp
deleted file mode 100644
index 146aaa1802675..0000000000000
--- a/llvm/lib/Frontend/HLSL/HLSLRootSignatureUtils.cpp
+++ /dev/null
@@ -1,24 +0,0 @@
-//===- HLSLRootSignatureUtils.cpp - HLSL Root Signature helpers 
-----------===//
-//
-// Part of the LLVM Project, under the Apache License v2.0 with LLVM 
Exceptions.
-// See https://llvm.org/LICENSE.txt for license information.
-// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
-//
-//===----------------------------------------------------------------------===//
-///
-/// \file This file contains helpers for working with HLSL Root Signatures.
-///
-//===----------------------------------------------------------------------===//
-
-#include "llvm/Frontend/HLSL/HLSLRootSignatureUtils.h"
-#include "llvm/ADT/SmallString.h"
-#include "llvm/ADT/bit.h"
-#include "llvm/Support/ScopedPrinter.h"
-
-namespace llvm {
-namespace hlsl {
-namespace rootsig {
-
-} // namespace rootsig
-} // namespace hlsl
-} // namespace llvm

>From 23f69f2c2a374de88adfb25adfda17971643212f Mon Sep 17 00:00:00 2001
From: Finn Plummer <canadienf...@gmail.com>
Date: Fri, 27 Jun 2025 17:46:41 +0000
Subject: [PATCH 5/5] nfc: move resource range analysis to
 `RootSignatureValidations` library

---
 clang/lib/Sema/SemaHLSL.cpp                   |  2 +-
 .../llvm/Frontend/HLSL/HLSLRootSignature.h    | 65 -------------
 .../Frontend/HLSL/RootSignatureValidations.h  | 91 +++++++++++++++++++
 llvm/lib/Frontend/HLSL/CMakeLists.txt         |  1 +
 llvm/lib/Frontend/HLSL/HLSLRootSignature.cpp  | 63 -------------
 .../HLSL/RootSignatureValidations.cpp         | 84 +++++++++++++++++
 .../Frontend/HLSLRootSignatureRangesTest.cpp  |  2 +-
 7 files changed, 178 insertions(+), 130 deletions(-)
 create mode 100644 llvm/include/llvm/Frontend/HLSL/RootSignatureValidations.h
 create mode 100644 llvm/lib/Frontend/HLSL/RootSignatureValidations.cpp

diff --git a/clang/lib/Sema/SemaHLSL.cpp b/clang/lib/Sema/SemaHLSL.cpp
index f2043657694ed..ca66c71370d60 100644
--- a/clang/lib/Sema/SemaHLSL.cpp
+++ b/clang/lib/Sema/SemaHLSL.cpp
@@ -39,7 +39,7 @@
 #include "llvm/ADT/StringExtras.h"
 #include "llvm/ADT/StringRef.h"
 #include "llvm/ADT/Twine.h"
-#include "llvm/Frontend/HLSL/HLSLRootSignature.h"
+#include "llvm/Frontend/HLSL/RootSignatureValidations.h"
 #include "llvm/Support/Casting.h"
 #include "llvm/Support/DXILABI.h"
 #include "llvm/Support/ErrorHandling.h"
diff --git a/llvm/include/llvm/Frontend/HLSL/HLSLRootSignature.h 
b/llvm/include/llvm/Frontend/HLSL/HLSLRootSignature.h
index 7e599745afb67..f747c8ccaeb18 100644
--- a/llvm/include/llvm/Frontend/HLSL/HLSLRootSignature.h
+++ b/llvm/include/llvm/Frontend/HLSL/HLSLRootSignature.h
@@ -14,7 +14,6 @@
 #ifndef LLVM_FRONTEND_HLSL_HLSLROOTSIGNATURE_H
 #define LLVM_FRONTEND_HLSL_HLSLROOTSIGNATURE_H
 
-#include "llvm/ADT/IntervalMap.h"
 #include "llvm/BinaryFormat/DXContainer.h"
 #include "llvm/Support/Compiler.h"
 #include "llvm/Support/DXILABI.h"
@@ -152,70 +151,6 @@ LLVM_ABI raw_ostream &operator<<(raw_ostream &OS, const 
RootElement &Element);
 
 LLVM_ABI void dumpRootElements(raw_ostream &OS, ArrayRef<RootElement> 
Elements);
 
-/// The following contains the validation interface of root elements
-struct RangeInfo {
-  const static uint32_t Unbounded = ~0u;
-
-  // Interval information
-  uint32_t LowerBound;
-  uint32_t UpperBound;
-
-  // Information retained for diagnostics
-  llvm::dxil::ResourceClass Class;
-  uint32_t Space;
-  llvm::dxbc::ShaderVisibility Visibility;
-};
-
-class ResourceRange {
-public:
-  using MapT = llvm::IntervalMap<uint32_t, const RangeInfo *, 16,
-                                 llvm::IntervalMapInfo<uint32_t>>;
-
-private:
-  MapT Intervals;
-
-public:
-  ResourceRange(MapT::Allocator &Allocator) : Intervals(MapT(Allocator)) {}
-
-  // Returns a reference to the first RangeInfo that overlaps with
-  // [Info.LowerBound;Info.UpperBound], or, std::nullopt if there is no overlap
-  std::optional<const RangeInfo *> getOverlapping(const RangeInfo &Info) const;
-
-  // Return the mapped RangeInfo at X or nullptr if no mapping exists
-  const RangeInfo *lookup(uint32_t X) const;
-
-  // Removes all entries of the ResourceRange
-  void clear();
-
-  // Insert the required (sub-)intervals such that the interval of [a;b] =
-  // [Info.LowerBound, Info.UpperBound] is covered and points to a valid
-  // RangeInfo &.
-  //
-  // For instance consider the following chain of inserting RangeInfos with the
-  // intervals denoting the Lower/Upper-bounds:
-  //
-  // A = [0;2]
-  //   insert(A) -> false
-  //   intervals: [0;2] -> &A
-  // B = [5;7]
-  //   insert(B) -> false
-  //   intervals: [0;2] -> &A, [5;7] -> &B
-  // C = [4;7]
-  //   insert(C) -> true
-  //   intervals: [0;2] -> &A, [4;7] -> &C
-  // D = [1;5]
-  //   insert(D) -> true
-  //   intervals: [0;2] -> &A, [3;3] -> &D, [4;7] -> &C
-  // E = [0;unbounded]
-  //   insert(E) -> true
-  //   intervals: [0;unbounded] -> E
-  //
-  // Returns a reference to the first RangeInfo that overlaps with
-  // [Info.LowerBound;Info.UpperBound], or, std::nullopt if there is no overlap
-  // (equivalent to getOverlapping)
-  std::optional<const RangeInfo *> insert(const RangeInfo &Info);
-};
-
 } // namespace rootsig
 } // namespace hlsl
 } // namespace llvm
diff --git a/llvm/include/llvm/Frontend/HLSL/RootSignatureValidations.h 
b/llvm/include/llvm/Frontend/HLSL/RootSignatureValidations.h
new file mode 100644
index 0000000000000..14eb7c482c08c
--- /dev/null
+++ b/llvm/include/llvm/Frontend/HLSL/RootSignatureValidations.h
@@ -0,0 +1,91 @@
+//===- RootSignatureValidations.h - HLSL Root Signature helpers 
-----------===//
+//
+// 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 obejcts for working with HLSL Root
+/// Signatures.
+///
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_FRONTEND_HLSL_ROOTSIGNATUREVALIDATIONS_H
+#define LLVM_FRONTEND_HLSL_ROOTSIGNATUREVALIDATIONS_H
+
+#include "llvm/ADT/IntervalMap.h"
+#include "llvm/Frontend/HLSL/HLSLRootSignature.h"
+
+namespace llvm {
+namespace hlsl {
+namespace rootsig {
+
+struct RangeInfo {
+  const static uint32_t Unbounded = ~0u;
+
+  // Interval information
+  uint32_t LowerBound;
+  uint32_t UpperBound;
+
+  // Information retained for diagnostics
+  llvm::dxil::ResourceClass Class;
+  uint32_t Space;
+  llvm::dxbc::ShaderVisibility Visibility;
+};
+
+class ResourceRange {
+public:
+  using MapT = llvm::IntervalMap<uint32_t, const RangeInfo *, 16,
+                                 llvm::IntervalMapInfo<uint32_t>>;
+
+private:
+  MapT Intervals;
+
+public:
+  ResourceRange(MapT::Allocator &Allocator) : Intervals(MapT(Allocator)) {}
+
+  // Returns a reference to the first RangeInfo that overlaps with
+  // [Info.LowerBound;Info.UpperBound], or, std::nullopt if there is no overlap
+  std::optional<const RangeInfo *> getOverlapping(const RangeInfo &Info) const;
+
+  // Return the mapped RangeInfo at X or nullptr if no mapping exists
+  const RangeInfo *lookup(uint32_t X) const;
+
+  // Removes all entries of the ResourceRange
+  void clear();
+
+  // Insert the required (sub-)intervals such that the interval of [a;b] =
+  // [Info.LowerBound, Info.UpperBound] is covered and points to a valid
+  // RangeInfo &.
+  //
+  // For instance consider the following chain of inserting RangeInfos with the
+  // intervals denoting the Lower/Upper-bounds:
+  //
+  // A = [0;2]
+  //   insert(A) -> false
+  //   intervals: [0;2] -> &A
+  // B = [5;7]
+  //   insert(B) -> false
+  //   intervals: [0;2] -> &A, [5;7] -> &B
+  // C = [4;7]
+  //   insert(C) -> true
+  //   intervals: [0;2] -> &A, [4;7] -> &C
+  // D = [1;5]
+  //   insert(D) -> true
+  //   intervals: [0;2] -> &A, [3;3] -> &D, [4;7] -> &C
+  // E = [0;unbounded]
+  //   insert(E) -> true
+  //   intervals: [0;unbounded] -> E
+  //
+  // Returns a reference to the first RangeInfo that overlaps with
+  // [Info.LowerBound;Info.UpperBound], or, std::nullopt if there is no overlap
+  // (equivalent to getOverlapping)
+  std::optional<const RangeInfo *> insert(const RangeInfo &Info);
+};
+
+} // namespace rootsig
+} // namespace hlsl
+} // namespace llvm
+
+#endif // LLVM_FRONTEND_HLSL_ROOTSIGNATUREVALIDATIONS_H
diff --git a/llvm/lib/Frontend/HLSL/CMakeLists.txt 
b/llvm/lib/Frontend/HLSL/CMakeLists.txt
index 8b337363b9f84..534346920ff19 100644
--- a/llvm/lib/Frontend/HLSL/CMakeLists.txt
+++ b/llvm/lib/Frontend/HLSL/CMakeLists.txt
@@ -3,6 +3,7 @@ add_llvm_component_library(LLVMFrontendHLSL
   HLSLResource.cpp
   HLSLRootSignature.cpp
   RootSignatureMetadata.cpp
+  RootSignatureValidations.cpp
 
   ADDITIONAL_HEADER_DIRS
   ${LLVM_MAIN_INCLUDE_DIR}/llvm/Frontend
diff --git a/llvm/lib/Frontend/HLSL/HLSLRootSignature.cpp 
b/llvm/lib/Frontend/HLSL/HLSLRootSignature.cpp
index ead017945eefe..78c20a6c5c9ff 100644
--- a/llvm/lib/Frontend/HLSL/HLSLRootSignature.cpp
+++ b/llvm/lib/Frontend/HLSL/HLSLRootSignature.cpp
@@ -239,69 +239,6 @@ void dumpRootElements(raw_ostream &OS, 
ArrayRef<RootElement> Elements) {
   OS << "}";
 }
 
-std::optional<const RangeInfo *>
-ResourceRange::getOverlapping(const RangeInfo &Info) const {
-  MapT::const_iterator Interval = Intervals.find(Info.LowerBound);
-  if (!Interval.valid() || Info.UpperBound < Interval.start())
-    return std::nullopt;
-  return Interval.value();
-}
-
-const RangeInfo *ResourceRange::lookup(uint32_t X) const {
-  return Intervals.lookup(X, nullptr);
-}
-
-void ResourceRange::clear() { return Intervals.clear(); }
-
-std::optional<const RangeInfo *> ResourceRange::insert(const RangeInfo &Info) {
-  uint32_t LowerBound = Info.LowerBound;
-  uint32_t UpperBound = Info.UpperBound;
-
-  std::optional<const RangeInfo *> Res = std::nullopt;
-  MapT::iterator Interval = Intervals.begin();
-
-  while (true) {
-    if (UpperBound < LowerBound)
-      break;
-
-    Interval.advanceTo(LowerBound);
-    if (!Interval.valid()) // No interval found
-      break;
-
-    // Let Interval = [x;y] and [LowerBound;UpperBound] = [a;b] and note that
-    // a <= y implicitly from Intervals.find(LowerBound)
-    if (UpperBound < Interval.start())
-      break; // found interval does not overlap with inserted one
-
-    if (!Res.has_value()) // Update to be the first found intersection
-      Res = Interval.value();
-
-    if (Interval.start() <= LowerBound && UpperBound <= Interval.stop()) {
-      // x <= a <= b <= y implies that [a;b] is covered by [x;y]
-      //  -> so we don't need to insert this, report an overlap
-      return Res;
-    } else if (LowerBound <= Interval.start() &&
-               Interval.stop() <= UpperBound) {
-      // a <= x <= y <= b implies that [x;y] is covered by [a;b]
-      //  -> so remove the existing interval that we will cover with the
-      //  overwrite
-      Interval.erase();
-    } else if (LowerBound < Interval.start() && UpperBound <= Interval.stop()) 
{
-      // a < x <= b <= y implies that [a; x] is not covered but [x;b] is
-      //  -> so set b = x - 1 such that [a;x-1] is now the interval to insert
-      UpperBound = Interval.start() - 1;
-    } else if (Interval.start() <= LowerBound && Interval.stop() < UpperBound) 
{
-      // a < x <= b <= y implies that [y; b] is not covered but [a;y] is
-      //  -> so set a = y + 1 such that [y+1;b] is now the interval to insert
-      LowerBound = Interval.stop() + 1;
-    }
-  }
-
-  assert(LowerBound <= UpperBound && "Attempting to insert an empty interval");
-  Intervals.insert(LowerBound, UpperBound, &Info);
-  return Res;
-}
-
 } // namespace rootsig
 } // namespace hlsl
 } // namespace llvm
diff --git a/llvm/lib/Frontend/HLSL/RootSignatureValidations.cpp 
b/llvm/lib/Frontend/HLSL/RootSignatureValidations.cpp
new file mode 100644
index 0000000000000..9825946d59690
--- /dev/null
+++ b/llvm/lib/Frontend/HLSL/RootSignatureValidations.cpp
@@ -0,0 +1,84 @@
+//===- HLSLRootSignatureValidations.cpp - HLSL Root Signature helpers 
-----===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM 
Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+///
+/// \file This file contains helpers for working with HLSL Root Signatures.
+///
+//===----------------------------------------------------------------------===//
+
+#include "llvm/Frontend/HLSL/RootSignatureValidations.h"
+
+namespace llvm {
+namespace hlsl {
+namespace rootsig {
+
+std::optional<const RangeInfo *>
+ResourceRange::getOverlapping(const RangeInfo &Info) const {
+  MapT::const_iterator Interval = Intervals.find(Info.LowerBound);
+  if (!Interval.valid() || Info.UpperBound < Interval.start())
+    return std::nullopt;
+  return Interval.value();
+}
+
+const RangeInfo *ResourceRange::lookup(uint32_t X) const {
+  return Intervals.lookup(X, nullptr);
+}
+
+void ResourceRange::clear() { return Intervals.clear(); }
+
+std::optional<const RangeInfo *> ResourceRange::insert(const RangeInfo &Info) {
+  uint32_t LowerBound = Info.LowerBound;
+  uint32_t UpperBound = Info.UpperBound;
+
+  std::optional<const RangeInfo *> Res = std::nullopt;
+  MapT::iterator Interval = Intervals.begin();
+
+  while (true) {
+    if (UpperBound < LowerBound)
+      break;
+
+    Interval.advanceTo(LowerBound);
+    if (!Interval.valid()) // No interval found
+      break;
+
+    // Let Interval = [x;y] and [LowerBound;UpperBound] = [a;b] and note that
+    // a <= y implicitly from Intervals.find(LowerBound)
+    if (UpperBound < Interval.start())
+      break; // found interval does not overlap with inserted one
+
+    if (!Res.has_value()) // Update to be the first found intersection
+      Res = Interval.value();
+
+    if (Interval.start() <= LowerBound && UpperBound <= Interval.stop()) {
+      // x <= a <= b <= y implies that [a;b] is covered by [x;y]
+      //  -> so we don't need to insert this, report an overlap
+      return Res;
+    } else if (LowerBound <= Interval.start() &&
+               Interval.stop() <= UpperBound) {
+      // a <= x <= y <= b implies that [x;y] is covered by [a;b]
+      //  -> so remove the existing interval that we will cover with the
+      //  overwrite
+      Interval.erase();
+    } else if (LowerBound < Interval.start() && UpperBound <= Interval.stop()) 
{
+      // a < x <= b <= y implies that [a; x] is not covered but [x;b] is
+      //  -> so set b = x - 1 such that [a;x-1] is now the interval to insert
+      UpperBound = Interval.start() - 1;
+    } else if (Interval.start() <= LowerBound && Interval.stop() < UpperBound) 
{
+      // a < x <= b <= y implies that [y; b] is not covered but [a;y] is
+      //  -> so set a = y + 1 such that [y+1;b] is now the interval to insert
+      LowerBound = Interval.stop() + 1;
+    }
+  }
+
+  assert(LowerBound <= UpperBound && "Attempting to insert an empty interval");
+  Intervals.insert(LowerBound, UpperBound, &Info);
+  return Res;
+}
+
+} // namespace rootsig
+} // namespace hlsl
+} // namespace llvm
diff --git a/llvm/unittests/Frontend/HLSLRootSignatureRangesTest.cpp 
b/llvm/unittests/Frontend/HLSLRootSignatureRangesTest.cpp
index d026b03b4803f..be3f51e0e83d5 100644
--- a/llvm/unittests/Frontend/HLSLRootSignatureRangesTest.cpp
+++ b/llvm/unittests/Frontend/HLSLRootSignatureRangesTest.cpp
@@ -6,7 +6,7 @@
 //
 
//===----------------------------------------------------------------------===//
 
-#include "llvm/Frontend/HLSL/HLSLRootSignature.h"
+#include "llvm/Frontend/HLSL/RootSignatureValidations.h"
 #include "gtest/gtest.h"
 
 using namespace llvm::hlsl::rootsig;

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

Reply via email to