Skip to content

Commit bcc056e

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

File tree

7 files changed

+169
-2
lines changed

7 files changed

+169
-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: 105 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,108 @@ 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+
static const unsigned NumVisEnums =
967+
(unsigned)llvm::hlsl::rootsig::ShaderVisibility::NumEnums;
968+
969+
private:
970+
llvm::hlsl::rootsig::ResourceRange::IMap::Allocator Allocator;
971+
972+
// Denotes a mapping of a unique combination of ResourceClass and register
973+
// space to a ResourceRange
974+
using MapT = llvm::SmallDenseMap<KeyT, llvm::hlsl::rootsig::ResourceRange>;
975+
976+
// Denotes a mapping for each unique visibility
977+
MapT RangeMaps[NumVisEnums];
978+
979+
constexpr static KeyT getKey(const llvm::hlsl::rootsig::RangeInfo &Info) {
980+
uint64_t SpacePacked = (uint64_t)Info.Space;
981+
uint64_t ClassPacked = (uint64_t)llvm::to_underlying(Info.Class);
982+
return (ClassPacked << 32) | SpacePacked;
983+
}
984+
985+
public:
986+
// Returns std::nullopt if there was no collision. Otherwise, it will
987+
// return the RangeInfo of the collision
988+
std::optional<const llvm::hlsl::rootsig::RangeInfo *>
989+
addRange(const llvm::hlsl::rootsig::RangeInfo &Info) {
990+
MapT &VisRangeMap = RangeMaps[llvm::to_underlying(Info.Vis)];
991+
auto [It, _] = VisRangeMap.insert(
992+
{getKey(Info), llvm::hlsl::rootsig::ResourceRange(Allocator)});
993+
auto Res = It->second.insert(Info);
994+
if (Res.has_value())
995+
return Res;
996+
997+
MutableArrayRef<MapT> Maps =
998+
Info.Vis == llvm::hlsl::rootsig::ShaderVisibility::All
999+
? MutableArrayRef<MapT>{RangeMaps}.drop_front()
1000+
: MutableArrayRef<MapT>{RangeMaps}.take_front();
1001+
1002+
for (MapT &CurMap : Maps) {
1003+
auto CurIt = CurMap.find(getKey(Info));
1004+
if (CurIt != CurMap.end())
1005+
if (auto Overlapping = CurIt->second.getOverlapping(Info))
1006+
return Overlapping;
1007+
}
1008+
1009+
return std::nullopt;
1010+
}
1011+
};
1012+
1013+
} // namespace
1014+
1015+
bool SemaHLSL::handleRootSignatureDecl(HLSLRootSignatureDecl *D,
1016+
SourceLocation Loc) {
1017+
auto Elements = D->getRootElements();
1018+
1019+
// First we will go through and collect our range info
1020+
llvm::SmallVector<llvm::hlsl::rootsig::RangeInfo> Infos;
1021+
for (const auto &Elem : Elements) {
1022+
if (const auto *Param =
1023+
std::get_if<llvm::hlsl::rootsig::RootParam>(&Elem)) {
1024+
llvm::hlsl::rootsig::RangeInfo Info;
1025+
Info.LowerBound = Param->Reg.Number;
1026+
Info.UpperBound = Info.LowerBound; // use inclusive ranges []
1027+
1028+
Info.Class = Param->Type;
1029+
Info.Space = Param->Space;
1030+
Info.Vis = Param->Visibility;
1031+
Infos.push_back(Info);
1032+
}
1033+
}
1034+
1035+
// Iterate through info and attempt to insert corresponding range
1036+
ResourceRanges Ranges;
1037+
bool HadOverlap = false;
1038+
for (const llvm::hlsl::rootsig::RangeInfo &Info : Infos)
1039+
if (auto MaybeOverlappingInfo = Ranges.addRange(Info)) {
1040+
const llvm::hlsl::rootsig::RangeInfo *OInfo =
1041+
MaybeOverlappingInfo.value();
1042+
auto CommonVis = Info.Vis == llvm::hlsl::rootsig::ShaderVisibility::All
1043+
? OInfo->Vis
1044+
: Info.Vis;
1045+
1046+
Diag(Loc, diag::err_hlsl_resource_range_overlap)
1047+
<< llvm::to_underlying(Info.Class) << Info.LowerBound
1048+
<< Info.UpperBound << llvm::to_underlying(OInfo->Class)
1049+
<< OInfo->LowerBound << OInfo->UpperBound << Info.Space << CommonVis;
1050+
1051+
HadOverlap = true;
1052+
}
1053+
1054+
return HadOverlap;
1055+
}
1056+
9541057
void SemaHLSL::handleRootSignatureAttr(Decl *D, const ParsedAttr &AL) {
9551058
if (AL.getNumArgs() != 1) {
9561059
Diag(AL.getLoc(), diag::err_attribute_wrong_number_arguments) << AL << 1;
@@ -973,6 +1076,8 @@ void SemaHLSL::handleRootSignatureAttr(Decl *D, const ParsedAttr &AL) {
9731076
if (auto *SignatureDecl =
9741077
dyn_cast<HLSLRootSignatureDecl>(R.getFoundDecl())) {
9751078
// Perform validation of constructs here
1079+
if (handleRootSignatureDecl(SignatureDecl, AL.getLoc()))
1080+
return;
9761081
D->addAttr(::new (getASTContext()) RootSignatureAttr(
9771082
getASTContext(), AL, Ident, SignatureDecl));
9781083
}
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: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -75,6 +75,7 @@ enum class ShaderVisibility {
7575
Pixel = 5,
7676
Amplification = 6,
7777
Mesh = 7,
78+
NumEnums = 8,
7879
};
7980

8081
// Definitions of the in-memory data layout structures
@@ -199,13 +200,17 @@ class MetadataBuilder {
199200
SmallVector<Metadata *> GeneratedMetadata;
200201
};
201202

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

206+
// Interval information
207207
uint32_t LowerBound;
208208
uint32_t UpperBound;
209+
210+
// Information retained for diagnostics
211+
llvm::dxil::ResourceClass Class;
212+
uint32_t Space;
213+
ShaderVisibility Vis;
209214
};
210215

211216
class ResourceRange {

llvm/lib/Frontend/HLSL/HLSLRootSignature.cpp

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -66,6 +66,8 @@ static raw_ostream &operator<<(raw_ostream &OS,
6666
case ShaderVisibility::Mesh:
6767
OS << "Mesh";
6868
break;
69+
case ShaderVisibility::NumEnums:
70+
break;
6971
}
7072

7173
return OS;

0 commit comments

Comments
 (0)