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+
10751187void 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 }
0 commit comments