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