Skip to content

Commit 6ee2563

Browse files
committed
rebased original version
1 parent c0c7146 commit 6ee2563

File tree

6 files changed

+174
-4
lines changed

6 files changed

+174
-4
lines changed

clang/include/clang/Basic/DiagnosticSemaKinds.td

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13054,6 +13054,11 @@ def err_invalid_hlsl_resource_type: Error<
1305413054
def err_hlsl_spirv_only: Error<"%0 is only available for the SPIR-V target">;
1305513055
def err_hlsl_vk_literal_must_contain_constant: Error<"the argument to vk::Literal must be a vk::integral_constant">;
1305613056

13057+
def err_hlsl_resource_range_overlap: Error<
13058+
"resource ranges %select{t|u|b|s}0[%1;%2] and %select{t|u|b|s}3[%4;%5] "
13059+
"overlap within space = %6 and visibility = "
13060+
"%select{All|Vertex|Hull|Domain|Geometry|Pixel|Amplification|Mesh}7">;
13061+
1305713062
// Layout randomization diagnostics.
1305813063
def err_non_designated_init_used : Error<
1305913064
"a randomized struct can only be initialized with a designated initializer">;

clang/include/clang/Sema/SemaHLSL.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -134,6 +134,8 @@ class SemaHLSL : public SemaBase {
134134
SourceLocation Loc, IdentifierInfo *DeclIdent,
135135
SmallVector<llvm::hlsl::rootsig::RootElement> &Elements);
136136

137+
// Returns true when D is invalid and a diagnostic was produced
138+
bool handleRootSignatureDecl(HLSLRootSignatureDecl *D, SourceLocation Loc);
137139
void handleRootSignatureAttr(Decl *D, const ParsedAttr &AL);
138140
void handleNumThreadsAttr(Decl *D, const ParsedAttr &AL);
139141
void handleWaveSizeAttr(Decl *D, const ParsedAttr &AL);

clang/lib/Sema/SemaHLSL.cpp

Lines changed: 112 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,7 @@
3939
#include "llvm/ADT/StringExtras.h"
4040
#include "llvm/ADT/StringRef.h"
4141
#include "llvm/ADT/Twine.h"
42+
#include "llvm/Frontend/HLSL/HLSLRootSignatureUtils.h"
4243
#include "llvm/Support/Casting.h"
4344
#include "llvm/Support/DXILABI.h"
4445
#include "llvm/Support/ErrorHandling.h"
@@ -1068,10 +1069,121 @@ void SemaHLSL::ActOnFinishRootSignatureDecl(
10681069
SemaRef.getASTContext(), /*DeclContext=*/SemaRef.CurContext, Loc,
10691070
DeclIdent, Elements);
10701071

