88
99#include " llvm/Analysis/DXILResource.h"
1010#include " llvm/ADT/APInt.h"
11+ #include " llvm/ADT/STLExtras.h"
1112#include " llvm/ADT/SmallString.h"
13+ #include " llvm/ADT/SmallVector.h"
1214#include " llvm/IR/Constants.h"
1315#include " llvm/IR/DerivedTypes.h"
1416#include " llvm/IR/DiagnosticInfo.h"
1921#include " llvm/IR/Module.h"
2022#include " llvm/InitializePasses.h"
2123#include " llvm/Support/FormatVariadic.h"
24+ #include < climits>
25+ #include < cstdint>
2226
2327#define DEBUG_TYPE " dxil-resource"
2428
@@ -879,8 +883,126 @@ SmallVector<dxil::ResourceInfo *> DXILResourceMap::findByUse(const Value *Key) {
879883
880884// ===----------------------------------------------------------------------===//
881885
886+ void DXILResourceBindingInfo::populate (Module &M, DXILResourceTypeMap &DRTM) {
887+ struct Binding {
888+ ResourceClass RC;
889+ uint32_t Space;
890+ uint32_t LowerBound;
891+ uint32_t UpperBound;
892+ Binding (ResourceClass RC, uint32_t Space, uint32_t LowerBound,
893+ uint32_t UpperBound)
894+ : RC(RC), Space(Space), LowerBound(LowerBound), UpperBound(UpperBound) {
895+ }
896+ };
897+ SmallVector<Binding> Bindings;
898+
899+ // collect all of the llvm.dx.resource.handlefrombinding calls;
900+ // make a note if there is llvm.dx.resource.handlefromimplicitbinding
901+ for (Function &F : M.functions ()) {
902+ if (!F.isDeclaration ())
903+ continue ;
904+
905+ switch (F.getIntrinsicID ()) {
906+ default :
907+ continue ;
908+ case Intrinsic::dx_resource_handlefrombinding: {
909+ auto *HandleTy = cast<TargetExtType>(F.getReturnType ());
910+ ResourceTypeInfo &RTI = DRTM[HandleTy];
911+
912+ for (User *U : F.users ())
913+ if (CallInst *CI = dyn_cast<CallInst>(U)) {
914+ uint32_t Space =
915+ cast<ConstantInt>(CI->getArgOperand (0 ))->getZExtValue ();
916+ uint32_t LowerBound =
917+ cast<ConstantInt>(CI->getArgOperand (1 ))->getZExtValue ();
918+ int32_t Size =
919+ cast<ConstantInt>(CI->getArgOperand (2 ))->getZExtValue ();
920+
921+ // negative size means unbounded resource array;
922+ // upper bound register overflow should be detected in Sema
923+ assert ((Size < 0 || (unsigned )LowerBound + Size - 1 <= UINT32_MAX) &&
924+ " upper bound register overflow" );
925+ uint32_t UpperBound = Size < 0 ? UINT32_MAX : LowerBound + Size - 1 ;
926+ Bindings.emplace_back (RTI.getResourceClass (), Space, LowerBound,
927+ UpperBound);
928+ }
929+ break ;
930+ }
931+ case Intrinsic::dx_resource_handlefromimplicitbinding: {
932+ ImplicitBinding = true ;
933+ break ;
934+ }
935+ }
936+ }
937+
938+ // sort all the collected bindings
939+ llvm::stable_sort (Bindings, [](auto &LHS, auto &RHS) {
940+ return std::tie (LHS.RC , LHS.Space , LHS.LowerBound ) <
941+ std::tie (RHS.RC , RHS.Space , RHS.LowerBound );
942+ });
943+
944+ // remove duplicates
945+ Binding *NewEnd = llvm::unique (Bindings, [](auto &LHS, auto &RHS) {
946+ return std::tie (LHS.RC , LHS.Space , LHS.LowerBound , LHS.UpperBound ) ==
947+ std::tie (RHS.RC , RHS.Space , RHS.LowerBound , RHS.UpperBound );
948+ });
949+ if (NewEnd != Bindings.end ())
950+ Bindings.erase (NewEnd);
951+
952+ // Go over the sorted bindings and build up lists of free register ranges
953+ // for each binding type and used spaces. Bindings are sorted by resource
954+ // class, space, and lower bound register slot.
955+ BindingSpaces *BS = &SRVSpaces;
956+ for (unsigned I = 0 , E = Bindings.size (); I != E; ++I) {
957+ Binding &B = Bindings[I];
958+
959+ if (BS->RC != B.RC )
960+ // move to the next resource class spaces
961+ BS = &getBindingSpaces (B.RC );
962+
963+ RegisterSpace *S = BS->Spaces .empty () ? &BS->Spaces .emplace_back (B.Space )
964+ : &BS->Spaces .back ();
965+ assert (S->Space <= B.Space && " bindings not sorted correctly?" );
966+ if (B.Space != S->Space )
967+ // add new space
968+ S = &BS->Spaces .emplace_back (B.Space );
969+
970+ // the space is full - set flag to report overlapping binding later
971+ if (S->FreeRanges .empty ()) {
972+ OverlappingBinding = true ;
973+ continue ;
974+ }
975+
976+ // adjust the last free range lower bound, split it in two, or remove it
977+ BindingRange &LastFreeRange = S->FreeRanges .back ();
978+ assert (LastFreeRange.UpperBound == UINT32_MAX);
979+ if (LastFreeRange.LowerBound == B.LowerBound ) {
980+ if (B.UpperBound < UINT32_MAX)
981+ LastFreeRange.LowerBound = B.UpperBound + 1 ;
982+ else
983+ S->FreeRanges .pop_back ();
984+ } else if (LastFreeRange.LowerBound < B.LowerBound ) {
985+ LastFreeRange.UpperBound = B.LowerBound - 1 ;
986+ if (B.UpperBound < UINT32_MAX)
987+ S->FreeRanges .emplace_back (B.UpperBound + 1 , UINT32_MAX);
988+ } else {
989+ // FIXME: This only detects overlapping bindings that are not an exact
990+ // match (llvm/llvm-project#110723)
991+ OverlappingBinding = true ;
992+ if (B.UpperBound < UINT32_MAX)
993+ LastFreeRange.LowerBound =
994+ std::max (LastFreeRange.LowerBound , B.UpperBound + 1 );
995+ else
996+ S->FreeRanges .pop_back ();
997+ }
998+ }
999+ }
1000+
1001+ // ===----------------------------------------------------------------------===//
1002+
8821003AnalysisKey DXILResourceTypeAnalysis::Key;
8831004AnalysisKey DXILResourceAnalysis::Key;
1005+ AnalysisKey DXILResourceBindingAnalysis::Key;
8841006
8851007DXILResourceMap DXILResourceAnalysis::run (Module &M,
8861008 ModuleAnalysisManager &AM) {
@@ -890,6 +1012,14 @@ DXILResourceMap DXILResourceAnalysis::run(Module &M,
8901012 return Data;
8911013}
8921014
1015+ DXILResourceBindingInfo
1016+ DXILResourceBindingAnalysis::run (Module &M, ModuleAnalysisManager &AM) {
1017+ DXILResourceBindingInfo Data;
1018+ DXILResourceTypeMap &DRTM = AM.getResult <DXILResourceTypeAnalysis>(M);
1019+ Data.populate (M, DRTM);
1020+ return Data;
1021+ }
1022+
8931023PreservedAnalyses DXILResourcePrinterPass::run (Module &M,
8941024 ModuleAnalysisManager &AM) {
8951025 DXILResourceMap &DRM = AM.getResult <DXILResourceAnalysis>(M);
@@ -952,3 +1082,33 @@ char DXILResourceWrapperPass::ID = 0;
9521082ModulePass *llvm::createDXILResourceWrapperPassPass () {
9531083 return new DXILResourceWrapperPass ();
9541084}
1085+
1086+ DXILResourceBindingWrapperPass::DXILResourceBindingWrapperPass ()
1087+ : ModulePass(ID) {}
1088+
1089+ DXILResourceBindingWrapperPass::~DXILResourceBindingWrapperPass () = default ;
1090+
1091+ void DXILResourceBindingWrapperPass::getAnalysisUsage (AnalysisUsage &AU) const {
1092+ AU.addRequiredTransitive <DXILResourceTypeWrapperPass>();
1093+ AU.setPreservesAll ();
1094+ }
1095+
1096+ bool DXILResourceBindingWrapperPass::runOnModule (Module &M) {
1097+ BindingInfo.reset (new DXILResourceBindingInfo ());
1098+
1099+ DXILResourceTypeMap &DRTM =
1100+ getAnalysis<DXILResourceTypeWrapperPass>().getResourceTypeMap ();
1101+ BindingInfo->populate (M, DRTM);
1102+
1103+ return false ;
1104+ }
1105+
1106+ void DXILResourceBindingWrapperPass::releaseMemory () { BindingInfo.reset (); }
1107+
1108+ INITIALIZE_PASS (DXILResourceBindingWrapperPass, " dxil-resource-binding" ,
1109+ " DXIL Resource Binding Analysis" , false , true )
1110+ char DXILResourceBindingWrapperPass::ID = 0;
1111+
1112+ ModulePass *llvm::createDXILResourceBindingWrapperPassPass () {
1113+ return new DXILResourceWrapperPass ();
1114+ }
0 commit comments