Author: Finn Plummer Date: 2025-07-08T18:13:36-07:00 New Revision: aa1829df02b24cb8f4a1846348b5a7b4e0be62f8
URL: https://github.com/llvm/llvm-project/commit/aa1829df02b24cb8f4a1846348b5a7b4e0be62f8 DIFF: https://github.com/llvm/llvm-project/commit/aa1829df02b24cb8f4a1846348b5a7b4e0be62f8.diff LOG: [NFC][HLSL] Move resource range logic from `SemaHLSL` to `RootSignatureValidations` (#147117) 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 Added: Modified: clang/lib/Sema/SemaHLSL.cpp llvm/include/llvm/Frontend/HLSL/RootSignatureValidations.h llvm/lib/Frontend/HLSL/RootSignatureValidations.cpp Removed: ################################################################################ diff --git a/clang/lib/Sema/SemaHLSL.cpp b/clang/lib/Sema/SemaHLSL.cpp index 968b96990bd85..cc50d23e0b998 100644 --- a/clang/lib/Sema/SemaHLSL.cpp +++ b/clang/lib/Sema/SemaHLSL.cpp @@ -1079,29 +1079,8 @@ void SemaHLSL::ActOnFinishRootSignatureDecl( bool SemaHLSL::handleRootSignatureDecl(HLSLRootSignatureDecl *D, SourceLocation Loc) { - // 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; // 1. Collect RangeInfos llvm::SmallVector<RangeInfo> Infos; @@ -1166,40 +1145,10 @@ bool SemaHLSL::handleRootSignatureDecl(HLSLRootSignatureDecl *D, } } - // 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, Loc, &HadOverlap](const RangeInfo *Info, - const RangeInfo *OInfo) { - HadOverlap = true; + auto ReportOverlap = [this, Loc](OverlappingRanges Overlap) { + const RangeInfo *Info = Overlap.A; + const RangeInfo *OInfo = Overlap.B; auto CommonVis = Info->Visibility == llvm::dxbc::ShaderVisibility::All ? OInfo->Visibility : Info->Visibility; @@ -1212,42 +1161,12 @@ bool SemaHLSL::handleRootSignatureDecl(HLSLRootSignatureDecl *D, << OInfo->UpperBound << Info->Space << CommonVis; }; - // 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 9b68a524432cc..7e0f50a58e25e 100644 --- a/llvm/include/llvm/Frontend/HLSL/RootSignatureValidations.h +++ b/llvm/include/llvm/Frontend/HLSL/RootSignatureValidations.h @@ -46,7 +46,7 @@ struct RangeInfo { uint32_t LowerBound; uint32_t UpperBound; - // Information retained for diagnostics + // Information retained for determining overlap llvm::dxil::ResourceClass Class; uint32_t Space; llvm::dxbc::ShaderVisibility Visibility; @@ -103,6 +103,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 b5b5fc0c74d83..6454d74c85717 100644 --- a/llvm/lib/Frontend/HLSL/RootSignatureValidations.cpp +++ b/llvm/lib/Frontend/HLSL/RootSignatureValidations.cpp @@ -222,6 +222,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 _______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits