Skip to content

Commit 630dae0

Browse files
committed
[HLSL][RootSignature] Plug into the thing
1 parent a3240de commit 630dae0

File tree

6 files changed

+159
-2
lines changed

6 files changed

+159
-2
lines changed

clang/include/clang/Basic/DiagnosticSemaKinds.td

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12967,6 +12967,11 @@ def err_hlsl_expect_arg_const_int_one_or_neg_one: Error<
1296712967
def err_invalid_hlsl_resource_type: Error<
1296812968
"invalid __hlsl_resource_t type attributes">;
1296912969

12970+
def err_hlsl_resource_range_overlap: Error<
12971+
"resource ranges %select{t|u|b|s}0[%1;%2] and %select{t|u|b|s}3[%4;%5] "
12972+
"overlap within space = %6 and visibility = "
12973+
"%select{All|Vertex|Hull|Domain|Geometry|Pixel|Amplification|Mesh}7">;
12974+
1297012975
// Layout randomization diagnostics.
1297112976
def err_non_designated_init_used : Error<
1297212977
"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
@@ -119,6 +119,8 @@ class SemaHLSL : public SemaBase {
119119
bool IsCompAssign);
120120
void emitLogicalOperatorFixIt(Expr *LHS, Expr *RHS, BinaryOperatorKind Opc);
121121

122+
// Returns true when D is invalid and a diagnostic was produced
123+
bool handleRootSignatureDecl(HLSLRootSignatureDecl *D, SourceLocation Loc);
122124
void handleRootSignatureAttr(Decl *D, const ParsedAttr &AL);
123125
void handleNumThreadsAttr(Decl *D, const ParsedAttr &AL);
124126
void handleWaveSizeAttr(Decl *D, const ParsedAttr &AL);

clang/lib/Sema/SemaHLSL.cpp

Lines changed: 98 additions & 0 deletions
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/HLSLRootSignature.h"
4243
#include "llvm/Support/Casting.h"
4344
#include "llvm/Support/DXILABI.h"
4445
#include "llvm/Support/ErrorHandling.h"
@@ -951,6 +952,101 @@ void SemaHLSL::emitLogicalOperatorFixIt(Expr *LHS, Expr *RHS,
951952
<< NewFnName << FixItHint::CreateReplacement(FullRange, OS.str());
952953
}
953954

