Skip to content

Commit aa1829d

Browse files
authored
[NFC][HLSL] Move resource range logic from SemaHLSL to RootSignatureValidations (llvm#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: llvm#146393
1 parent 191386f commit aa1829d

File tree

3 files changed

+116
-92
lines changed

3 files changed

+116
-92
lines changed

clang/lib/Sema/SemaHLSL.cpp

Lines changed: 10 additions & 91 deletions
Original file line numberDiff line numberDiff line change
@@ -1079,29 +1079,8 @@ void SemaHLSL::ActOnFinishRootSignatureDecl(
10791079

10801080
bool SemaHLSL::handleRootSignatureDecl(HLSLRootSignatureDecl *D,
10811081
SourceLocation Loc) {
1082-
// The following conducts analysis on resource ranges to detect and report
1083-
// any overlaps in resource ranges.
1084-
//
1085-
// A resource range overlaps with another resource range if they have:
1086-
// - equivalent ResourceClass (SRV, UAV, CBuffer, Sampler)
1087-
// - equivalent resource space
1088-
// - overlapping visbility
1089-
//
1090-
// The following algorithm is implemented in the following steps:
1091-
//
1092-
// 1. Collect RangeInfo from relevant RootElements:
1093-
// - RangeInfo will retain the interval, ResourceClass, Space and Visibility
1094-
// 2. Sort the RangeInfo's such that they are grouped together by
1095-
// ResourceClass and Space (GroupT defined below)
1096-
// 3. Iterate through the collected RangeInfos by their groups
1097-
// - For each group we will have a ResourceRange for each visibility
1098-
// - As we iterate through we will:
1099-
// A: Insert the current RangeInfo into the corresponding Visibility
1100-
// ResourceRange
1101-
// B: Check for overlap with any overlapping Visibility ResourceRange
11021082
using RangeInfo = llvm::hlsl::rootsig::RangeInfo;
1103-
using ResourceRange = llvm::hlsl::rootsig::ResourceRange;
1104-
using GroupT = std::pair<ResourceClass, /*Space*/ uint32_t>;
1083+
using OverlappingRanges = llvm::hlsl::rootsig::OverlappingRanges;
11051084

11061085
// 1. Collect RangeInfos
11071086
llvm::SmallVector<RangeInfo> Infos;
@@ -1166,40 +1145,10 @@ bool SemaHLSL::handleRootSignatureDecl(HLSLRootSignatureDecl *D,
11661145
}
11671146
}
11681147

1169-
// 2. Sort the RangeInfo's by their GroupT to form groupings
1170-
std::sort(Infos.begin(), Infos.end(), [](RangeInfo A, RangeInfo B) {
1171-
return std::tie(A.Class, A.Space) < std::tie(B.Class, B.Space);
1172-
});
1173-
1174-
// 3. First we will init our state to track:
1175-
if (Infos.size() == 0)
1176-
return false; // No ranges to overlap
1177-
GroupT CurGroup = {Infos[0].Class, Infos[0].Space};
1178-
bool HadOverlap = false;
1179-
1180-
// Create a ResourceRange for each Visibility
1181-
ResourceRange::MapT::Allocator Allocator;
1182-
std::array<ResourceRange, 8> Ranges = {
1183-
ResourceRange(Allocator), // All
1184-
ResourceRange(Allocator), // Vertex
1185-
ResourceRange(Allocator), // Hull
1186-
ResourceRange(Allocator), // Domain
1187-
ResourceRange(Allocator), // Geometry
1188-
ResourceRange(Allocator), // Pixel
1189-
ResourceRange(Allocator), // Amplification
1190-
ResourceRange(Allocator), // Mesh
1191-
};
1192-
1193-
// Reset the ResourceRanges for when we iterate through a new group
1194-
auto ClearRanges = [&Ranges]() {
1195-
for (ResourceRange &Range : Ranges)
1196-
Range.clear();
1197-
};
1198-
11991148
// Helper to report diagnostics
1200-
auto ReportOverlap = [this, Loc, &HadOverlap](const RangeInfo *Info,
1201-
const RangeInfo *OInfo) {
1202-
HadOverlap = true;
1149+
auto ReportOverlap = [this, Loc](OverlappingRanges Overlap) {
1150+
const RangeInfo *Info = Overlap.A;
1151+
const RangeInfo *OInfo = Overlap.B;
12031152
auto CommonVis = Info->Visibility == llvm::dxbc::ShaderVisibility::All
12041153
? OInfo->Visibility
12051154
: Info->Visibility;
@@ -1212,42 +1161,12 @@ bool SemaHLSL::handleRootSignatureDecl(HLSLRootSignatureDecl *D,
12121161
<< OInfo->UpperBound << Info->Space << CommonVis;
12131162
};
12141163

1215-
// 3: Iterate through collected RangeInfos
1216-
for (const RangeInfo &Info : Infos) {
1217-
GroupT InfoGroup = {Info.Class, Info.Space};
1218-
// Reset our ResourceRanges when we enter a new group
1219-
if (CurGroup != InfoGroup) {
1220-
ClearRanges();
1221-
CurGroup = InfoGroup;
1222-
}
1223-
1224-
// 3A: Insert range info into corresponding Visibility ResourceRange
1225-
ResourceRange &VisRange = Ranges[llvm::to_underlying(Info.Visibility)];
1226-
if (std::optional<const RangeInfo *> Overlapping = VisRange.insert(Info))
1227-
ReportOverlap(&Info, Overlapping.value());
1228-
1229-
// 3B: Check for overlap in all overlapping Visibility ResourceRanges
1230-
//
1231-
// If the range that we are inserting has ShaderVisiblity::All it needs to
1232-
// check for an overlap in all other visibility types as well.
1233-
// Otherwise, the range that is inserted needs to check that it does not
1234-
// overlap with ShaderVisibility::All.
1235-
//
1236-
// OverlapRanges will be an ArrayRef to all non-all visibility
1237-
// ResourceRanges in the former case and it will be an ArrayRef to just the
1238-
// all visiblity ResourceRange in the latter case.
1239-
ArrayRef<ResourceRange> OverlapRanges =
1240-
Info.Visibility == llvm::dxbc::ShaderVisibility::All
1241-
? ArrayRef<ResourceRange>{Ranges}.drop_front()
1242-
: ArrayRef<ResourceRange>{Ranges}.take_front();
1243-
1244-
for (const ResourceRange &Range : OverlapRanges)
1245-
if (std::optional<const RangeInfo *> Overlapping =
1246-
Range.getOverlapping(Info))
1247-
ReportOverlap(&Info, Overlapping.value());
1248-
}
1249-
1250-
return HadOverlap;
1164+
llvm::SmallVector<OverlappingRanges> Overlaps =
1165+
llvm::hlsl::rootsig::findOverlappingRanges(Infos);
1166+
for (OverlappingRanges Overlap : Overlaps)
1167+
ReportOverlap(Overlap);
1168+
1169+
return Overlaps.size() != 0;
12511170
}
12521171

12531172
void SemaHLSL::handleRootSignatureAttr(Decl *D, const ParsedAttr &AL) {

llvm/include/llvm/Frontend/HLSL/RootSignatureValidations.h

Lines changed: 33 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -46,7 +46,7 @@ struct RangeInfo {
4646
uint32_t LowerBound;
4747
uint32_t UpperBound;
4848

49-
// Information retained for diagnostics
49+
// Information retained for determining overlap
5050
llvm::dxil::ResourceClass Class;
5151
uint32_t Space;
5252
llvm::dxbc::ShaderVisibility Visibility;
@@ -103,6 +103,38 @@ class ResourceRange {
103103
LLVM_ABI std::optional<const RangeInfo *> insert(const RangeInfo &Info);
104104
};
105105

106+
struct OverlappingRanges {
107+
const RangeInfo *A;
108+
const RangeInfo *B;
109+
110+
OverlappingRanges(const RangeInfo *A, const RangeInfo *B) : A(A), B(B) {}
111+
};
112+
113+
/// The following conducts analysis on resource ranges to detect and report
114+
/// any overlaps in resource ranges.
115+
///
116+
/// A resource range overlaps with another resource range if they have:
117+
/// - equivalent ResourceClass (SRV, UAV, CBuffer, Sampler)
118+
/// - equivalent resource space
119+
/// - overlapping visbility
120+
///
121+
/// The algorithm is implemented in the following steps:
122+
///
123+
/// 1. The user will collect RangeInfo from relevant RootElements:
124+
/// - RangeInfo will retain the interval, ResourceClass, Space and Visibility
125+
/// - It will also contain an index so that it can be associated to
126+
/// additional diagnostic information
127+
/// 2. Sort the RangeInfo's such that they are grouped together by
128+
/// ResourceClass and Space
129+
/// 3. Iterate through the collected RangeInfos by their groups
130+
/// - For each group we will have a ResourceRange for each visibility
131+
/// - As we iterate through we will:
132+
/// A: Insert the current RangeInfo into the corresponding Visibility
133+
/// ResourceRange
134+
/// B: Check for overlap with any overlapping Visibility ResourceRange
135+
llvm::SmallVector<OverlappingRanges>
136+
findOverlappingRanges(llvm::SmallVector<RangeInfo> &Infos);
137+
106138
} // namespace rootsig
107139
} // namespace hlsl
108140
} // namespace llvm

llvm/lib/Frontend/HLSL/RootSignatureValidations.cpp

Lines changed: 73 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -222,6 +222,79 @@ std::optional<const RangeInfo *> ResourceRange::insert(const RangeInfo &Info) {
222222
return Res;
223223
}
224224

225+
llvm::SmallVector<OverlappingRanges>
226+
findOverlappingRanges(llvm::SmallVector<RangeInfo> &Infos) {
227+
// 1. The user has provided the corresponding range information
228+
llvm::SmallVector<OverlappingRanges> Overlaps;
229+
using GroupT = std::pair<dxil::ResourceClass, /*Space*/ uint32_t>;
230+
231+
// 2. Sort the RangeInfo's by their GroupT to form groupings
232+
std::sort(Infos.begin(), Infos.end(), [](RangeInfo A, RangeInfo B) {
233+
return std::tie(A.Class, A.Space) < std::tie(B.Class, B.Space);
234+
});
235+
236+
// 3. First we will init our state to track:
237+
if (Infos.size() == 0)
238+
return Overlaps; // No ranges to overlap
239+
GroupT CurGroup = {Infos[0].Class, Infos[0].Space};
240+
241+
// Create a ResourceRange for each Visibility
242+
ResourceRange::MapT::Allocator Allocator;
243+
std::array<ResourceRange, 8> Ranges = {
244+
ResourceRange(Allocator), // All
245+
ResourceRange(Allocator), // Vertex
246+
ResourceRange(Allocator), // Hull
247+
ResourceRange(Allocator), // Domain
248+
ResourceRange(Allocator), // Geometry
249+
ResourceRange(Allocator), // Pixel
250+
ResourceRange(Allocator), // Amplification
251+
ResourceRange(Allocator), // Mesh
252+
};
253+
254+
// Reset the ResourceRanges for when we iterate through a new group
255+
auto ClearRanges = [&Ranges]() {
256+
for (ResourceRange &Range : Ranges)
257+
Range.clear();
258+
};
259+
260+
// 3: Iterate through collected RangeInfos
261+
for (const RangeInfo &Info : Infos) {
262+
GroupT InfoGroup = {Info.Class, Info.Space};
263+
// Reset our ResourceRanges when we enter a new group
264+
if (CurGroup != InfoGroup) {
265+
ClearRanges();
266+
CurGroup = InfoGroup;
267+
}
268+
269+
// 3A: Insert range info into corresponding Visibility ResourceRange
270+
ResourceRange &VisRange = Ranges[llvm::to_underlying(Info.Visibility)];
271+
if (std::optional<const RangeInfo *> Overlapping = VisRange.insert(Info))
272+
Overlaps.push_back(OverlappingRanges(&Info, Overlapping.value()));
273+
274+
// 3B: Check for overlap in all overlapping Visibility ResourceRanges
275+
//
276+
// If the range that we are inserting has ShaderVisiblity::All it needs to
277+
// check for an overlap in all other visibility types as well.
278+
// Otherwise, the range that is inserted needs to check that it does not
279+
// overlap with ShaderVisibility::All.
280+
//
281+
// OverlapRanges will be an ArrayRef to all non-all visibility
282+
// ResourceRanges in the former case and it will be an ArrayRef to just the
283+
// all visiblity ResourceRange in the latter case.
284+
ArrayRef<ResourceRange> OverlapRanges =
285+
Info.Visibility == llvm::dxbc::ShaderVisibility::All
286+
? ArrayRef<ResourceRange>{Ranges}.drop_front()
287+
: ArrayRef<ResourceRange>{Ranges}.take_front();
288+
289+
for (const ResourceRange &Range : OverlapRanges)
290+
if (std::optional<const RangeInfo *> Overlapping =
291+
Range.getOverlapping(Info))
292+
Overlaps.push_back(OverlappingRanges(&Info, Overlapping.value()));
293+
}
294+
295+
return Overlaps;
296+
}
297+
225298
} // namespace rootsig
226299
} // namespace hlsl
227300
} // namespace llvm

0 commit comments

Comments
 (0)