1919#include " llvm/IR/Module.h"
2020#include " llvm/InitializePasses.h"
2121#include " llvm/Support/FormatVariadic.h"
22+ #include < algorithm>
2223
2324#define DEBUG_TYPE " dxil-resource"
2425
@@ -818,8 +819,88 @@ DXILBindingMap::findByUse(const Value *Key) const {
818819
819820// ===----------------------------------------------------------------------===//
820821
822+ static bool isUpdateCounterIntrinsic (Function &F) {
823+ return F.getIntrinsicID () == Intrinsic::dx_resource_updatecounter;
824+ }
825+
826+ void DXILResourceCounterDirectionMap::populate (Module &M, ModuleAnalysisManager &AM) {
827+ DXILBindingMap &DBM = AM.getResult <DXILResourceBindingAnalysis>(M);
828+ CounterDirections.clear ();
829+
830+ for (Function &F : M.functions ()) {
831+ if (!isUpdateCounterIntrinsic (F))
832+ continue ;
833+
834+ for (const User *U : F.users ()) {
835+ const CallInst *CI = dyn_cast<CallInst>(U);
836+ assert (CI && " Users of dx_resource_updateCounter must be call instrs" );
837+
838+ // Determine if the use is an increment or decrement
839+ Value *CountArg = CI->getArgOperand (1 );
840+ ConstantInt *CountValue = dyn_cast<ConstantInt>(CountArg);
841+ int64_t CountLiteral = CountValue->getSExtValue ();
842+
843+ ResourceCounterDirection Direction = ResourceCounterDirection::Unknown;
844+ if (CountLiteral > 0 ) {
845+ Direction = ResourceCounterDirection::Increment;
846+ }
847+ if (CountLiteral < 0 ) {
848+ Direction = ResourceCounterDirection::Decrement;
849+ }
850+
851+
852+ // Collect all potential creation points for the handle arg
853+ Value *HandleArg = CI->getArgOperand (0 );
854+ SmallVector<dxil::ResourceBindingInfo> RBInfos = DBM.findByUse (HandleArg);
855+ for (const dxil::ResourceBindingInfo RBInfo : RBInfos) {
856+ CounterDirections.emplace_back (RBInfo, Direction);
857+ }
858+ }
859+ }
860+
861+ // An entry that is not in the map is considered unknown so its wasted
862+ // overhead and increased complexity to keep it so it should be removed.
863+ const auto RemoveEnd = std::remove_if (CounterDirections.begin (), CounterDirections.end (), [](const auto & Item) {
864+ return Item.second == ResourceCounterDirection::Unknown;
865+ });
866+
867+ // Order for fast lookup
868+ std::sort (CounterDirections.begin (), RemoveEnd);
869+
870+ // Remove the duplicate entries. Since direction is considered for equality
871+ // a unique resource with more than one direction will not be deduped.
872+ const auto UniqueEnd = std::unique (CounterDirections.begin (), RemoveEnd);
873+
874+ // Actually erase the items invalidated by remove_if + unique
875+ CounterDirections.erase (UniqueEnd, CounterDirections.end ());
876+
877+ // If any duplicate entries still exist at this point then it must be a
878+ // resource that was both incremented and decremented which is not allowed.
879+ const auto DuplicateEntry = std::adjacent_find (CounterDirections.begin (), CounterDirections.end (), [](const auto & LHS, const auto & RHS){
880+ return LHS.first == RHS.first ;
881+ });
882+ if (DuplicateEntry == CounterDirections.end ())
883+ return ;
884+
885+ // TODO: Emit an error message
886+ assert (CounterDirections.size () == 1 && " dups found" );
887+ }
888+
889+ bool DXILResourceCounterDirectionMap::invalidate (Module &M, const PreservedAnalyses &PA,
890+ ModuleAnalysisManager::Invalidator &Inv) {
891+ // Passes that introduce resource types must explicitly invalidate this pass.
892+ // auto PAC = PA.getChecker<DXILResourceTypeAnalysis>();
893+ // return !PAC.preservedWhenStateless();
894+ return false ;
895+ }
896+
897+ void DXILResourceCounterDirectionWrapperPass::anchor () {}
898+
899+ // ===----------------------------------------------------------------------===//
900+
821901AnalysisKey DXILResourceTypeAnalysis::Key;
822902AnalysisKey DXILResourceBindingAnalysis::Key;
903+ AnalysisKey DXILResourceCounterDirectionAnalysis::Key;
823904
824905DXILBindingMap DXILResourceBindingAnalysis::run (Module &M,
825906 ModuleAnalysisManager &AM) {
@@ -838,6 +919,13 @@ DXILResourceBindingPrinterPass::run(Module &M, ModuleAnalysisManager &AM) {
838919 return PreservedAnalyses::all ();
839920}
840921
922+ INITIALIZE_PASS (DXILResourceCounterDirectionWrapperPass, " dxil-resource-counter" ,
923+ " DXIL Resource Counter Analysis" , false , true )
924+
925+ DXILResourceCounterDirectionWrapperPass::DXILResourceCounterDirectionWrapperPass() : ImmutablePass(ID) {
926+ initializeDXILResourceTypeWrapperPassPass (*PassRegistry::getPassRegistry ());
927+ }
928+
841929void DXILResourceTypeWrapperPass::anchor () {}
842930
843931DXILResourceTypeWrapperPass::DXILResourceTypeWrapperPass () : ImmutablePass(ID) {
@@ -847,11 +935,16 @@ DXILResourceTypeWrapperPass::DXILResourceTypeWrapperPass() : ImmutablePass(ID) {
847935INITIALIZE_PASS (DXILResourceTypeWrapperPass, " dxil-resource-type" ,
848936 " DXIL Resource Type Analysis" , false , true )
849937char DXILResourceTypeWrapperPass::ID = 0;
938+ char DXILResourceCounterDirectionWrapperPass::ID = 0 ;
850939
851940ModulePass *llvm::createDXILResourceTypeWrapperPassPass () {
852941 return new DXILResourceTypeWrapperPass ();
853942}
854943
944+ ModulePass *llvm::createDXILResourceCounterDirectionWrapperPassPass () {
945+ return new DXILResourceCounterDirectionWrapperPass ();
946+ }
947+
855948DXILResourceBindingWrapperPass::DXILResourceBindingWrapperPass ()
856949 : ModulePass(ID) {
857950 initializeDXILResourceBindingWrapperPassPass (
0 commit comments