1072+
// Perform validation of constructs here
1073+
if (handleRootSignatureDecl(SignatureDecl, Loc))
1074+
return;
1075+
10711076
SignatureDecl->setImplicit();
10721077
SemaRef.PushOnScopeChains(SignatureDecl, SemaRef.getCurScope());
10731078
}
10741079

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+
bool SemaHLSL::handleRootSignatureDecl(HLSLRootSignatureDecl *D,
1146+
SourceLocation Loc) {
1147+
auto Elements = D->getRootElements();
1148+
1149+
// First we will go through and collect our range info
1150+
llvm::SmallVector<llvm::hlsl::rootsig::RangeInfo> Infos;
1151+
for (const auto &Elem : Elements) {
1152+
if (const auto *Descriptor =
1153+
std::get_if<llvm::hlsl::rootsig::RootDescriptor>(&Elem)) {
1154+
llvm::hlsl::rootsig::RangeInfo Info;
1155+
Info.LowerBound = Descriptor->Reg.Number;
1156+
Info.UpperBound = Info.LowerBound; // use inclusive ranges []
1157+
1158+
Info.Class = llvm::dxil::ResourceClass(llvm::to_underlying(Descriptor->Type));
1159+
Info.Space = Descriptor->Space;
1160+
Info.Vis = Descriptor->Visibility;
1161+
Infos.push_back(Info);
1162+
}
1163+
}
1164+
1165+
// Iterate through info and attempt to insert corresponding range
1166+
ResourceRanges Ranges;
1167+
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+
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;
1180+
1181+
HadOverlap = true;
1182+
}
1183+
1184+
return HadOverlap;
1185+
}
1186+
10751187
void SemaHLSL::handleRootSignatureAttr(Decl *D, const ParsedAttr &AL) {
10761188
if (AL.getNumArgs() != 1) {
10771189
Diag(AL.getLoc(), diag::err_attribute_wrong_number_arguments) << AL << 1;
@@ -1093,7 +1205,6 @@ void SemaHLSL::handleRootSignatureAttr(Decl *D, const ParsedAttr &AL) {
10931205
if (SemaRef.LookupQualifiedName(R, D->getDeclContext()))
10941206
if (auto *SignatureDecl =
10951207
dyn_cast<HLSLRootSignatureDecl>(R.getFoundDecl())) {
1096-
// Perform validation of constructs here
10971208
D->addAttr(::new (getASTContext()) RootSignatureAttr(
10981209
getASTContext(), AL, Ident, SignatureDecl));
10991210
}
Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
// RUN: %clang_cc1 -triple dxil-pc-shadermodel6.3-library -x hlsl -o - %s -verify
2+
3+
#define Overlap0 "CBV(b42), CBV(b42)"
4+
5+
[RootSignature(Overlap0)] // expected-error {{resource ranges b[42;42] and b[42;42] overlap within space = 0 and visibility = All}}
6+
void bad_root_signature_0() {}
7+
8+
#define Overlap1 "SRV(t0, space = 3), SRV(t0, space = 3)"
9+
10+
[RootSignature(Overlap1)] // expected-error {{resource ranges t[0;0] and t[0;0] overlap within space = 3 and visibility = All}}
11+
void bad_root_signature_1() {}
12+
13+
#define Overlap2 "UAV(u0, visibility = SHADER_VISIBILITY_PIXEL), UAV(u0, visibility = SHADER_VISIBILITY_PIXEL)"
14+
15+
[RootSignature(Overlap2)] // expected-error {{resource ranges u[0;0] and u[0;0] overlap within space = 0 and visibility = Pixel}}
16+
void bad_root_signature_2() {}
17+
18+
#define Overlap3 "UAV(u0, visibility = SHADER_VISIBILITY_ALL), UAV(u0, visibility = SHADER_VISIBILITY_PIXEL)"
19+
20+
[RootSignature(Overlap3)] // expected-error {{resource ranges u[0;0] and u[0;0] overlap within space = 0 and visibility = Pixel}}
21+
void bad_root_signature_3() {}
22+
23+
#define Overlap4 "UAV(u0, visibility = SHADER_VISIBILITY_PIXEL), UAV(u0, visibility = SHADER_VISIBILITY_ALL)"
24+
25+
[RootSignature(Overlap4)] // expected-error {{resource ranges u[0;0] and u[0;0] overlap within space = 0 and visibility = Pixel}}
26+
void bad_root_signature_4() {}
Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
// RUN: %clang_cc1 -triple dxil-pc-shadermodel6.3-library -x hlsl -o - %s -verify
2+
// expected-no-diagnostics
3+
4+
#define NoOverlap0 "CBV(b0), CBV(b1)"
5+
6+
[RootSignature(NoOverlap0)]
7+
void valid_root_signature_0() {}
8+
9+
#define NoOverlap1 "CBV(b0, visibility = SHADER_VISIBILITY_DOMAIN), CBV(b0, visibility = SHADER_VISIBILITY_PIXEL)"
10+
11+
[RootSignature(NoOverlap1)]
12+
void valid_root_signature_1() {}
13+
14+
#define NoOverlap2 "CBV(b0, space = 1), CBV(b0, space = 2)"
15+
16+
[RootSignature(NoOverlap2)]
17+
void valid_root_signature_2() {}
18+
19+
#define NoOverlap3 "CBV(b0), SRV(t0)"
20+
21+
[RootSignature(NoOverlap3)]
22+
void valid_root_signature_3() {}

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

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -71,13 +71,17 @@ class MetadataBuilder {
7171
SmallVector<Metadata *> GeneratedMetadata;
7272
};
7373

74-
// RangeInfo holds the information to correctly construct a ResourceRange
75-
// and retains this information to be used for displaying a better diagnostic
7674
struct RangeInfo {
77-
const static uint32_t Unbounded = ~0u;
75+
const static uint32_t Unbounded = static_cast<uint32_t>(-1);
7876

77+
// Interval information
7978
uint32_t LowerBound;
8079
uint32_t UpperBound;
80+
81+
// Information retained for diagnostics
82+
llvm::dxil::ResourceClass Class;
83+
uint32_t Space;
84+
ShaderVisibility Vis;
8185
};
8286

8387
class ResourceRange {

0 commit comments

Comments
 (0)