@@ -1077,110 +1077,128 @@ void SemaHLSL::ActOnFinishRootSignatureDecl(
1077
1077
SemaRef.PushOnScopeChains (SignatureDecl, SemaRef.getCurScope ());
1078
1078
}
1079
1079
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
-
1145
1080
bool SemaHLSL::handleRootSignatureDecl (HLSLRootSignatureDecl *D,
1146
1081
SourceLocation Loc) {
1147
1082
auto Elements = D->getRootElements ();
1148
1083
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;
1151
1110
for (const auto &Elem : Elements) {
1152
1111
if (const auto *Descriptor =
1153
1112
std::get_if<llvm::hlsl::rootsig::RootDescriptor>(&Elem)) {
1154
- llvm::hlsl::rootsig:: RangeInfo Info;
1113
+ RangeInfo Info;
1155
1114
Info.LowerBound = Descriptor->Reg .Number ;
1156
1115
Info.UpperBound = Info.LowerBound ; // use inclusive ranges []
1157
1116
1158
- Info.Class = llvm::dxil::ResourceClass (llvm::to_underlying (Descriptor->Type ));
1117
+ Info.Class =
1118
+ llvm::dxil::ResourceClass (llvm::to_underlying (Descriptor->Type ));
1159
1119
Info.Space = Descriptor->Space ;
1160
1120
Info.Vis = Descriptor->Visibility ;
1161
1121
Infos.push_back (Info);
1162
1122
}
1163
1123
}
1164
1124
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 };
1167
1134
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 ;
1175
1135
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
+ };
1180
1154
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;
1182
1175
}
1183
1176
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
+
1184
1202
return HadOverlap;
1185
1203
}
1186
1204
0 commit comments