39
39
#include " llvm/ADT/StringExtras.h"
40
40
#include " llvm/ADT/StringRef.h"
41
41
#include " llvm/ADT/Twine.h"
42
+ #include " llvm/Frontend/HLSL/HLSLRootSignatureUtils.h"
42
43
#include " llvm/Support/Casting.h"
43
44
#include " llvm/Support/DXILABI.h"
44
45
#include " llvm/Support/ErrorHandling.h"
@@ -1068,10 +1069,121 @@ void SemaHLSL::ActOnFinishRootSignatureDecl(
1068
1069
SemaRef.getASTContext (), /* DeclContext=*/ SemaRef.CurContext , Loc,
1069
1070
DeclIdent, Elements);
1070
1071
1072
+ // Perform validation of constructs here
1073
+ if (handleRootSignatureDecl (SignatureDecl, Loc))
1074
+ return ;
1075
+
1071
1076
SignatureDecl->setImplicit ();
1072
1077
SemaRef.PushOnScopeChains (SignatureDecl, SemaRef.getCurScope ());
1073
1078
}
1074
1079
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
+
1075
1187
void SemaHLSL::handleRootSignatureAttr (Decl *D, const ParsedAttr &AL) {
1076
1188
if (AL.getNumArgs () != 1 ) {
1077
1189
Diag (AL.getLoc (), diag::err_attribute_wrong_number_arguments) << AL << 1 ;
@@ -1093,7 +1205,6 @@ void SemaHLSL::handleRootSignatureAttr(Decl *D, const ParsedAttr &AL) {
1093
1205
if (SemaRef.LookupQualifiedName (R, D->getDeclContext ()))
1094
1206
if (auto *SignatureDecl =
1095
1207
dyn_cast<HLSLRootSignatureDecl>(R.getFoundDecl ())) {
1096
- // Perform validation of constructs here
1097
1208
D->addAttr (::new (getASTContext ()) RootSignatureAttr (
1098
1209
getASTContext (), AL, Ident, SignatureDecl));
1099
1210
}
0 commit comments