955+
namespace {
956+
957+
// A resource range overlaps with another resource range if they have:
958+
// - equivalent ResourceClass (SRV, UAV, CBuffer, Sampler)
959+
// - equivalent resource space
960+
// - overlapping visbility
961+
class ResourceRanges {
962+
public:
963+
// KeyT: 32-lsb denotes resource space, and 32-msb denotes resource type enum
964+
using KeyT = uint64_t;
965+
966+
constexpr static KeyT getKey(const llvm::hlsl::rootsig::RangeInfo &Info) {
967+
uint64_t SpacePacked = (uint64_t)Info.Space;
968+
uint64_t ClassPacked = (uint64_t)llvm::to_underlying(Info.Class);
969+
return (ClassPacked << 32) | SpacePacked;
970+
}
971+
972+
static const unsigned NumVisEnums = 8;
973+
// (unsigned)llvm::hlsl::rootsig::ShaderVisibility::NumEnums;
974+
975+
private:
976+
llvm::hlsl::rootsig::ResourceRange::IMap::Allocator Allocator;
977+
978+
using MapT = llvm::SmallDenseMap<KeyT, llvm::hlsl::rootsig::ResourceRange>;
979+
980+
MapT RangeMaps[NumVisEnums];
981+
982+
public:
983+
// Returns std::nullopt if there was no collision. Otherwise, it will
984+
// return the RangeInfo of the collision
985+
std::optional<const llvm::hlsl::rootsig::RangeInfo *> addRange(const llvm::hlsl::rootsig::RangeInfo &Info) {
986+
MapT &VisRangeMap = RangeMaps[llvm::to_underlying(Info.Vis)];
987+
auto [It, _] = VisRangeMap.insert({getKey(Info), llvm::hlsl::rootsig::ResourceRange(Allocator)});
988+
auto Res = It->second.insert(Info);
989+
if (Res.has_value())
990+
return Res;
991+
992+
MutableArrayRef<MapT> Maps =
993+
Info.Vis == llvm::hlsl::rootsig::ShaderVisibility::All
994+
? MutableArrayRef<MapT>{RangeMaps}.drop_front()
995+
: MutableArrayRef<MapT>{RangeMaps}.take_front();
996+
997+
for (MapT &CurMap : Maps) {
998+
auto CurIt = CurMap.find(getKey(Info));
999+
if (CurIt != CurMap.end())
1000+
if (auto Overlapping = CurIt->second.getOverlapping(Info))
1001+
return Overlapping;
1002+
}
1003+
1004+
return std::nullopt;
1005+
}
1006+
};
1007+
1008+
} // namespace
1009+
1010+
bool SemaHLSL::handleRootSignatureDecl(HLSLRootSignatureDecl *D,
1011+
SourceLocation Loc) {
1012+
auto Elements = D->getRootElements();
1013+
1014+
// First we will go through and collect our range info
1015+
llvm::SmallVector<llvm::hlsl::rootsig::RangeInfo> Infos;
1016+
for (const auto &Elem : Elements) {
1017+
if (const auto *Param =
1018+
std::get_if<llvm::hlsl::rootsig::RootParam>(&Elem)) {
1019+
llvm::hlsl::rootsig::RangeInfo Info;
1020+
Info.LowerBound = Param->Reg.Number;
1021+
Info.UpperBound = Info.LowerBound; // use inclusive ranges []
1022+
1023+
Info.Class = Param->Type;
1024+
Info.Space = Param->Space;
1025+
Info.Vis = Param->Visibility;
1026+
Infos.push_back(Info);
1027+
}
1028+
}
1029+
1030+
// Iterate through info and attempt to insert corresponding range
1031+
ResourceRanges Ranges;
1032+
bool HadOverlap = false;
1033+
for (const llvm::hlsl::rootsig::RangeInfo &Info : Infos)
1034+
if (auto MaybeOverlappingInfo = Ranges.addRange(Info)) {
1035+
const llvm::hlsl::rootsig::RangeInfo *OInfo = MaybeOverlappingInfo.value();
1036+
auto CommonVis = Info.Vis == llvm::hlsl::rootsig::ShaderVisibility::All
1037+
? OInfo->Vis : Info.Vis;
1038+
1039+
Diag(Loc, diag::err_hlsl_resource_range_overlap)
1040+
<< llvm::to_underlying(Info.Class) << Info.LowerBound << Info.UpperBound
1041+
<< llvm::to_underlying(OInfo->Class) << OInfo->LowerBound << OInfo->UpperBound
1042+
<< Info.Space << CommonVis;
1043+
1044+
HadOverlap = true;
1045+
}
1046+
1047+
return HadOverlap;
1048+
}
1049+
9541050
void SemaHLSL::handleRootSignatureAttr(Decl *D, const ParsedAttr &AL) {
9551051
if (AL.getNumArgs() != 1) {
9561052
Diag(AL.getLoc(), diag::err_attribute_wrong_number_arguments) << AL << 1;
@@ -973,6 +1069,8 @@ void SemaHLSL::handleRootSignatureAttr(Decl *D, const ParsedAttr &AL) {
9731069
if (auto *SignatureDecl =
9741070
dyn_cast<HLSLRootSignatureDecl>(R.getFoundDecl())) {
9751071
// Perform validation of constructs here
1072+
if (handleRootSignatureDecl(SignatureDecl, AL.getLoc()))
1073+
return;
9761074
D->addAttr(::new (getASTContext()) RootSignatureAttr(
9771075
getASTContext(), AL, Ident, SignatureDecl));
9781076
}
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/HLSLRootSignature.h

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -199,13 +199,17 @@ class MetadataBuilder {
199199
SmallVector<Metadata *> GeneratedMetadata;
200200
};
201201

202-
// RangeInfo holds the information to correctly construct a ResourceRange
203-
// and retains this information to be used for displaying a better diagnostic
204202
struct RangeInfo {
205203
const static uint32_t Unbounded = static_cast<uint32_t>(-1);
206204

205+
// Interval information
207206
uint32_t LowerBound;
208207
uint32_t UpperBound;
208+
209+
// Information retained for diagnostics
210+
llvm::dxil::ResourceClass Class;
211+
uint32_t Space;
212+
ShaderVisibility Vis;
209213
};
210214

211215
class ResourceRange {

0 commit comments

Comments
 (0)