[llvm-branch-commits] [clang] [llvm] [NFC][HLSL] Move resource range logic from `SemaHLSL` to `RootSignatureValidations` (PR #147117)

via llvm-branch-commits llvm-branch-commits at lists.llvm.org
Fri Jul 4 15:27:55 PDT 2025


llvmbot wrote:


<!--LLVM PR SUMMARY COMMENT-->

@llvm/pr-subscribers-hlsl

Author: Finn Plummer (inbelic)

<details>
<summary>Changes</summary>

This pr abstracts out the logic of detecting resource range overlap from `SemaHLSL` into the `RootSignatureValidations` library.

For more context see linked issue.

- Moves the validation logic from `SemaHLSL` to `RootSignatureValidations`
- Updates `SemaHLSL` to use the new interface for the validations

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

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


3 Files Affected:

- (modified) clang/lib/Sema/SemaHLSL.cpp (+10-91) 
- (modified) llvm/include/llvm/Frontend/HLSL/RootSignatureValidations.h (+32) 
- (modified) llvm/lib/Frontend/HLSL/RootSignatureValidations.cpp (+73) 


``````````diff
diff --git a/clang/lib/Sema/SemaHLSL.cpp b/clang/lib/Sema/SemaHLSL.cpp
index 3feb27ac44bd6..18b84c33b39c8 100644
--- a/clang/lib/Sema/SemaHLSL.cpp
+++ b/clang/lib/Sema/SemaHLSL.cpp
@@ -1083,29 +1083,8 @@ void SemaHLSL::ActOnFinishRootSignatureDecl(
 
 bool SemaHLSL::handleRootSignatureElements(
     ArrayRef<hlsl::RootSignatureElement> Elements) {
-  // The following conducts analysis on resource ranges to detect and report
-  // any overlaps in resource ranges.
-  //
-  // A resource range overlaps with another resource range if they have:
-  // - equivalent ResourceClass (SRV, UAV, CBuffer, Sampler)
-  // - equivalent resource space
-  // - overlapping visbility
-  //
-  // The following algorithm is implemented in the following steps:
-  //
-  // 1. Collect RangeInfo from relevant RootElements:
-  //   - RangeInfo will retain the interval, ResourceClass, Space and Visibility
-  // 2. Sort the RangeInfo's such that they are grouped together by
-  //  ResourceClass and Space (GroupT defined below)
-  // 3. Iterate through the collected RangeInfos by their groups
-  //   - For each group we will have a ResourceRange for each visibility
-  //   - As we iterate through we will:
-  //      A: Insert the current RangeInfo into the corresponding Visibility
-  //   ResourceRange
-  //      B: Check for overlap with any overlapping Visibility ResourceRange
   using RangeInfo = llvm::hlsl::rootsig::RangeInfo;
-  using ResourceRange = llvm::hlsl::rootsig::ResourceRange;
-  using GroupT = std::pair<ResourceClass, /*Space*/ uint32_t>;
+  using OverlappingRanges = llvm::hlsl::rootsig::OverlappingRanges;
 
   // Introduce a mapping from the collected RangeInfos back to the
   // RootSignatureElement that will retain its diagnostics info
@@ -1188,40 +1167,10 @@ bool SemaHLSL::handleRootSignatureElements(
     }
   }
 
-  // 2. Sort the RangeInfo's by their GroupT to form groupings
-  std::sort(Infos.begin(), Infos.end(), [](RangeInfo A, RangeInfo B) {
-    return std::tie(A.Class, A.Space) < std::tie(B.Class, B.Space);
-  });
-
-  // 3. First we will init our state to track:
-  if (Infos.size() == 0)
-    return false; // No ranges to overlap
-  GroupT CurGroup = {Infos[0].Class, Infos[0].Space};
-  bool HadOverlap = false;
-
-  // Create a ResourceRange for each Visibility
-  ResourceRange::MapT::Allocator Allocator;
-  std::array<ResourceRange, 8> Ranges = {
-      ResourceRange(Allocator), // All
-      ResourceRange(Allocator), // Vertex
-      ResourceRange(Allocator), // Hull
-      ResourceRange(Allocator), // Domain
-      ResourceRange(Allocator), // Geometry
-      ResourceRange(Allocator), // Pixel
-      ResourceRange(Allocator), // Amplification
-      ResourceRange(Allocator), // Mesh
-  };
-
-  // Reset the ResourceRanges for when we iterate through a new group
-  auto ClearRanges = [&Ranges]() {
-    for (ResourceRange &Range : Ranges)
-      Range.clear();
-  };
-
   // Helper to report diagnostics
-  auto ReportOverlap = [this, InfoIndexMap, &HadOverlap](
-                           const RangeInfo *Info, const RangeInfo *OInfo) {
-    HadOverlap = true;
+  auto ReportOverlap = [this, InfoIndexMap](OverlappingRanges Overlap) {
+    const RangeInfo *Info = Overlap.A;
+    const RangeInfo *OInfo = Overlap.B;
     auto CommonVis = Info->Visibility == llvm::dxbc::ShaderVisibility::All
                          ? OInfo->Visibility
                          : Info->Visibility;
@@ -1240,42 +1189,12 @@ bool SemaHLSL::handleRootSignatureElements(
     this->Diag(OInfoLoc, diag::note_hlsl_resource_range_here);
   };
 
-  // 3: Iterate through collected RangeInfos
-  for (const RangeInfo &Info : Infos) {
-    GroupT InfoGroup = {Info.Class, Info.Space};
-    // Reset our ResourceRanges when we enter a new group
-    if (CurGroup != InfoGroup) {
-      ClearRanges();
-      CurGroup = InfoGroup;
-    }
-
-    // 3A: Insert range info into corresponding Visibility ResourceRange
-    ResourceRange &VisRange = Ranges[llvm::to_underlying(Info.Visibility)];
-    if (std::optional<const RangeInfo *> Overlapping = VisRange.insert(Info))
-      ReportOverlap(&Info, Overlapping.value());
-
-    // 3B: Check for overlap in all overlapping Visibility ResourceRanges
-    //
-    // If the range that we are inserting has ShaderVisiblity::All it needs to
-    // check for an overlap in all other visibility types as well.
-    // Otherwise, the range that is inserted needs to check that it does not
-    // overlap with ShaderVisibility::All.
-    //
-    // OverlapRanges will be an ArrayRef to all non-all visibility
-    // ResourceRanges in the former case and it will be an ArrayRef to just the
-    // all visiblity ResourceRange in the latter case.
-    ArrayRef<ResourceRange> OverlapRanges =
-        Info.Visibility == llvm::dxbc::ShaderVisibility::All
-            ? ArrayRef<ResourceRange>{Ranges}.drop_front()
-            : ArrayRef<ResourceRange>{Ranges}.take_front();
-
-    for (const ResourceRange &Range : OverlapRanges)
-      if (std::optional<const RangeInfo *> Overlapping =
-              Range.getOverlapping(Info))
-        ReportOverlap(&Info, Overlapping.value());
-  }
-
-  return HadOverlap;
+  llvm::SmallVector<OverlappingRanges> Overlaps =
+      llvm::hlsl::rootsig::findOverlappingRanges(Infos);
+  for (OverlappingRanges Overlap : Overlaps)
+    ReportOverlap(Overlap);
+
+  return Overlaps.size() != 0;
 }
 
 void SemaHLSL::handleRootSignatureAttr(Decl *D, const ParsedAttr &AL) {
diff --git a/llvm/include/llvm/Frontend/HLSL/RootSignatureValidations.h b/llvm/include/llvm/Frontend/HLSL/RootSignatureValidations.h
index 6bb59027a4cac..0f35850c3922f 100644
--- a/llvm/include/llvm/Frontend/HLSL/RootSignatureValidations.h
+++ b/llvm/include/llvm/Frontend/HLSL/RootSignatureValidations.h
@@ -88,6 +88,38 @@ class ResourceRange {
   LLVM_ABI std::optional<const RangeInfo *> insert(const RangeInfo &Info);
 };
 
+struct OverlappingRanges {
+  const RangeInfo *A;
+  const RangeInfo *B;
+
+  OverlappingRanges(const RangeInfo *A, const RangeInfo *B) : A(A), B(B) {}
+};
+
+/// The following conducts analysis on resource ranges to detect and report
+/// any overlaps in resource ranges.
+///
+/// A resource range overlaps with another resource range if they have:
+/// - equivalent ResourceClass (SRV, UAV, CBuffer, Sampler)
+/// - equivalent resource space
+/// - overlapping visbility
+///
+/// The algorithm is implemented in the following steps:
+///
+/// 1. The user will collect RangeInfo from relevant RootElements:
+///   - RangeInfo will retain the interval, ResourceClass, Space and Visibility
+///   - It will also contain an index so that it can be associated to
+/// additional diagnostic information
+/// 2. Sort the RangeInfo's such that they are grouped together by
+///  ResourceClass and Space
+/// 3. Iterate through the collected RangeInfos by their groups
+///   - For each group we will have a ResourceRange for each visibility
+///   - As we iterate through we will:
+///      A: Insert the current RangeInfo into the corresponding Visibility
+///   ResourceRange
+///      B: Check for overlap with any overlapping Visibility ResourceRange
+llvm::SmallVector<OverlappingRanges>
+findOverlappingRanges(llvm::SmallVector<RangeInfo> &Infos);
+
 } // namespace rootsig
 } // namespace hlsl
 } // namespace llvm
diff --git a/llvm/lib/Frontend/HLSL/RootSignatureValidations.cpp b/llvm/lib/Frontend/HLSL/RootSignatureValidations.cpp
index 9825946d59690..118b570538f9e 100644
--- a/llvm/lib/Frontend/HLSL/RootSignatureValidations.cpp
+++ b/llvm/lib/Frontend/HLSL/RootSignatureValidations.cpp
@@ -79,6 +79,79 @@ std::optional<const RangeInfo *> ResourceRange::insert(const RangeInfo &Info) {
   return Res;
 }
 
+llvm::SmallVector<OverlappingRanges>
+findOverlappingRanges(llvm::SmallVector<RangeInfo> &Infos) {
+  // 1. The user has provided the corresponding range information
+  llvm::SmallVector<OverlappingRanges> Overlaps;
+  using GroupT = std::pair<dxil::ResourceClass, /*Space*/ uint32_t>;
+
+  // 2. Sort the RangeInfo's by their GroupT to form groupings
+  std::sort(Infos.begin(), Infos.end(), [](RangeInfo A, RangeInfo B) {
+    return std::tie(A.Class, A.Space) < std::tie(B.Class, B.Space);
+  });
+
+  // 3. First we will init our state to track:
+  if (Infos.size() == 0)
+    return Overlaps; // No ranges to overlap
+  GroupT CurGroup = {Infos[0].Class, Infos[0].Space};
+
+  // Create a ResourceRange for each Visibility
+  ResourceRange::MapT::Allocator Allocator;
+  std::array<ResourceRange, 8> Ranges = {
+      ResourceRange(Allocator), // All
+      ResourceRange(Allocator), // Vertex
+      ResourceRange(Allocator), // Hull
+      ResourceRange(Allocator), // Domain
+      ResourceRange(Allocator), // Geometry
+      ResourceRange(Allocator), // Pixel
+      ResourceRange(Allocator), // Amplification
+      ResourceRange(Allocator), // Mesh
+  };
+
+  // Reset the ResourceRanges for when we iterate through a new group
+  auto ClearRanges = [&Ranges]() {
+    for (ResourceRange &Range : Ranges)
+      Range.clear();
+  };
+
+  // 3: Iterate through collected RangeInfos
+  for (const RangeInfo &Info : Infos) {
+    GroupT InfoGroup = {Info.Class, Info.Space};
+    // Reset our ResourceRanges when we enter a new group
+    if (CurGroup != InfoGroup) {
+      ClearRanges();
+      CurGroup = InfoGroup;
+    }
+
+    // 3A: Insert range info into corresponding Visibility ResourceRange
+    ResourceRange &VisRange = Ranges[llvm::to_underlying(Info.Visibility)];
+    if (std::optional<const RangeInfo *> Overlapping = VisRange.insert(Info))
+      Overlaps.push_back(OverlappingRanges(&Info, Overlapping.value()));
+
+    // 3B: Check for overlap in all overlapping Visibility ResourceRanges
+    //
+    // If the range that we are inserting has ShaderVisiblity::All it needs to
+    // check for an overlap in all other visibility types as well.
+    // Otherwise, the range that is inserted needs to check that it does not
+    // overlap with ShaderVisibility::All.
+    //
+    // OverlapRanges will be an ArrayRef to all non-all visibility
+    // ResourceRanges in the former case and it will be an ArrayRef to just the
+    // all visiblity ResourceRange in the latter case.
+    ArrayRef<ResourceRange> OverlapRanges =
+        Info.Visibility == llvm::dxbc::ShaderVisibility::All
+            ? ArrayRef<ResourceRange>{Ranges}.drop_front()
+            : ArrayRef<ResourceRange>{Ranges}.take_front();
+
+    for (const ResourceRange &Range : OverlapRanges)
+      if (std::optional<const RangeInfo *> Overlapping =
+              Range.getOverlapping(Info))
+        Overlaps.push_back(OverlappingRanges(&Info, Overlapping.value()));
+  }
+
+  return Overlaps;
+}
+
 } // namespace rootsig
 } // namespace hlsl
 } // namespace llvm

``````````

</details>


https://github.com/llvm/llvm-project/pull/147117


More information about the llvm-branch-commits mailing list