[clang] [llvm] [HLSL][RootSignature] Implement validation of resource ranges for `RootDescriptors` (PR #140962)
Justin Bogner via llvm-commits
llvm-commits at lists.llvm.org
Thu Jun 19 16:03:41 PDT 2025
================
@@ -1068,10 +1069,139 @@ void SemaHLSL::ActOnFinishRootSignatureDecl(
SemaRef.getASTContext(), /*DeclContext=*/SemaRef.CurContext, Loc,
DeclIdent, Elements);
+ // Perform validation of constructs here
+ if (handleRootSignatureDecl(SignatureDecl, Loc))
+ return;
+
SignatureDecl->setImplicit();
SemaRef.PushOnScopeChains(SignatureDecl, SemaRef.getCurScope());
}
+bool SemaHLSL::handleRootSignatureDecl(HLSLRootSignatureDecl *D,
+ SourceLocation Loc) {
+ auto Elements = D->getRootElements();
+
+ // 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>;
+
+ // 1. Collect RangeInfos
+ llvm::SmallVector<RangeInfo> Infos;
+ for (const auto &Elem : Elements) {
+ if (const auto *Descriptor =
+ std::get_if<llvm::hlsl::rootsig::RootDescriptor>(&Elem)) {
+ RangeInfo Info;
+ Info.LowerBound = Descriptor->Reg.Number;
+ Info.UpperBound = Info.LowerBound; // use inclusive ranges []
+
+ Info.Class =
+ llvm::dxil::ResourceClass(llvm::to_underlying(Descriptor->Type));
+ Info.Space = Descriptor->Space;
+ Info.Vis = Descriptor->Visibility;
+ Infos.push_back(Info);
+ }
+ }
+
+ // 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;
+ SmallVector<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, Loc, &HadOverlap](const RangeInfo *Info,
+ const RangeInfo *OInfo) {
+ HadOverlap = true;
+ auto CommonVis = Info->Vis == llvm::hlsl::rootsig::ShaderVisibility::All
+ ? OInfo->Vis
+ : Info->Vis;
+ this->Diag(Loc, diag::err_hlsl_resource_range_overlap)
+ << llvm::to_underlying(Info->Class) << Info->LowerBound
+ << Info->UpperBound << llvm::to_underlying(OInfo->Class)
+ << OInfo->LowerBound << OInfo->UpperBound << Info->Space << CommonVis;
+ };
+
+ // 3: Iterate throught 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.Vis)];
+ if (auto Overlapping = VisRange.insert(Info))
----------------
bogner wrote:
I'd probably spell the type out here.
```suggestion
if (std::optional<const RangeInfo *> Overlapping = VisRange.insert(Info))
```
Same below where we call `getOverlapping`.
https://github.com/llvm/llvm-project/pull/140962
More information about the llvm-commits
mailing list