Skip to content

Commit 75402c3

Browse files
committed
review: use sorted RangeInfo as opposed to storing in a densemap
- this will improve readability and efficiency as we will be able to free all ResourceRanges after they are used
1 parent 6ee2563 commit 75402c3

File tree

3 files changed

+106
-83
lines changed

3 files changed

+106
-83
lines changed

clang/lib/Sema/SemaHLSL.cpp

Lines changed: 101 additions & 83 deletions
Original file line numberDiff line numberDiff line change
@@ -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-
11451080
bool 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

llvm/include/llvm/Frontend/HLSL/HLSLRootSignatureUtils.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -102,6 +102,9 @@ class ResourceRange {
102102
// Return the mapped RangeInfo at X or nullptr if no mapping exists
103103
const RangeInfo *lookup(uint32_t X) const;
104104

105+
// Removes all entries of the ResourceRange
106+
void clear();
107+
105108
// Insert the required (sub-)intervals such that the interval of [a;b] =
106109
// [Info.LowerBound, Info.UpperBound] is covered and points to a valid
107110
// RangeInfo &.

llvm/lib/Frontend/HLSL/HLSLRootSignatureUtils.cpp

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -509,6 +509,8 @@ const RangeInfo *ResourceRange::lookup(uint32_t X) const {
509509
return Intervals.lookup(X, nullptr);
510510
}
511511

512+
void ResourceRange::clear() { return Intervals.clear(); }
513+
512514
std::optional<const RangeInfo *> ResourceRange::insert(const RangeInfo &Info) {
513515
uint32_t LowerBound = Info.LowerBound;
514516
uint32_t UpperBound = Info.UpperBound;

0 commit comments

Comments
 (0)