@@ -1077,110 +1077,128 @@ void SemaHLSL::ActOnFinishRootSignatureDecl(
10771077 SemaRef.PushOnScopeChains (SignatureDecl, SemaRef.getCurScope ());
10781078}
10791079
1080- namespace {
1081-
1082- // A resource range overlaps with another resource range if they have:
1083- // - equivalent ResourceClass (SRV, UAV, CBuffer, Sampler)
1084- // - equivalent resource space
1085- // - overlapping visbility
1086- class ResourceRanges {
1087- public:
1088- // KeyT: 32-lsb denotes resource space, and 32-msb denotes ResourceClass enum
1089- using KeyT = std::pair<ResourceClass, uint32_t >;
1090-
1091- static const size_t NumVisEnums = 8 ;
1092-
1093- private:
1094- llvm::hlsl::rootsig::ResourceRange::MapT::Allocator Allocator;
1095-
1096- // Denotes a mapping of a unique combination of ResourceClass and register
1097- // space to a ResourceRange
1098- using MapT = llvm::SmallDenseMap<KeyT, llvm::hlsl::rootsig::ResourceRange>;
1099-
1100- // Denotes a mapping for each unique visibility
1101- MapT RangeMaps[NumVisEnums];
1102-
1103- constexpr static KeyT getKey (const llvm::hlsl::rootsig::RangeInfo &Info) {
1104- return {Info.Class , Info.Space };
1105- }
1106-
1107- public:
1108- // Returns std::nullopt if there was no collision. Otherwise, it will
1109- // return the RangeInfo of the collision
1110- std::optional<const llvm::hlsl::rootsig::RangeInfo *>
1111- addRange (const llvm::hlsl::rootsig::RangeInfo &Info) {
1112- MapT &VisRangeMap = RangeMaps[llvm::to_underlying (Info.Vis )];
1113- auto [It, _] = VisRangeMap.insert (
1114- {getKey (Info), llvm::hlsl::rootsig::ResourceRange (Allocator)});
1115- auto Res = It->second .insert (Info);
1116- if (Res.has_value ())
1117- return Res;
1118-
1119- // If the range that we are inserting has ShaderVisiblity::All it needs to
1120- // check for an overlap in all other visibility types as well.
1121- // Otherwise, the range that is inserted needs to check that it does not
1122- // overlap with ShaderVisibility::All.
1123- //
1124- // Maps will be an ArrayRef to all non-all visibility RangeMaps in the
1125- // former case and it will be an ArrayRef to just the all visiblity
1126- // RangeMap in the latter case.
1127- MutableArrayRef<MapT> Maps =
1128- Info.Vis == llvm::hlsl::rootsig::ShaderVisibility::All
1129- ? MutableArrayRef<MapT>{RangeMaps}.drop_front ()
1130- : MutableArrayRef<MapT>{RangeMaps}.take_front ();
1131-
1132- for (MapT &CurMap : Maps) {
1133- auto CurIt = CurMap.find (getKey (Info));
1134- if (CurIt != CurMap.end ())
1135- if (auto Overlapping = CurIt->second .getOverlapping (Info))
1136- return Overlapping;
1137- }
1138-
1139- return std::nullopt ;
1140- }
1141- };
1142-
1143- } // namespace
1144-
11451080bool SemaHLSL::handleRootSignatureDecl (HLSLRootSignatureDecl *D,
11461081 SourceLocation Loc) {
11471082 auto Elements = D->getRootElements ();
11481083
1149- // First we will go through and collect our range info
1150- llvm::SmallVector<llvm::hlsl::rootsig::RangeInfo> Infos;
1084+ // The following conducts analysis on resource ranges to detect and report
1085+ // any overlaps in resource ranges.
1086+ //
1087+ // A resource range overlaps with another resource range if they have:
1088+ // - equivalent ResourceClass (SRV, UAV, CBuffer, Sampler)
1089+ // - equivalent resource space
1090+ // - overlapping visbility
1091+ //
1092+ // The following algorithm is implemented in the following steps:
1093+ //
1094+ // 1. Collect RangeInfo from relevant RootElements:
1095+ // - RangeInfo will retain the interval, ResourceClass, Space and Visibility
1096+ // 2. Sort the RangeInfo's such that they are grouped together by
1097+ // ResourceClass and Space (GroupT defined below)
1098+ // 3. Iterate through the collected RangeInfos by their groups
1099+ // - For each group we will have a ResourceRange for each visibility
1100+ // - As we iterate through we will:
1101+ // A: Insert the current RangeInfo into the corresponding Visibility
1102+ // ResourceRange
1103+ // B: Check for overlap with any overlapping Visibility ResourceRange
1104+ using RangeInfo = llvm::hlsl::rootsig::RangeInfo;
1105+ using ResourceRange = llvm::hlsl::rootsig::ResourceRange;
1106+ using GroupT = std::pair<ResourceClass, /* Space*/ uint32_t >;
1107+
1108+ // 1. Collect RangeInfos
1109+ llvm::SmallVector<RangeInfo> Infos;
11511110 for (const auto &Elem : Elements) {
11521111 if (const auto *Descriptor =
11531112 std::get_if<llvm::hlsl::rootsig::RootDescriptor>(&Elem)) {
1154- llvm::hlsl::rootsig:: RangeInfo Info;
1113+ RangeInfo Info;
11551114 Info.LowerBound = Descriptor->Reg .Number ;
11561115 Info.UpperBound = Info.LowerBound ; // use inclusive ranges []
11571116
1158- Info.Class = llvm::dxil::ResourceClass (llvm::to_underlying (Descriptor->Type ));
1117+ Info.Class =
1118+ llvm::dxil::ResourceClass (llvm::to_underlying (Descriptor->Type ));
11591119 Info.Space = Descriptor->Space ;
11601120 Info.Vis = Descriptor->Visibility ;
11611121 Infos.push_back (Info);
11621122 }
11631123 }
11641124
1165- // Iterate through info and attempt to insert corresponding range
1166- ResourceRanges Ranges;
1125+ // 2. Sort the RangeInfo's by their GroupT to form groupings
1126+ std::sort (Infos.begin (), Infos.end (), [](RangeInfo A, RangeInfo B) {
1127+ return std::tie (A.Class , A.Space ) < std::tie (B.Class , B.Space );
1128+ });
1129+
1130+ // 3. First we will init our state to track:
1131+ if (Infos.size () == 0 )
1132+ return false ; // No ranges to overlap
1133+ GroupT CurGroup = {Infos[0 ].Class , Infos[0 ].Space };
11671134 bool HadOverlap = false ;
1168- for (const llvm::hlsl::rootsig::RangeInfo &Info : Infos)
1169- if (auto MaybeOverlappingInfo = Ranges.addRange (Info)) {
1170- const llvm::hlsl::rootsig::RangeInfo *OInfo =
1171- MaybeOverlappingInfo.value ();
1172- auto CommonVis = Info.Vis == llvm::hlsl::rootsig::ShaderVisibility::All
1173- ? OInfo->Vis
1174- : Info.Vis ;
11751135
1176- Diag (Loc, diag::err_hlsl_resource_range_overlap)
1177- << llvm::to_underlying (Info.Class ) << Info.LowerBound
1178- << Info.UpperBound << llvm::to_underlying (OInfo->Class )
1179- << OInfo->LowerBound << OInfo->UpperBound << Info.Space << CommonVis;
1136+ // Create a ResourceRange for each Visibility
1137+ ResourceRange::MapT::Allocator Allocator;
1138+ SmallVector<ResourceRange, 8 > Ranges = {
1139+ ResourceRange (Allocator), // All
1140+ ResourceRange (Allocator), // Vertex
1141+ ResourceRange (Allocator), // Hull
1142+ ResourceRange (Allocator), // Domain
1143+ ResourceRange (Allocator), // Geometry
1144+ ResourceRange (Allocator), // Pixel
1145+ ResourceRange (Allocator), // Amplification
1146+ ResourceRange (Allocator), // Mesh
1147+ };
1148+
1149+ // Reset the ResourceRanges for when we iterate through a new group
1150+ auto ClearRanges = [&Ranges]() {
1151+ for (ResourceRange &Range : Ranges)
1152+ Range.clear ();
1153+ };
11801154
1181- HadOverlap = true ;
1155+ // Helper to report diagnostics
1156+ auto ReportOverlap = [this , Loc, &HadOverlap](const RangeInfo *Info,
1157+ const RangeInfo *OInfo) {
1158+ HadOverlap = true ;
1159+ auto CommonVis = Info->Vis == llvm::hlsl::rootsig::ShaderVisibility::All
1160+ ? OInfo->Vis
1161+ : Info->Vis ;
1162+ this ->Diag (Loc, diag::err_hlsl_resource_range_overlap)
1163+ << llvm::to_underlying (Info->Class ) << Info->LowerBound
1164+ << Info->UpperBound << llvm::to_underlying (OInfo->Class )
1165+ << OInfo->LowerBound << OInfo->UpperBound << Info->Space << CommonVis;
1166+ };
1167+
1168+ // 3: Iterate throught collected RangeInfos
1169+ for (const RangeInfo &Info : Infos) {
1170+ GroupT InfoGroup = {Info.Class , Info.Space };
1171+ // Reset our ResourceRanges when we enter a new group
1172+ if (CurGroup != InfoGroup) {
1173+ ClearRanges ();
1174+ CurGroup = InfoGroup;
11821175 }
11831176
1177+ // 3A: Insert range info into corresponding Visibility ResourceRange
1178+ ResourceRange &VisRange = Ranges[llvm::to_underlying (Info.Vis )];
1179+ if (auto Overlapping = VisRange.insert (Info))
1180+ ReportOverlap (&Info, Overlapping.value ());
1181+
1182+ // 3B: Check for overlap in all overlapping Visibility ResourceRanges
1183+ //
1184+ // If the range that we are inserting has ShaderVisiblity::All it needs to
1185+ // check for an overlap in all other visibility types as well.
1186+ // Otherwise, the range that is inserted needs to check that it does not
1187+ // overlap with ShaderVisibility::All.
1188+ //
1189+ // Maps will be an ArrayRef to all non-all visibility RangeMaps in the
1190+ // former case and it will be an ArrayRef to just the all visiblity
1191+ // RangeMap in the latter case.
1192+ MutableArrayRef<ResourceRange> OverlapRanges =
1193+ Info.Vis == llvm::hlsl::rootsig::ShaderVisibility::All
1194+ ? MutableArrayRef<ResourceRange>{Ranges}.drop_front ()
1195+ : MutableArrayRef<ResourceRange>{Ranges}.take_front ();
1196+
1197+ for (ResourceRange &Range : OverlapRanges)
1198+ if (auto Overlapping = Range.getOverlapping (Info))
1199+ ReportOverlap (&Info, Overlapping.value ());
1200+ }
1201+
11841202 return HadOverlap;
11851203}
11861204
0 commit comments