[llvm] [HLSL] Analyze update counter usage (PR #130356)

Ashley Coleman via llvm-commits llvm-commits at lists.llvm.org
Tue Mar 25 14:09:26 PDT 2025


https://github.com/V-FEXrt updated https://github.com/llvm/llvm-project/pull/130356

>From ee05b44bb7ff79ea77927d94724aba2657d0134a Mon Sep 17 00:00:00 2001
From: Ashley Coleman <ascoleman at microsoft.com>
Date: Wed, 5 Mar 2025 17:23:12 -0700
Subject: [PATCH 01/19] [HLSL] Analyze update counter usage

---
 llvm/include/llvm/Analysis/DXILResource.h     | 67 +++++++++++++
 llvm/include/llvm/InitializePasses.h          |  1 +
 llvm/lib/Analysis/DXILResource.cpp            | 93 +++++++++++++++++++
 .../DirectX/UniqueResourceFromUseTests.cpp    | 44 +++++++++
 4 files changed, 205 insertions(+)

diff --git a/llvm/include/llvm/Analysis/DXILResource.h b/llvm/include/llvm/Analysis/DXILResource.h
index d399457e16916..3f11b07cd75eb 100644
--- a/llvm/include/llvm/Analysis/DXILResource.h
+++ b/llvm/include/llvm/Analysis/DXILResource.h
@@ -18,6 +18,10 @@
 #include "llvm/Support/Alignment.h"
 #include "llvm/Support/DXILABI.h"
 
+#include <algorithm>
+#include <cstdint>
+#include <unordered_map>
+
 namespace llvm {
 class CallInst;
 class DataLayout;
@@ -407,6 +411,69 @@ class DXILResourceTypeMap {
   }
 };
 
+enum ResourceCounterDirection {
+  Increment,
+  Decrement,
+  Unknown,
+};
+
+class DXILResourceCounterDirectionMap {
+  std::vector<std::pair<dxil::ResourceBindingInfo, ResourceCounterDirection>> CounterDirections;
+
+public:
+  bool invalidate(Module &M, const PreservedAnalyses &PA,
+                  ModuleAnalysisManager::Invalidator &Inv);
+
+   void populate(Module &M, ModuleAnalysisManager &AM);
+
+   ResourceCounterDirection operator[](const dxil::ResourceBindingInfo &Info) const {
+    auto Lower = std::lower_bound(CounterDirections.begin(), CounterDirections.end(), std::pair{Info, ResourceCounterDirection::Unknown},  [](auto lhs, auto rhs){
+                                  return lhs.first  < rhs.first;
+    });
+
+    if (Lower == CounterDirections.end()) {
+      return ResourceCounterDirection::Unknown;
+    }
+
+    if (Lower->first != Info) {
+      return ResourceCounterDirection::Unknown;
+    }
+
+    return Lower->second;
+   }
+};
+
+class DXILResourceCounterDirectionAnalysis
+    : public AnalysisInfoMixin<DXILResourceCounterDirectionAnalysis> {
+  friend AnalysisInfoMixin<DXILResourceCounterDirectionAnalysis>;
+
+  static AnalysisKey Key;
+
+public:
+  using Result = DXILResourceCounterDirectionMap;
+
+  DXILResourceCounterDirectionMap run(Module &M, ModuleAnalysisManager &AM) {
+    DXILResourceCounterDirectionMap DRCDM{};
+    DRCDM.populate(M, AM);
+    return DRCDM;
+  }
+};
+
+class DXILResourceCounterDirectionWrapperPass : public ImmutablePass {
+  DXILResourceCounterDirectionMap DRCDM;
+
+  virtual void anchor();
+
+public:
+  static char ID;
+  DXILResourceCounterDirectionWrapperPass();
+
+  DXILResourceCounterDirectionMap &getResourceCounterDirectionMap() { return DRCDM; }
+  const DXILResourceCounterDirectionMap &getResourceCounterDirectionMap() const { return DRCDM; }
+};
+
+ModulePass *createDXILResourceCounterDirectionWrapperPassPass();
+
 class DXILResourceTypeAnalysis
     : public AnalysisInfoMixin<DXILResourceTypeAnalysis> {
   friend AnalysisInfoMixin<DXILResourceTypeAnalysis>;
diff --git a/llvm/include/llvm/InitializePasses.h b/llvm/include/llvm/InitializePasses.h
index 0dfb46a210c7e..3848f0dd6fe03 100644
--- a/llvm/include/llvm/InitializePasses.h
+++ b/llvm/include/llvm/InitializePasses.h
@@ -85,6 +85,7 @@ void initializeDCELegacyPassPass(PassRegistry &);
 void initializeDXILMetadataAnalysisWrapperPassPass(PassRegistry &);
 void initializeDXILMetadataAnalysisWrapperPrinterPass(PassRegistry &);
 void initializeDXILResourceBindingWrapperPassPass(PassRegistry &);
+void initializeDXILResourceCounterDirectionWrapperPassPass(PassRegistry &);
 void initializeDXILResourceTypeWrapperPassPass(PassRegistry &);
 void initializeDeadMachineInstructionElimPass(PassRegistry &);
 void initializeDebugifyMachineModulePass(PassRegistry &);
diff --git a/llvm/lib/Analysis/DXILResource.cpp b/llvm/lib/Analysis/DXILResource.cpp
index c0319c9a354a6..59e432075db17 100644
--- a/llvm/lib/Analysis/DXILResource.cpp
+++ b/llvm/lib/Analysis/DXILResource.cpp
@@ -19,6 +19,7 @@
 #include "llvm/IR/Module.h"
 #include "llvm/InitializePasses.h"
 #include "llvm/Support/FormatVariadic.h"
+#include <algorithm>
 
 #define DEBUG_TYPE "dxil-resource"
 
@@ -818,8 +819,88 @@ DXILBindingMap::findByUse(const Value *Key) const {
 
 //===----------------------------------------------------------------------===//
 
+static bool isUpdateCounterIntrinsic(Function &F) {
+  return F.getIntrinsicID() == Intrinsic::dx_resource_updatecounter;
+}
+
+void DXILResourceCounterDirectionMap::populate(Module &M, ModuleAnalysisManager &AM) {
+    DXILBindingMap &DBM = AM.getResult<DXILResourceBindingAnalysis>(M);
+    CounterDirections.clear();
+
+    for (Function &F : M.functions()) {
+      if (!isUpdateCounterIntrinsic(F))
+        continue;
+
+      for (const User *U : F.users()) {
+        const CallInst *CI = dyn_cast<CallInst>(U);
+        assert(CI && "Users of dx_resource_updateCounter must be call instrs");
+
+        // Determine if the use is an increment or decrement
+        Value *CountArg = CI->getArgOperand(1);
+        ConstantInt *CountValue = dyn_cast<ConstantInt>(CountArg);
+        int64_t CountLiteral = CountValue->getSExtValue();
+
+        ResourceCounterDirection Direction = ResourceCounterDirection::Unknown;
+        if (CountLiteral > 0) {
+          Direction = ResourceCounterDirection::Increment;
+        }
+        if (CountLiteral < 0) {
+          Direction = ResourceCounterDirection::Decrement;
+        }
+
+
+        // Collect all potential creation points for the handle arg
+        Value *HandleArg = CI->getArgOperand(0);
+        SmallVector<dxil::ResourceBindingInfo> RBInfos = DBM.findByUse(HandleArg);
+        for(const dxil::ResourceBindingInfo RBInfo : RBInfos) {
+          CounterDirections.emplace_back(RBInfo, Direction);
+        }
+      }
+    }
+
+    // An entry that is not in the map is considered unknown so its wasted
+    // overhead and increased complexity to keep it so it should be removed.
+    const auto RemoveEnd = std::remove_if(CounterDirections.begin(), CounterDirections.end(), [](const auto& Item) { 
+         return Item.second == ResourceCounterDirection::Unknown;
+    });
+
+    // Order for fast lookup
+    std::sort(CounterDirections.begin(), RemoveEnd);
+
+    // Remove the duplicate entries. Since direction is considered for equality
+    // a unique resource with more than one direction will not be deduped.
+    const auto UniqueEnd = std::unique(CounterDirections.begin(), RemoveEnd);
+
+    // Actually erase the items invalidated by remove_if + unique
+    CounterDirections.erase(UniqueEnd, CounterDirections.end());
+
+    // If any duplicate entries still exist at this point then it must be a
+    // resource that was both incremented and decremented which is not allowed.
+    const auto DuplicateEntry = std::adjacent_find(CounterDirections.begin(), CounterDirections.end(), [](const auto& LHS, const auto& RHS){
+      return LHS.first == RHS.first;
+    });
+    if (DuplicateEntry == CounterDirections.end())
+        return;
+
+    // TODO: Emit an error message
+    assert(CounterDirections.size() == 1 && "dups found");
+}
+
+bool DXILResourceCounterDirectionMap::invalidate(Module &M, const PreservedAnalyses &PA,
+                                     ModuleAnalysisManager::Invalidator &Inv) {
+  // Passes that introduce resource types must explicitly invalidate this pass.
+  // auto PAC = PA.getChecker<DXILResourceTypeAnalysis>();
+  // return !PAC.preservedWhenStateless();
+  return false;
+}
+
+void DXILResourceCounterDirectionWrapperPass::anchor() {}
+
+//===----------------------------------------------------------------------===//
+
 AnalysisKey DXILResourceTypeAnalysis::Key;
 AnalysisKey DXILResourceBindingAnalysis::Key;
+AnalysisKey DXILResourceCounterDirectionAnalysis::Key;
 
 DXILBindingMap DXILResourceBindingAnalysis::run(Module &M,
                                                 ModuleAnalysisManager &AM) {
@@ -838,6 +919,13 @@ DXILResourceBindingPrinterPass::run(Module &M, ModuleAnalysisManager &AM) {
   return PreservedAnalyses::all();
 }
 
+INITIALIZE_PASS(DXILResourceCounterDirectionWrapperPass, "dxil-resource-counter",
+                "DXIL Resource Counter Analysis", false, true)
+
+DXILResourceCounterDirectionWrapperPass::DXILResourceCounterDirectionWrapperPass() : ImmutablePass(ID) {
+  initializeDXILResourceTypeWrapperPassPass(*PassRegistry::getPassRegistry());
+}
+
 void DXILResourceTypeWrapperPass::anchor() {}
 
 DXILResourceTypeWrapperPass::DXILResourceTypeWrapperPass() : ImmutablePass(ID) {
@@ -847,11 +935,16 @@ DXILResourceTypeWrapperPass::DXILResourceTypeWrapperPass() : ImmutablePass(ID) {
 INITIALIZE_PASS(DXILResourceTypeWrapperPass, "dxil-resource-type",
                 "DXIL Resource Type Analysis", false, true)
 char DXILResourceTypeWrapperPass::ID = 0;
+char DXILResourceCounterDirectionWrapperPass::ID = 0;
 
 ModulePass *llvm::createDXILResourceTypeWrapperPassPass() {
   return new DXILResourceTypeWrapperPass();
 }
 
+ModulePass *llvm::createDXILResourceCounterDirectionWrapperPassPass() {
+  return new DXILResourceCounterDirectionWrapperPass();
+}
+
 DXILResourceBindingWrapperPass::DXILResourceBindingWrapperPass()
     : ModulePass(ID) {
   initializeDXILResourceBindingWrapperPassPass(
diff --git a/llvm/unittests/Target/DirectX/UniqueResourceFromUseTests.cpp b/llvm/unittests/Target/DirectX/UniqueResourceFromUseTests.cpp
index f272381c0c250..a991cf230d930 100644
--- a/llvm/unittests/Target/DirectX/UniqueResourceFromUseTests.cpp
+++ b/llvm/unittests/Target/DirectX/UniqueResourceFromUseTests.cpp
@@ -35,6 +35,7 @@ class UniqueResourceFromUseTest : public testing::Test {
     PB->registerModuleAnalyses(*MAM);
     MAM->registerPass([&] { return DXILResourceTypeAnalysis(); });
     MAM->registerPass([&] { return DXILResourceBindingAnalysis(); });
+    MAM->registerPass([&] { return DXILResourceCounterDirectionAnalysis(); });
   }
 
   virtual void TearDown() {
@@ -280,4 +281,47 @@ declare target("dx.RawBuffer", float, 1, 0) @ind.func(target("dx.RawBuffer", flo
   }
 }
 
+TEST_F(UniqueResourceFromUseTest, TestResourceCounter) {
+  StringRef Assembly = R"(
+define void @main() {
+entry:
+  %handle = call target("dx.RawBuffer", float, 1, 0) @llvm.dx.resource.handlefrombinding.tdx.RawBuffer_f32_1_0t(i32 1, i32 2, i32 3, i32 4, i1 false)
+  call i32 @llvm.dx.resource.updatecounter.tdx.RawBuffer_f32_1_0t(target("dx.RawBuffer", float, 1, 0) %handle, i8 -1)
+  call i32 @llvm.dx.resource.updatecounter.tdx.RawBuffer_f32_1_0t(target("dx.RawBuffer", float, 1, 0) %handle, i8 -1)
+  call i32 @llvm.dx.resource.updatecounter.tdx.RawBuffer_f32_1_0t(target("dx.RawBuffer", float, 1, 0) %handle, i8 -1)
+  call i32 @llvm.dx.resource.updatecounter.tdx.RawBuffer_f32_1_0t(target("dx.RawBuffer", float, 1, 0) %handle, i8 -1)
+  call i32 @llvm.dx.resource.updatecounter.tdx.RawBuffer_f32_1_0t(target("dx.RawBuffer", float, 1, 0) %handle, i8 -1)
+  call i32 @llvm.dx.resource.updatecounter.tdx.RawBuffer_f32_1_0t(target("dx.RawBuffer", float, 1, 0) %handle, i8 -1)
+  call void @a.func(target("dx.RawBuffer", float, 1, 0) %handle)
+  ret void
+}
+
+declare target("dx.RawBuffer", float, 1, 0) @llvm.dx.resource.handlefrombinding.tdx.RawBuffer_f32_1_0t(i32, i32, i32, i32, i1)
+declare i32 @llvm.dx.resource.updatecounter.tdx.RawBuffer_f32_1_0t(target("dx.RawBuffer", float, 1, 0), i8)
+declare void @a.func(target("dx.RawBuffer", float, 1, 0) %handle)
+  )";
+
+  LLVMContext Context;
+  SMDiagnostic Error;
+  auto M = parseAssemblyString(Assembly, Error, Context);
+  ASSERT_TRUE(M) << "Bad assembly?";
+
+  const DXILBindingMap &DBM = MAM->getResult<DXILResourceBindingAnalysis>(*M);
+  const DXILResourceCounterDirectionMap &DCDM = MAM->getResult<DXILResourceCounterDirectionAnalysis>(*M);
+
+  for (const Function &F : M->functions()) {
+    if (F.getName() != "a.func") {
+      continue;
+    }
+
+    for (const User *U : F.users()) {
+      const CallInst *CI = cast<CallInst>(U);
+      const Value *Handle = CI->getArgOperand(0);
+      const auto Bindings = DBM.findByUse(Handle);
+      ASSERT_EQ(Bindings.size(), 1u);
+      ASSERT_EQ(DCDM[Bindings.front()], ResourceCounterDirection::Decrement);
+    }
+  }
+}
+
 } // namespace

>From 28e7369e462a7b2b7bac3c0e01351b8cb7dfb6c0 Mon Sep 17 00:00:00 2001
From: Ashley Coleman <ascoleman at microsoft.com>
Date: Wed, 5 Mar 2025 17:23:36 -0700
Subject: [PATCH 02/19] format

---
 llvm/include/llvm/Analysis/DXILResource.h     |  26 ++--
 llvm/lib/Analysis/DXILResource.cpp            | 117 +++++++++---------
 .../DirectX/UniqueResourceFromUseTests.cpp    |   3 +-
 3 files changed, 80 insertions(+), 66 deletions(-)

diff --git a/llvm/include/llvm/Analysis/DXILResource.h b/llvm/include/llvm/Analysis/DXILResource.h
index 3f11b07cd75eb..61ee3b99d250f 100644
--- a/llvm/include/llvm/Analysis/DXILResource.h
+++ b/llvm/include/llvm/Analysis/DXILResource.h
@@ -418,18 +418,21 @@ enum ResourceCounterDirection {
 };
 
 class DXILResourceCounterDirectionMap {
-  std::vector<std::pair<dxil::ResourceBindingInfo, ResourceCounterDirection>> CounterDirections;
+  std::vector<std::pair<dxil::ResourceBindingInfo, ResourceCounterDirection>>
+      CounterDirections;
 
 public:
   bool invalidate(Module &M, const PreservedAnalyses &PA,
                   ModuleAnalysisManager::Invalidator &Inv);
 
-   void populate(Module &M, ModuleAnalysisManager &AM);
+  void populate(Module &M, ModuleAnalysisManager &AM);
 
-   ResourceCounterDirection operator[](const dxil::ResourceBindingInfo &Info) const {
-    auto Lower = std::lower_bound(CounterDirections.begin(), CounterDirections.end(), std::pair{Info, ResourceCounterDirection::Unknown},  [](auto lhs, auto rhs){
-                                  return lhs.first  < rhs.first;
-    });
+  ResourceCounterDirection
+  operator[](const dxil::ResourceBindingInfo &Info) const {
+    auto Lower = std::lower_bound(
+        CounterDirections.begin(), CounterDirections.end(),
+        std::pair{Info, ResourceCounterDirection::Unknown},
+        [](auto lhs, auto rhs) { return lhs.first < rhs.first; });
 
     if (Lower == CounterDirections.end()) {
       return ResourceCounterDirection::Unknown;
@@ -440,7 +443,7 @@ class DXILResourceCounterDirectionMap {
     }
 
     return Lower->second;
-   }
+  }
 };
 
 class DXILResourceCounterDirectionAnalysis
@@ -468,8 +471,13 @@ class DXILResourceCounterDirectionWrapperPass : public ImmutablePass {
   static char ID;
   DXILResourceCounterDirectionWrapperPass();
 
-  DXILResourceCounterDirectionMap &getResourceCounterDirectionMap() { return DRCDM; }
-  const DXILResourceCounterDirectionMap &getResourceCounterDirectionMap() const { return DRCDM; }
+  DXILResourceCounterDirectionMap &getResourceCounterDirectionMap() {
+    return DRCDM;
+  }
+  const DXILResourceCounterDirectionMap &
+  getResourceCounterDirectionMap() const {
+    return DRCDM;
+  }
 };
 
 ModulePass *createDXILResourceCounterDirectionWrapperPassPass();
diff --git a/llvm/lib/Analysis/DXILResource.cpp b/llvm/lib/Analysis/DXILResource.cpp
index 59e432075db17..d274de11d9bc0 100644
--- a/llvm/lib/Analysis/DXILResource.cpp
+++ b/llvm/lib/Analysis/DXILResource.cpp
@@ -823,71 +823,73 @@ static bool isUpdateCounterIntrinsic(Function &F) {
   return F.getIntrinsicID() == Intrinsic::dx_resource_updatecounter;
 }
 
-void DXILResourceCounterDirectionMap::populate(Module &M, ModuleAnalysisManager &AM) {
-    DXILBindingMap &DBM = AM.getResult<DXILResourceBindingAnalysis>(M);
-    CounterDirections.clear();
-
-    for (Function &F : M.functions()) {
-      if (!isUpdateCounterIntrinsic(F))
-        continue;
-
-      for (const User *U : F.users()) {
-        const CallInst *CI = dyn_cast<CallInst>(U);
-        assert(CI && "Users of dx_resource_updateCounter must be call instrs");
-
-        // Determine if the use is an increment or decrement
-        Value *CountArg = CI->getArgOperand(1);
-        ConstantInt *CountValue = dyn_cast<ConstantInt>(CountArg);
-        int64_t CountLiteral = CountValue->getSExtValue();
-
-        ResourceCounterDirection Direction = ResourceCounterDirection::Unknown;
-        if (CountLiteral > 0) {
-          Direction = ResourceCounterDirection::Increment;
-        }
-        if (CountLiteral < 0) {
-          Direction = ResourceCounterDirection::Decrement;
-        }
+void DXILResourceCounterDirectionMap::populate(Module &M,
+                                               ModuleAnalysisManager &AM) {
+  DXILBindingMap &DBM = AM.getResult<DXILResourceBindingAnalysis>(M);
+  CounterDirections.clear();
 
+  for (Function &F : M.functions()) {
+    if (!isUpdateCounterIntrinsic(F))
+      continue;
 
-        // Collect all potential creation points for the handle arg
-        Value *HandleArg = CI->getArgOperand(0);
-        SmallVector<dxil::ResourceBindingInfo> RBInfos = DBM.findByUse(HandleArg);
-        for(const dxil::ResourceBindingInfo RBInfo : RBInfos) {
-          CounterDirections.emplace_back(RBInfo, Direction);
-        }
+    for (const User *U : F.users()) {
+      const CallInst *CI = dyn_cast<CallInst>(U);
+      assert(CI && "Users of dx_resource_updateCounter must be call instrs");
+
+      // Determine if the use is an increment or decrement
+      Value *CountArg = CI->getArgOperand(1);
+      ConstantInt *CountValue = dyn_cast<ConstantInt>(CountArg);
+      int64_t CountLiteral = CountValue->getSExtValue();
+
+      ResourceCounterDirection Direction = ResourceCounterDirection::Unknown;
+      if (CountLiteral > 0) {
+        Direction = ResourceCounterDirection::Increment;
+      }
+      if (CountLiteral < 0) {
+        Direction = ResourceCounterDirection::Decrement;
+      }
+
+      // Collect all potential creation points for the handle arg
+      Value *HandleArg = CI->getArgOperand(0);
+      SmallVector<dxil::ResourceBindingInfo> RBInfos = DBM.findByUse(HandleArg);
+      for (const dxil::ResourceBindingInfo RBInfo : RBInfos) {
+        CounterDirections.emplace_back(RBInfo, Direction);
       }
     }
+  }
 
-    // An entry that is not in the map is considered unknown so its wasted
-    // overhead and increased complexity to keep it so it should be removed.
-    const auto RemoveEnd = std::remove_if(CounterDirections.begin(), CounterDirections.end(), [](const auto& Item) { 
-         return Item.second == ResourceCounterDirection::Unknown;
-    });
+  // An entry that is not in the map is considered unknown so its wasted
+  // overhead and increased complexity to keep it so it should be removed.
+  const auto RemoveEnd = std::remove_if(
+      CounterDirections.begin(), CounterDirections.end(), [](const auto &Item) {
+        return Item.second == ResourceCounterDirection::Unknown;
+      });
 
-    // Order for fast lookup
-    std::sort(CounterDirections.begin(), RemoveEnd);
+  // Order for fast lookup
+  std::sort(CounterDirections.begin(), RemoveEnd);
 
-    // Remove the duplicate entries. Since direction is considered for equality
-    // a unique resource with more than one direction will not be deduped.
-    const auto UniqueEnd = std::unique(CounterDirections.begin(), RemoveEnd);
+  // Remove the duplicate entries. Since direction is considered for equality
+  // a unique resource with more than one direction will not be deduped.
+  const auto UniqueEnd = std::unique(CounterDirections.begin(), RemoveEnd);
 
-    // Actually erase the items invalidated by remove_if + unique
-    CounterDirections.erase(UniqueEnd, CounterDirections.end());
+  // Actually erase the items invalidated by remove_if + unique
+  CounterDirections.erase(UniqueEnd, CounterDirections.end());
 
-    // If any duplicate entries still exist at this point then it must be a
-    // resource that was both incremented and decremented which is not allowed.
-    const auto DuplicateEntry = std::adjacent_find(CounterDirections.begin(), CounterDirections.end(), [](const auto& LHS, const auto& RHS){
-      return LHS.first == RHS.first;
-    });
-    if (DuplicateEntry == CounterDirections.end())
-        return;
+  // If any duplicate entries still exist at this point then it must be a
+  // resource that was both incremented and decremented which is not allowed.
+  const auto DuplicateEntry = std::adjacent_find(
+      CounterDirections.begin(), CounterDirections.end(),
+      [](const auto &LHS, const auto &RHS) { return LHS.first == RHS.first; });
+  if (DuplicateEntry == CounterDirections.end())
+    return;
 
-    // TODO: Emit an error message
-    assert(CounterDirections.size() == 1 && "dups found");
+  // TODO: Emit an error message
+  assert(CounterDirections.size() == 1 && "dups found");
 }
 
-bool DXILResourceCounterDirectionMap::invalidate(Module &M, const PreservedAnalyses &PA,
-                                     ModuleAnalysisManager::Invalidator &Inv) {
+bool DXILResourceCounterDirectionMap::invalidate(
+    Module &M, const PreservedAnalyses &PA,
+    ModuleAnalysisManager::Invalidator &Inv) {
   // Passes that introduce resource types must explicitly invalidate this pass.
   // auto PAC = PA.getChecker<DXILResourceTypeAnalysis>();
   // return !PAC.preservedWhenStateless();
@@ -919,10 +921,13 @@ DXILResourceBindingPrinterPass::run(Module &M, ModuleAnalysisManager &AM) {
   return PreservedAnalyses::all();
 }
 
-INITIALIZE_PASS(DXILResourceCounterDirectionWrapperPass, "dxil-resource-counter",
-                "DXIL Resource Counter Analysis", false, true)
+INITIALIZE_PASS(DXILResourceCounterDirectionWrapperPass,
+                "dxil-resource-counter", "DXIL Resource Counter Analysis",
+                false, true)
 
-DXILResourceCounterDirectionWrapperPass::DXILResourceCounterDirectionWrapperPass() : ImmutablePass(ID) {
+DXILResourceCounterDirectionWrapperPass::
+    DXILResourceCounterDirectionWrapperPass()
+    : ImmutablePass(ID) {
   initializeDXILResourceTypeWrapperPassPass(*PassRegistry::getPassRegistry());
 }
 
diff --git a/llvm/unittests/Target/DirectX/UniqueResourceFromUseTests.cpp b/llvm/unittests/Target/DirectX/UniqueResourceFromUseTests.cpp
index a991cf230d930..9cacd005f6b14 100644
--- a/llvm/unittests/Target/DirectX/UniqueResourceFromUseTests.cpp
+++ b/llvm/unittests/Target/DirectX/UniqueResourceFromUseTests.cpp
@@ -307,7 +307,8 @@ declare void @a.func(target("dx.RawBuffer", float, 1, 0) %handle)
   ASSERT_TRUE(M) << "Bad assembly?";
 
   const DXILBindingMap &DBM = MAM->getResult<DXILResourceBindingAnalysis>(*M);
-  const DXILResourceCounterDirectionMap &DCDM = MAM->getResult<DXILResourceCounterDirectionAnalysis>(*M);
+  const DXILResourceCounterDirectionMap &DCDM =
+      MAM->getResult<DXILResourceCounterDirectionAnalysis>(*M);
 
   for (const Function &F : M->functions()) {
     if (F.getName() != "a.func") {

>From 90621829cb71e6a2fcd465728f2b1e586dd03f1c Mon Sep 17 00:00:00 2001
From: Ashley Coleman <ascoleman at microsoft.com>
Date: Fri, 7 Mar 2025 14:57:00 -0700
Subject: [PATCH 03/19] Add Diag and tests

---
 llvm/lib/Analysis/DXILResource.cpp            |  10 +-
 llvm/lib/Passes/PassRegistry.def              |   1 +
 llvm/lib/Target/DirectX/DXILOpLowering.cpp    |   1 +
 .../CodeGen/DirectX/resource_counter_error.ll |  13 ++
 .../DirectX/UniqueResourceFromUseTests.cpp    | 130 +++++++++++++++++-
 5 files changed, 147 insertions(+), 8 deletions(-)
 create mode 100644 llvm/test/CodeGen/DirectX/resource_counter_error.ll

diff --git a/llvm/lib/Analysis/DXILResource.cpp b/llvm/lib/Analysis/DXILResource.cpp
index d274de11d9bc0..82a42e5c44359 100644
--- a/llvm/lib/Analysis/DXILResource.cpp
+++ b/llvm/lib/Analysis/DXILResource.cpp
@@ -9,6 +9,7 @@
 #include "llvm/Analysis/DXILResource.h"
 #include "llvm/ADT/APInt.h"
 #include "llvm/ADT/SmallString.h"
+#include "llvm/ADT/StringRef.h"
 #include "llvm/IR/Constants.h"
 #include "llvm/IR/DerivedTypes.h"
 #include "llvm/IR/DiagnosticInfo.h"
@@ -20,6 +21,7 @@
 #include "llvm/InitializePasses.h"
 #include "llvm/Support/FormatVariadic.h"
 #include <algorithm>
+#include "llvm/IR/DiagnosticInfo.h"
 
 #define DEBUG_TYPE "dxil-resource"
 
@@ -858,8 +860,8 @@ void DXILResourceCounterDirectionMap::populate(Module &M,
     }
   }
 
-  // An entry that is not in the map is considered unknown so its wasted
-  // overhead and increased complexity to keep it so it should be removed.
+  // An entry that is not in the map is considered unknown so its wasted overhead
+  // and increased complexity to keep an entry explicitly marked unknown
   const auto RemoveEnd = std::remove_if(
       CounterDirections.begin(), CounterDirections.end(), [](const auto &Item) {
         return Item.second == ResourceCounterDirection::Unknown;
@@ -883,8 +885,8 @@ void DXILResourceCounterDirectionMap::populate(Module &M,
   if (DuplicateEntry == CounterDirections.end())
     return;
 
-  // TODO: Emit an error message
-  assert(CounterDirections.size() == 1 && "dups found");
+  StringRef Message = "RWStructuredBuffers may increment or decrement their counters, but not both.";
+  M.getContext().diagnose(DiagnosticInfoGeneric(Message));
 }
 
 bool DXILResourceCounterDirectionMap::invalidate(
diff --git a/llvm/lib/Passes/PassRegistry.def b/llvm/lib/Passes/PassRegistry.def
index a664d6fd7085f..5812add8c701a 100644
--- a/llvm/lib/Passes/PassRegistry.def
+++ b/llvm/lib/Passes/PassRegistry.def
@@ -24,6 +24,7 @@ MODULE_ANALYSIS("ctx-prof-analysis", CtxProfAnalysis())
 MODULE_ANALYSIS("dxil-metadata", DXILMetadataAnalysis())
 MODULE_ANALYSIS("dxil-resource-binding", DXILResourceBindingAnalysis())
 MODULE_ANALYSIS("dxil-resource-type", DXILResourceTypeAnalysis())
+MODULE_ANALYSIS("dxil-resource-counter-direction", DXILResourceCounterDirectionAnalysis())
 MODULE_ANALYSIS("inline-advisor", InlineAdvisorAnalysis())
 MODULE_ANALYSIS("ir-similarity", IRSimilarityAnalysis())
 MODULE_ANALYSIS("last-run-tracking", LastRunTrackingAnalysis())
diff --git a/llvm/lib/Target/DirectX/DXILOpLowering.cpp b/llvm/lib/Target/DirectX/DXILOpLowering.cpp
index 83cc4b18824c7..b4bf40d26489f 100644
--- a/llvm/lib/Target/DirectX/DXILOpLowering.cpp
+++ b/llvm/lib/Target/DirectX/DXILOpLowering.cpp
@@ -816,6 +816,7 @@ class OpLowerer {
 PreservedAnalyses DXILOpLowering::run(Module &M, ModuleAnalysisManager &MAM) {
   DXILBindingMap &DBM = MAM.getResult<DXILResourceBindingAnalysis>(M);
   DXILResourceTypeMap &DRTM = MAM.getResult<DXILResourceTypeAnalysis>(M);
+  DXILResourceCounterDirectionMap &DRCDM = MAM.getResult<DXILResourceCounterDirectionAnalysis>(M);
 
   bool MadeChanges = OpLowerer(M, DBM, DRTM).lowerIntrinsics();
   if (!MadeChanges)
diff --git a/llvm/test/CodeGen/DirectX/resource_counter_error.ll b/llvm/test/CodeGen/DirectX/resource_counter_error.ll
new file mode 100644
index 0000000000000..48ce32031ef00
--- /dev/null
+++ b/llvm/test/CodeGen/DirectX/resource_counter_error.ll
@@ -0,0 +1,13 @@
+; RUN: not opt -S -passes='dxil-op-lower' -mtriple=dxil-pc-shadermodel6.3-library %s 2>&1 | FileCheck %s
+; CHECK:  RWStructuredBuffers may increment or decrement their counters, but not both.
+
+define void @inc_and_dec() {
+entry:
+  %handle = call target("dx.RawBuffer", float, 1, 0) @llvm.dx.resource.handlefrombinding.tdx.RawBuffer_f32_1_0t(i32 1, i32 2, i32 3, i32 4, i1 false)
+  call i32 @llvm.dx.resource.updatecounter.tdx.RawBuffer_f32_1_0t(target("dx.RawBuffer", float, 1, 0) %handle, i8 -1)
+  call i32 @llvm.dx.resource.updatecounter.tdx.RawBuffer_f32_1_0t(target("dx.RawBuffer", float, 1, 0) %handle, i8 1)
+  ret void
+}
+
+declare target("dx.RawBuffer", float, 1, 0) @llvm.dx.resource.handlefrombinding.tdx.RawBuffer_f32_1_0t(i32, i32, i32, i32, i1)
+declare i32 @llvm.dx.resource.updatecounter.tdx.RawBuffer_f32_1_0t(target("dx.RawBuffer", float, 1, 0), i8)
diff --git a/llvm/unittests/Target/DirectX/UniqueResourceFromUseTests.cpp b/llvm/unittests/Target/DirectX/UniqueResourceFromUseTests.cpp
index 9cacd005f6b14..c9c526ef058ea 100644
--- a/llvm/unittests/Target/DirectX/UniqueResourceFromUseTests.cpp
+++ b/llvm/unittests/Target/DirectX/UniqueResourceFromUseTests.cpp
@@ -281,7 +281,7 @@ declare target("dx.RawBuffer", float, 1, 0) @ind.func(target("dx.RawBuffer", flo
   }
 }
 
-TEST_F(UniqueResourceFromUseTest, TestResourceCounter) {
+TEST_F(UniqueResourceFromUseTest, TestResourceCounterDecrement) {
   StringRef Assembly = R"(
 define void @main() {
 entry:
@@ -289,9 +289,6 @@ define void @main() {
   call i32 @llvm.dx.resource.updatecounter.tdx.RawBuffer_f32_1_0t(target("dx.RawBuffer", float, 1, 0) %handle, i8 -1)
   call i32 @llvm.dx.resource.updatecounter.tdx.RawBuffer_f32_1_0t(target("dx.RawBuffer", float, 1, 0) %handle, i8 -1)
   call i32 @llvm.dx.resource.updatecounter.tdx.RawBuffer_f32_1_0t(target("dx.RawBuffer", float, 1, 0) %handle, i8 -1)
-  call i32 @llvm.dx.resource.updatecounter.tdx.RawBuffer_f32_1_0t(target("dx.RawBuffer", float, 1, 0) %handle, i8 -1)
-  call i32 @llvm.dx.resource.updatecounter.tdx.RawBuffer_f32_1_0t(target("dx.RawBuffer", float, 1, 0) %handle, i8 -1)
-  call i32 @llvm.dx.resource.updatecounter.tdx.RawBuffer_f32_1_0t(target("dx.RawBuffer", float, 1, 0) %handle, i8 -1)
   call void @a.func(target("dx.RawBuffer", float, 1, 0) %handle)
   ret void
 }
@@ -325,4 +322,129 @@ declare void @a.func(target("dx.RawBuffer", float, 1, 0) %handle)
   }
 }
 
+TEST_F(UniqueResourceFromUseTest, TestResourceCounterIncrement) {
+  StringRef Assembly = R"(
+define void @main() {
+entry:
+  %handle = call target("dx.RawBuffer", float, 1, 0) @llvm.dx.resource.handlefrombinding.tdx.RawBuffer_f32_1_0t(i32 1, i32 2, i32 3, i32 4, i1 false)
+  call i32 @llvm.dx.resource.updatecounter.tdx.RawBuffer_f32_1_0t(target("dx.RawBuffer", float, 1, 0) %handle, i8 1)
+  call i32 @llvm.dx.resource.updatecounter.tdx.RawBuffer_f32_1_0t(target("dx.RawBuffer", float, 1, 0) %handle, i8 1)
+  call i32 @llvm.dx.resource.updatecounter.tdx.RawBuffer_f32_1_0t(target("dx.RawBuffer", float, 1, 0) %handle, i8 1)
+  call void @a.func(target("dx.RawBuffer", float, 1, 0) %handle)
+  ret void
+}
+
+declare target("dx.RawBuffer", float, 1, 0) @llvm.dx.resource.handlefrombinding.tdx.RawBuffer_f32_1_0t(i32, i32, i32, i32, i1)
+declare i32 @llvm.dx.resource.updatecounter.tdx.RawBuffer_f32_1_0t(target("dx.RawBuffer", float, 1, 0), i8)
+declare void @a.func(target("dx.RawBuffer", float, 1, 0) %handle)
+  )";
+
+  LLVMContext Context;
+  SMDiagnostic Error;
+  auto M = parseAssemblyString(Assembly, Error, Context);
+  ASSERT_TRUE(M) << "Bad assembly?";
+
+  const DXILBindingMap &DBM = MAM->getResult<DXILResourceBindingAnalysis>(*M);
+  const DXILResourceCounterDirectionMap &DCDM =
+      MAM->getResult<DXILResourceCounterDirectionAnalysis>(*M);
+
+  for (const Function &F : M->functions()) {
+    if (F.getName() != "a.func") {
+      continue;
+    }
+
+    for (const User *U : F.users()) {
+      const CallInst *CI = cast<CallInst>(U);
+      const Value *Handle = CI->getArgOperand(0);
+      const auto Bindings = DBM.findByUse(Handle);
+      ASSERT_EQ(Bindings.size(), 1u);
+      ASSERT_EQ(DCDM[Bindings.front()], ResourceCounterDirection::Increment);
+    }
+  }
+}
+
+TEST_F(UniqueResourceFromUseTest, TestResourceCounterUnknown) {
+  StringRef Assembly = R"(
+define void @main() {
+entry:
+  %handle = call target("dx.RawBuffer", float, 1, 0) @llvm.dx.resource.handlefrombinding.tdx.RawBuffer_f32_1_0t(i32 1, i32 2, i32 3, i32 4, i1 false)
+  call void @a.func(target("dx.RawBuffer", float, 1, 0) %handle)
+  ret void
+}
+
+declare target("dx.RawBuffer", float, 1, 0) @llvm.dx.resource.handlefrombinding.tdx.RawBuffer_f32_1_0t(i32, i32, i32, i32, i1)
+declare i32 @llvm.dx.resource.updatecounter.tdx.RawBuffer_f32_1_0t(target("dx.RawBuffer", float, 1, 0), i8)
+declare void @a.func(target("dx.RawBuffer", float, 1, 0) %handle)
+  )";
+
+  LLVMContext Context;
+  SMDiagnostic Error;
+  auto M = parseAssemblyString(Assembly, Error, Context);
+  ASSERT_TRUE(M) << "Bad assembly?";
+
+  const DXILBindingMap &DBM = MAM->getResult<DXILResourceBindingAnalysis>(*M);
+  const DXILResourceCounterDirectionMap &DCDM =
+      MAM->getResult<DXILResourceCounterDirectionAnalysis>(*M);
+
+  for (const Function &F : M->functions()) {
+    if (F.getName() != "a.func") {
+      continue;
+    }
+
+    for (const User *U : F.users()) {
+      const CallInst *CI = cast<CallInst>(U);
+      const Value *Handle = CI->getArgOperand(0);
+      const auto Bindings = DBM.findByUse(Handle);
+      ASSERT_EQ(Bindings.size(), 1u);
+      ASSERT_EQ(DCDM[Bindings.front()], ResourceCounterDirection::Unknown);
+    }
+  }
+}
+
+TEST_F(UniqueResourceFromUseTest, TestResourceCounterMultiple) {
+  StringRef Assembly = R"(
+define void @main() {
+entry:
+  %handle1 = call target("dx.RawBuffer", float, 1, 0) @llvm.dx.resource.handlefrombinding.tdx.RawBuffer_f32_1_0t(i32 1, i32 2, i32 3, i32 4, i1 false)
+  %handle2 = call target("dx.RawBuffer", float, 1, 0) @llvm.dx.resource.handlefrombinding.tdx.RawBuffer_f32_1_0t(i32 4, i32 3, i32 2, i32 1, i1 false)
+  call i32 @llvm.dx.resource.updatecounter.tdx.RawBuffer_f32_1_0t(target("dx.RawBuffer", float, 1, 0) %handle1, i8 -1)
+  call i32 @llvm.dx.resource.updatecounter.tdx.RawBuffer_f32_1_0t(target("dx.RawBuffer", float, 1, 0) %handle2, i8 1)
+  call void @a.func(target("dx.RawBuffer", float, 1, 0) %handle1)
+  call void @b.func(target("dx.RawBuffer", float, 1, 0) %handle2)
+  ret void
+}
+
+declare target("dx.RawBuffer", float, 1, 0) @llvm.dx.resource.handlefrombinding.tdx.RawBuffer_f32_1_0t(i32, i32, i32, i32, i1)
+declare i32 @llvm.dx.resource.updatecounter.tdx.RawBuffer_f32_1_0t(target("dx.RawBuffer", float, 1, 0), i8)
+declare void @a.func(target("dx.RawBuffer", float, 1, 0) %handle)
+declare void @b.func(target("dx.RawBuffer", float, 1, 0) %handle)
+  )";
+
+  LLVMContext Context;
+  SMDiagnostic Error;
+  auto M = parseAssemblyString(Assembly, Error, Context);
+  ASSERT_TRUE(M) << "Bad assembly?";
+
+  const DXILBindingMap &DBM = MAM->getResult<DXILResourceBindingAnalysis>(*M);
+  const DXILResourceCounterDirectionMap &DCDM =
+      MAM->getResult<DXILResourceCounterDirectionAnalysis>(*M);
+
+  for (const Function &F : M->functions()) {
+    StringRef FName = F.getName();
+    if (FName != "a.func" && FName != "b.func") {
+      continue;
+    }
+
+    auto Dir = FName == "a.func" ? ResourceCounterDirection::Decrement : ResourceCounterDirection::Increment;
+
+    for (const User *U : F.users()) {
+      const CallInst *CI = cast<CallInst>(U);
+      const Value *Handle = CI->getArgOperand(0);
+      const auto Bindings = DBM.findByUse(Handle);
+      ASSERT_EQ(Bindings.size(), 1u);
+      ASSERT_EQ(DCDM[Bindings.front()], Dir);
+    }
+  }
+}
+
 } // namespace

>From 7c777715cc05d0d0c8b88bd7221d4d424db3c26c Mon Sep 17 00:00:00 2001
From: Ashley Coleman <ascoleman at microsoft.com>
Date: Fri, 7 Mar 2025 14:57:37 -0700
Subject: [PATCH 04/19] format

---
 llvm/lib/Analysis/DXILResource.cpp                       | 9 +++++----
 llvm/lib/Target/DirectX/DXILOpLowering.cpp               | 3 ++-
 .../Target/DirectX/UniqueResourceFromUseTests.cpp        | 3 ++-
 3 files changed, 9 insertions(+), 6 deletions(-)

diff --git a/llvm/lib/Analysis/DXILResource.cpp b/llvm/lib/Analysis/DXILResource.cpp
index 82a42e5c44359..b5e28199593a4 100644
--- a/llvm/lib/Analysis/DXILResource.cpp
+++ b/llvm/lib/Analysis/DXILResource.cpp
@@ -21,7 +21,6 @@
 #include "llvm/InitializePasses.h"
 #include "llvm/Support/FormatVariadic.h"
 #include <algorithm>
-#include "llvm/IR/DiagnosticInfo.h"
 
 #define DEBUG_TYPE "dxil-resource"
 
@@ -860,8 +859,9 @@ void DXILResourceCounterDirectionMap::populate(Module &M,
     }
   }
 
-  // An entry that is not in the map is considered unknown so its wasted overhead
-  // and increased complexity to keep an entry explicitly marked unknown
+  // An entry that is not in the map is considered unknown so its wasted
+  // overhead and increased complexity to keep an entry explicitly marked
+  // unknown
   const auto RemoveEnd = std::remove_if(
       CounterDirections.begin(), CounterDirections.end(), [](const auto &Item) {
         return Item.second == ResourceCounterDirection::Unknown;
@@ -885,7 +885,8 @@ void DXILResourceCounterDirectionMap::populate(Module &M,
   if (DuplicateEntry == CounterDirections.end())
     return;
 
-  StringRef Message = "RWStructuredBuffers may increment or decrement their counters, but not both.";
+  StringRef Message = "RWStructuredBuffers may increment or decrement their "
+                      "counters, but not both.";
   M.getContext().diagnose(DiagnosticInfoGeneric(Message));
 }
 
diff --git a/llvm/lib/Target/DirectX/DXILOpLowering.cpp b/llvm/lib/Target/DirectX/DXILOpLowering.cpp
index b4bf40d26489f..ba2f2d9096d03 100644
--- a/llvm/lib/Target/DirectX/DXILOpLowering.cpp
+++ b/llvm/lib/Target/DirectX/DXILOpLowering.cpp
@@ -816,7 +816,8 @@ class OpLowerer {
 PreservedAnalyses DXILOpLowering::run(Module &M, ModuleAnalysisManager &MAM) {
   DXILBindingMap &DBM = MAM.getResult<DXILResourceBindingAnalysis>(M);
   DXILResourceTypeMap &DRTM = MAM.getResult<DXILResourceTypeAnalysis>(M);
-  DXILResourceCounterDirectionMap &DRCDM = MAM.getResult<DXILResourceCounterDirectionAnalysis>(M);
+  DXILResourceCounterDirectionMap &DRCDM =
+      MAM.getResult<DXILResourceCounterDirectionAnalysis>(M);
 
   bool MadeChanges = OpLowerer(M, DBM, DRTM).lowerIntrinsics();
   if (!MadeChanges)
diff --git a/llvm/unittests/Target/DirectX/UniqueResourceFromUseTests.cpp b/llvm/unittests/Target/DirectX/UniqueResourceFromUseTests.cpp
index c9c526ef058ea..b653bc3127ffc 100644
--- a/llvm/unittests/Target/DirectX/UniqueResourceFromUseTests.cpp
+++ b/llvm/unittests/Target/DirectX/UniqueResourceFromUseTests.cpp
@@ -435,7 +435,8 @@ declare void @b.func(target("dx.RawBuffer", float, 1, 0) %handle)
       continue;
     }
 
-    auto Dir = FName == "a.func" ? ResourceCounterDirection::Decrement : ResourceCounterDirection::Increment;
+    auto Dir = FName == "a.func" ? ResourceCounterDirection::Decrement
+                                 : ResourceCounterDirection::Increment;
 
     for (const User *U : F.users()) {
       const CallInst *CI = cast<CallInst>(U);

>From 11c731e5a89150a6e2a30a90b8f5591d13ea1571 Mon Sep 17 00:00:00 2001
From: Ashley Coleman <ascoleman at microsoft.com>
Date: Mon, 10 Mar 2025 17:21:29 -0600
Subject: [PATCH 05/19] Use Module Pass

---
 llvm/include/llvm/Analysis/DXILResource.h | 147 +++++++++++-----------
 llvm/lib/Analysis/DXILResource.cpp        |  40 ++++--
 2 files changed, 104 insertions(+), 83 deletions(-)

diff --git a/llvm/include/llvm/Analysis/DXILResource.h b/llvm/include/llvm/Analysis/DXILResource.h
index 61ee3b99d250f..749d7739ee2b1 100644
--- a/llvm/include/llvm/Analysis/DXILResource.h
+++ b/llvm/include/llvm/Analysis/DXILResource.h
@@ -20,7 +20,6 @@
 
 #include <algorithm>
 #include <cstdint>
-#include <unordered_map>
 
 namespace llvm {
 class CallInst;
@@ -411,77 +410,6 @@ class DXILResourceTypeMap {
   }
 };
 
-enum ResourceCounterDirection {
-  Increment,
-  Decrement,
-  Unknown,
-};
-
-class DXILResourceCounterDirectionMap {
-  std::vector<std::pair<dxil::ResourceBindingInfo, ResourceCounterDirection>>
-      CounterDirections;
-
-public:
-  bool invalidate(Module &M, const PreservedAnalyses &PA,
-                  ModuleAnalysisManager::Invalidator &Inv);
-
-  void populate(Module &M, ModuleAnalysisManager &AM);
-
-  ResourceCounterDirection
-  operator[](const dxil::ResourceBindingInfo &Info) const {
-    auto Lower = std::lower_bound(
-        CounterDirections.begin(), CounterDirections.end(),
-        std::pair{Info, ResourceCounterDirection::Unknown},
-        [](auto lhs, auto rhs) { return lhs.first < rhs.first; });
-
-    if (Lower == CounterDirections.end()) {
-      return ResourceCounterDirection::Unknown;
-    }
-
-    if (Lower->first != Info) {
-      return ResourceCounterDirection::Unknown;
-    }
-
-    return Lower->second;
-  }
-};
-
-class DXILResourceCounterDirectionAnalysis
-    : public AnalysisInfoMixin<DXILResourceCounterDirectionAnalysis> {
-  friend AnalysisInfoMixin<DXILResourceCounterDirectionAnalysis>;
-
-  static AnalysisKey Key;
-
-public:
-  using Result = DXILResourceCounterDirectionMap;
-
-  DXILResourceCounterDirectionMap run(Module &M, ModuleAnalysisManager &AM) {
-    DXILResourceCounterDirectionMap DRCDM{};
-    DRCDM.populate(M, AM);
-    return DRCDM;
-  }
-};
-
-class DXILResourceCounterDirectionWrapperPass : public ImmutablePass {
-  DXILResourceCounterDirectionMap DRCDM;
-
-  virtual void anchor();
-
-public:
-  static char ID;
-  DXILResourceCounterDirectionWrapperPass();
-
-  DXILResourceCounterDirectionMap &getResourceCounterDirectionMap() {
-    return DRCDM;
-  }
-  const DXILResourceCounterDirectionMap &
-  getResourceCounterDirectionMap() const {
-    return DRCDM;
-  }
-};
-
-ModulePass *createDXILResourceCounterDirectionWrapperPassPass();
-
 class DXILResourceTypeAnalysis
     : public AnalysisInfoMixin<DXILResourceTypeAnalysis> {
   friend AnalysisInfoMixin<DXILResourceTypeAnalysis>;
@@ -649,6 +577,81 @@ class DXILResourceBindingWrapperPass : public ModulePass {
 
 ModulePass *createDXILResourceBindingWrapperPassPass();
 
+enum ResourceCounterDirection {
+  Increment,
+  Decrement,
+  Unknown,
+};
+
+class DXILResourceCounterDirectionMap {
+  std::vector<std::pair<dxil::ResourceBindingInfo, ResourceCounterDirection>>
+      CounterDirections;
+
+public:
+  void populate(Module &M, DXILBindingMap &DBM);
+
+  ResourceCounterDirection
+  operator[](const dxil::ResourceBindingInfo &Info) const {
+    auto Lower = std::lower_bound(
+        CounterDirections.begin(), CounterDirections.end(),
+        std::pair{Info, ResourceCounterDirection::Unknown},
+        [](auto LHS, auto RHS) { return LHS.first < RHS.first; });
+
+    if (Lower == CounterDirections.end()) {
+      return ResourceCounterDirection::Unknown;
+    }
+
+    if (Lower->first != Info) {
+      return ResourceCounterDirection::Unknown;
+    }
+
+    return Lower->second;
+  }
+};
+
+class DXILResourceCounterDirectionAnalysis
+    : public AnalysisInfoMixin<DXILResourceCounterDirectionAnalysis> {
+  friend AnalysisInfoMixin<DXILResourceCounterDirectionAnalysis>;
+
+  static AnalysisKey Key;
+
+public:
+  using Result = DXILResourceCounterDirectionMap;
+
+  DXILResourceCounterDirectionMap run(Module &M, ModuleAnalysisManager &AM) {
+    DXILResourceCounterDirectionMap DRCDM{};
+    DXILBindingMap &DBM = AM.getResult<DXILResourceBindingAnalysis>(M);
+    DRCDM.populate(M, DBM);
+    return DRCDM;
+  }
+};
+
+class DXILResourceCounterDirectionWrapperPass : public ModulePass {
+  std::unique_ptr<DXILResourceCounterDirectionMap> Map;
+
+public:
+  static char ID;
+  DXILResourceCounterDirectionWrapperPass();
+  ~DXILResourceCounterDirectionWrapperPass() override = default;
+
+  DXILResourceCounterDirectionMap &getResourceCounterDirectionMap() {
+    return *Map;
+  }
+  const DXILResourceCounterDirectionMap &
+  getResourceCounterDirectionMap() const {
+    return *Map;
+  }
+
+  void getAnalysisUsage(AnalysisUsage &AU) const override;
+  bool runOnModule(Module &M) override;
+  void releaseMemory() override;
+
+  void print(raw_ostream &OS, const Module *M) const override;
+};
+
+ModulePass *createDXILResourceCounterDirectionWrapperPassPass();
+
+
 } // namespace llvm
 
 #endif // LLVM_ANALYSIS_DXILRESOURCE_H
diff --git a/llvm/lib/Analysis/DXILResource.cpp b/llvm/lib/Analysis/DXILResource.cpp
index 82e8af46ec0c1..80d4595efdec7 100644
--- a/llvm/lib/Analysis/DXILResource.cpp
+++ b/llvm/lib/Analysis/DXILResource.cpp
@@ -830,8 +830,7 @@ static bool isUpdateCounterIntrinsic(Function &F) {
 }
 
 void DXILResourceCounterDirectionMap::populate(Module &M,
-                                               ModuleAnalysisManager &AM) {
-  DXILBindingMap &DBM = AM.getResult<DXILResourceBindingAnalysis>(M);
+                                               DXILBindingMap &DBM) {
   CounterDirections.clear();
 
   for (Function &F : M.functions()) {
@@ -895,17 +894,36 @@ void DXILResourceCounterDirectionMap::populate(Module &M,
   M.getContext().diagnose(DiagnosticInfoGeneric(Message));
 }
 
-bool DXILResourceCounterDirectionMap::invalidate(
-    Module &M, const PreservedAnalyses &PA,
-    ModuleAnalysisManager::Invalidator &Inv) {
-  // Passes that introduce resource types must explicitly invalidate this pass.
-  // auto PAC = PA.getChecker<DXILResourceTypeAnalysis>();
-  // return !PAC.preservedWhenStateless();
+void DXILResourceCounterDirectionWrapperPass::getAnalysisUsage(AnalysisUsage &AU) const {
+  AU.addRequiredTransitive<DXILResourceBindingWrapperPass>();
+  AU.setPreservesAll();
+}
+
+bool DXILResourceCounterDirectionWrapperPass::runOnModule(Module &M) {
+  Map.reset(new DXILResourceCounterDirectionMap());
+
+  auto DBM = getAnalysis<DXILResourceBindingWrapperPass>().getBindingMap();
+  Map->populate(M, DBM);
+
   return false;
 }
 
-void DXILResourceCounterDirectionWrapperPass::anchor() {}
+void DXILResourceCounterDirectionWrapperPass::releaseMemory() { Map.reset(); }
+
+void DXILResourceCounterDirectionWrapperPass::print(raw_ostream &OS,
+                                           const Module *M) const {
+  if (!Map) {
+    OS << "No resource directions have been built!\n";
+    return;
+  }
+  //Map->print(OS, *DRTM, M->getDataLayout());
+}
+
 
+//#if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP)
+//LLVM_DUMP_METHOD
+//void DXILResourceCounterDirectionWrapperPass::dump() const { print(dbgs(), nullptr); }
+//#endif
 //===----------------------------------------------------------------------===//
 
 AnalysisKey DXILResourceTypeAnalysis::Key;
@@ -935,8 +953,8 @@ INITIALIZE_PASS(DXILResourceCounterDirectionWrapperPass,
 
 DXILResourceCounterDirectionWrapperPass::
     DXILResourceCounterDirectionWrapperPass()
-    : ImmutablePass(ID) {
-  initializeDXILResourceTypeWrapperPassPass(*PassRegistry::getPassRegistry());
+    : ModulePass(ID) {
+  initializeDXILResourceCounterDirectionWrapperPassPass(*PassRegistry::getPassRegistry());
 }
 
 void DXILResourceTypeWrapperPass::anchor() {}

>From 955ce1b03413b484a44b50ed670310103ec933c4 Mon Sep 17 00:00:00 2001
From: Ashley Coleman <ascoleman at microsoft.com>
Date: Tue, 11 Mar 2025 10:37:51 -0600
Subject: [PATCH 06/19] comments

---
 llvm/lib/Analysis/DXILResource.cpp | 9 +++------
 1 file changed, 3 insertions(+), 6 deletions(-)

diff --git a/llvm/lib/Analysis/DXILResource.cpp b/llvm/lib/Analysis/DXILResource.cpp
index 80d4595efdec7..847508fcf4518 100644
--- a/llvm/lib/Analysis/DXILResource.cpp
+++ b/llvm/lib/Analysis/DXILResource.cpp
@@ -847,19 +847,16 @@ void DXILResourceCounterDirectionMap::populate(Module &M,
       int64_t CountLiteral = CountValue->getSExtValue();
 
       ResourceCounterDirection Direction = ResourceCounterDirection::Unknown;
-      if (CountLiteral > 0) {
+      if (CountLiteral > 0)
         Direction = ResourceCounterDirection::Increment;
-      }
-      if (CountLiteral < 0) {
+      if (CountLiteral < 0)
         Direction = ResourceCounterDirection::Decrement;
-      }
 
       // Collect all potential creation points for the handle arg
       Value *HandleArg = CI->getArgOperand(0);
       SmallVector<dxil::ResourceBindingInfo> RBInfos = DBM.findByUse(HandleArg);
-      for (const dxil::ResourceBindingInfo RBInfo : RBInfos) {
+      for (const dxil::ResourceBindingInfo RBInfo : RBInfos)
         CounterDirections.emplace_back(RBInfo, Direction);
-      }
     }
   }
 

>From 92f2a467b8a046fb0a16757ed786ba6541127c2b Mon Sep 17 00:00:00 2001
From: Ashley Coleman <ascoleman at microsoft.com>
Date: Tue, 11 Mar 2025 10:44:41 -0600
Subject: [PATCH 07/19] format

---
 llvm/include/llvm/Analysis/DXILResource.h |  1 -
 llvm/lib/Analysis/DXILResource.cpp        | 22 +++++++++++-----------
 2 files changed, 11 insertions(+), 12 deletions(-)

diff --git a/llvm/include/llvm/Analysis/DXILResource.h b/llvm/include/llvm/Analysis/DXILResource.h
index 749d7739ee2b1..f4ba17f8e396b 100644
--- a/llvm/include/llvm/Analysis/DXILResource.h
+++ b/llvm/include/llvm/Analysis/DXILResource.h
@@ -651,7 +651,6 @@ class DXILResourceCounterDirectionWrapperPass : public ModulePass {
 
 ModulePass *createDXILResourceCounterDirectionWrapperPassPass();
 
-
 } // namespace llvm
 
 #endif // LLVM_ANALYSIS_DXILRESOURCE_H
diff --git a/llvm/lib/Analysis/DXILResource.cpp b/llvm/lib/Analysis/DXILResource.cpp
index 847508fcf4518..7ba277d0c3c0a 100644
--- a/llvm/lib/Analysis/DXILResource.cpp
+++ b/llvm/lib/Analysis/DXILResource.cpp
@@ -829,8 +829,7 @@ static bool isUpdateCounterIntrinsic(Function &F) {
   return F.getIntrinsicID() == Intrinsic::dx_resource_updatecounter;
 }
 
-void DXILResourceCounterDirectionMap::populate(Module &M,
-                                               DXILBindingMap &DBM) {
+void DXILResourceCounterDirectionMap::populate(Module &M, DXILBindingMap &DBM) {
   CounterDirections.clear();
 
   for (Function &F : M.functions()) {
@@ -891,7 +890,8 @@ void DXILResourceCounterDirectionMap::populate(Module &M,
   M.getContext().diagnose(DiagnosticInfoGeneric(Message));
 }
 
-void DXILResourceCounterDirectionWrapperPass::getAnalysisUsage(AnalysisUsage &AU) const {
+void DXILResourceCounterDirectionWrapperPass::getAnalysisUsage(
+    AnalysisUsage &AU) const {
   AU.addRequiredTransitive<DXILResourceBindingWrapperPass>();
   AU.setPreservesAll();
 }
@@ -908,19 +908,18 @@ bool DXILResourceCounterDirectionWrapperPass::runOnModule(Module &M) {
 void DXILResourceCounterDirectionWrapperPass::releaseMemory() { Map.reset(); }
 
 void DXILResourceCounterDirectionWrapperPass::print(raw_ostream &OS,
-                                           const Module *M) const {
+                                                    const Module *M) const {
   if (!Map) {
     OS << "No resource directions have been built!\n";
     return;
   }
-  //Map->print(OS, *DRTM, M->getDataLayout());
+  // Map->print(OS, *DRTM, M->getDataLayout());
 }
 
-
-//#if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP)
-//LLVM_DUMP_METHOD
-//void DXILResourceCounterDirectionWrapperPass::dump() const { print(dbgs(), nullptr); }
-//#endif
+// #if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP)
+// LLVM_DUMP_METHOD
+// void DXILResourceCounterDirectionWrapperPass::dump() const { print(dbgs(),
+// nullptr); } #endif
 //===----------------------------------------------------------------------===//
 
 AnalysisKey DXILResourceTypeAnalysis::Key;
@@ -951,7 +950,8 @@ INITIALIZE_PASS(DXILResourceCounterDirectionWrapperPass,
 DXILResourceCounterDirectionWrapperPass::
     DXILResourceCounterDirectionWrapperPass()
     : ModulePass(ID) {
-  initializeDXILResourceCounterDirectionWrapperPassPass(*PassRegistry::getPassRegistry());
+  initializeDXILResourceCounterDirectionWrapperPassPass(
+      *PassRegistry::getPassRegistry());
 }
 
 void DXILResourceTypeWrapperPass::anchor() {}

>From 176b8626de121f4270b01d825f85b38592d451ee Mon Sep 17 00:00:00 2001
From: Ashley Coleman <ascoleman at microsoft.com>
Date: Wed, 12 Mar 2025 15:47:43 -0600
Subject: [PATCH 08/19] Add location to error message

---
 llvm/lib/Analysis/DXILResource.cpp            | 47 ++++++++++++++-----
 .../CodeGen/DirectX/resource_counter_error.ll |  2 +-
 .../DirectX/UniqueResourceFromUseTests.cpp    |  8 ++++
 3 files changed, 44 insertions(+), 13 deletions(-)

diff --git a/llvm/lib/Analysis/DXILResource.cpp b/llvm/lib/Analysis/DXILResource.cpp
index 7ba277d0c3c0a..4cb20d9f1ea34 100644
--- a/llvm/lib/Analysis/DXILResource.cpp
+++ b/llvm/lib/Analysis/DXILResource.cpp
@@ -11,6 +11,7 @@
 #include "llvm/ADT/SmallString.h"
 #include "llvm/ADT/StringRef.h"
 #include "llvm/IR/Constants.h"
+#include "llvm/IR/DebugLoc.h"
 #include "llvm/IR/DerivedTypes.h"
 #include "llvm/IR/DiagnosticInfo.h"
 #include "llvm/IR/Instructions.h"
@@ -21,6 +22,7 @@
 #include "llvm/InitializePasses.h"
 #include "llvm/Support/FormatVariadic.h"
 #include <algorithm>
+#include <iterator>
 
 #define DEBUG_TYPE "dxil-resource"
 
@@ -830,7 +832,8 @@ static bool isUpdateCounterIntrinsic(Function &F) {
 }
 
 void DXILResourceCounterDirectionMap::populate(Module &M, DXILBindingMap &DBM) {
-  CounterDirections.clear();
+  std::vector<std::tuple<dxil::ResourceBindingInfo, ResourceCounterDirection, const Function*, const CallInst*>>
+      DiagCounterDirs;
 
   for (Function &F : M.functions()) {
     if (!isUpdateCounterIntrinsic(F))
@@ -855,7 +858,7 @@ void DXILResourceCounterDirectionMap::populate(Module &M, DXILBindingMap &DBM) {
       Value *HandleArg = CI->getArgOperand(0);
       SmallVector<dxil::ResourceBindingInfo> RBInfos = DBM.findByUse(HandleArg);
       for (const dxil::ResourceBindingInfo RBInfo : RBInfos)
-        CounterDirections.emplace_back(RBInfo, Direction);
+        DiagCounterDirs.emplace_back(RBInfo, Direction, &F, CI);
     }
   }
 
@@ -863,31 +866,51 @@ void DXILResourceCounterDirectionMap::populate(Module &M, DXILBindingMap &DBM) {
   // overhead and increased complexity to keep an entry explicitly marked
   // unknown
   const auto RemoveEnd = std::remove_if(
-      CounterDirections.begin(), CounterDirections.end(), [](const auto &Item) {
-        return Item.second == ResourceCounterDirection::Unknown;
+      DiagCounterDirs.begin(), DiagCounterDirs.end(), [](const auto &Item) {
+        return std::get<ResourceCounterDirection>(Item) == ResourceCounterDirection::Unknown;
       });
 
-  // Order for fast lookup
-  std::sort(CounterDirections.begin(), RemoveEnd);
+  // Sort by the Binding and Direction for fast lookup
+  std::sort(DiagCounterDirs.begin(), RemoveEnd, [](const auto &LHS, const auto &RHS) {
+    const auto L = std::pair{std::get<dxil::ResourceBindingInfo>(LHS), std::get<ResourceCounterDirection>(LHS)};
+    const auto R = std::pair{std::get<dxil::ResourceBindingInfo>(RHS), std::get<ResourceCounterDirection>(RHS)};
+    return L < R;
+  });
 
   // Remove the duplicate entries. Since direction is considered for equality
   // a unique resource with more than one direction will not be deduped.
-  const auto UniqueEnd = std::unique(CounterDirections.begin(), RemoveEnd);
+  const auto UniqueEnd = std::unique(DiagCounterDirs.begin(), RemoveEnd, [](const auto &LHS, const auto &RHS) {
+    const auto L = std::pair{std::get<dxil::ResourceBindingInfo>(LHS), std::get<ResourceCounterDirection>(LHS)};
+    const auto R = std::pair{std::get<dxil::ResourceBindingInfo>(RHS), std::get<ResourceCounterDirection>(RHS)};
+    return L == R;
+  });
 
   // Actually erase the items invalidated by remove_if + unique
-  CounterDirections.erase(UniqueEnd, CounterDirections.end());
+  DiagCounterDirs.erase(UniqueEnd, DiagCounterDirs.end());
 
   // If any duplicate entries still exist at this point then it must be a
   // resource that was both incremented and decremented which is not allowed.
   const auto DuplicateEntry = std::adjacent_find(
-      CounterDirections.begin(), CounterDirections.end(),
-      [](const auto &LHS, const auto &RHS) { return LHS.first == RHS.first; });
-  if (DuplicateEntry == CounterDirections.end())
+      DiagCounterDirs.begin(), DiagCounterDirs.end(),
+      [](const auto &LHS, const auto &RHS) {
+      return std::get<dxil::ResourceBindingInfo>(LHS) == std::get<dxil::ResourceBindingInfo>(RHS);
+  });
+
+  // Copy the results into the final vec
+  CounterDirections.clear();
+  CounterDirections.reserve(DiagCounterDirs.size());
+  std::transform(DiagCounterDirs.begin(), DiagCounterDirs.end(), std::back_inserter(CounterDirections), [](const auto &Item){
+    return std::pair{std::get<dxil::ResourceBindingInfo>(Item), std::get<ResourceCounterDirection>(Item)};
+  });
+
+  if (DuplicateEntry == DiagCounterDirs.end())
     return;
 
+  const Function* F = std::get<const Function*>(*DuplicateEntry);
+  const CallInst* CI = std::get<const CallInst*>(*DuplicateEntry);
   StringRef Message = "RWStructuredBuffers may increment or decrement their "
                       "counters, but not both.";
-  M.getContext().diagnose(DiagnosticInfoGeneric(Message));
+  M.getContext().diagnose(DiagnosticInfoGenericWithLoc(Message, *F, CI->getDebugLoc()));
 }
 
 void DXILResourceCounterDirectionWrapperPass::getAnalysisUsage(
diff --git a/llvm/test/CodeGen/DirectX/resource_counter_error.ll b/llvm/test/CodeGen/DirectX/resource_counter_error.ll
index 48ce32031ef00..bea8dcac572e5 100644
--- a/llvm/test/CodeGen/DirectX/resource_counter_error.ll
+++ b/llvm/test/CodeGen/DirectX/resource_counter_error.ll
@@ -1,5 +1,5 @@
 ; RUN: not opt -S -passes='dxil-op-lower' -mtriple=dxil-pc-shadermodel6.3-library %s 2>&1 | FileCheck %s
-; CHECK:  RWStructuredBuffers may increment or decrement their counters, but not both.
+; CHECK: <unknown>:0:0: RWStructuredBuffers may increment or decrement their counters, but not both.
 
 define void @inc_and_dec() {
 entry:
diff --git a/llvm/unittests/Target/DirectX/UniqueResourceFromUseTests.cpp b/llvm/unittests/Target/DirectX/UniqueResourceFromUseTests.cpp
index b653bc3127ffc..76de33e061a3d 100644
--- a/llvm/unittests/Target/DirectX/UniqueResourceFromUseTests.cpp
+++ b/llvm/unittests/Target/DirectX/UniqueResourceFromUseTests.cpp
@@ -281,6 +281,8 @@ declare target("dx.RawBuffer", float, 1, 0) @ind.func(target("dx.RawBuffer", flo
   }
 }
 
+// Test that several calls to decrement on the same resource don't raise a
+// Diagnositic and resolves to a single decrement entry
 TEST_F(UniqueResourceFromUseTest, TestResourceCounterDecrement) {
   StringRef Assembly = R"(
 define void @main() {
@@ -322,6 +324,8 @@ declare void @a.func(target("dx.RawBuffer", float, 1, 0) %handle)
   }
 }
 
+// Test that several calls to increment on the same resource don't raise a
+// Diagnositic and resolves to a single increment entry
 TEST_F(UniqueResourceFromUseTest, TestResourceCounterIncrement) {
   StringRef Assembly = R"(
 define void @main() {
@@ -363,6 +367,8 @@ declare void @a.func(target("dx.RawBuffer", float, 1, 0) %handle)
   }
 }
 
+// Test that looking up a resource that doesn't have the counter updated
+// resoves to unknown
 TEST_F(UniqueResourceFromUseTest, TestResourceCounterUnknown) {
   StringRef Assembly = R"(
 define void @main() {
@@ -401,6 +407,8 @@ declare void @a.func(target("dx.RawBuffer", float, 1, 0) %handle)
   }
 }
 
+// Test that multiple different resources with unique incs/decs don't
+// raise a Diagnostic and can be individually checked for direction
 TEST_F(UniqueResourceFromUseTest, TestResourceCounterMultiple) {
   StringRef Assembly = R"(
 define void @main() {

>From 5d1648ae259443c038e9a0c675a8f42db3452eac Mon Sep 17 00:00:00 2001
From: Ashley Coleman <ascoleman at microsoft.com>
Date: Wed, 12 Mar 2025 15:48:19 -0600
Subject: [PATCH 09/19] format

---
 llvm/lib/Analysis/DXILResource.cpp | 58 ++++++++++++++++++------------
 1 file changed, 35 insertions(+), 23 deletions(-)

diff --git a/llvm/lib/Analysis/DXILResource.cpp b/llvm/lib/Analysis/DXILResource.cpp
index 4cb20d9f1ea34..a06b77b1ac8be 100644
--- a/llvm/lib/Analysis/DXILResource.cpp
+++ b/llvm/lib/Analysis/DXILResource.cpp
@@ -832,7 +832,8 @@ static bool isUpdateCounterIntrinsic(Function &F) {
 }
 
 void DXILResourceCounterDirectionMap::populate(Module &M, DXILBindingMap &DBM) {
-  std::vector<std::tuple<dxil::ResourceBindingInfo, ResourceCounterDirection, const Function*, const CallInst*>>
+  std::vector<std::tuple<dxil::ResourceBindingInfo, ResourceCounterDirection,
+                         const Function *, const CallInst *>>
       DiagCounterDirs;
 
   for (Function &F : M.functions()) {
@@ -867,50 +868,61 @@ void DXILResourceCounterDirectionMap::populate(Module &M, DXILBindingMap &DBM) {
   // unknown
   const auto RemoveEnd = std::remove_if(
       DiagCounterDirs.begin(), DiagCounterDirs.end(), [](const auto &Item) {
-        return std::get<ResourceCounterDirection>(Item) == ResourceCounterDirection::Unknown;
+        return std::get<ResourceCounterDirection>(Item) ==
+               ResourceCounterDirection::Unknown;
       });
 
   // Sort by the Binding and Direction for fast lookup
-  std::sort(DiagCounterDirs.begin(), RemoveEnd, [](const auto &LHS, const auto &RHS) {
-    const auto L = std::pair{std::get<dxil::ResourceBindingInfo>(LHS), std::get<ResourceCounterDirection>(LHS)};
-    const auto R = std::pair{std::get<dxil::ResourceBindingInfo>(RHS), std::get<ResourceCounterDirection>(RHS)};
-    return L < R;
-  });
+  std::sort(DiagCounterDirs.begin(), RemoveEnd,
+            [](const auto &LHS, const auto &RHS) {
+              const auto L = std::pair{std::get<dxil::ResourceBindingInfo>(LHS),
+                                       std::get<ResourceCounterDirection>(LHS)};
+              const auto R = std::pair{std::get<dxil::ResourceBindingInfo>(RHS),
+                                       std::get<ResourceCounterDirection>(RHS)};
+              return L < R;
+            });
 
   // Remove the duplicate entries. Since direction is considered for equality
   // a unique resource with more than one direction will not be deduped.
-  const auto UniqueEnd = std::unique(DiagCounterDirs.begin(), RemoveEnd, [](const auto &LHS, const auto &RHS) {
-    const auto L = std::pair{std::get<dxil::ResourceBindingInfo>(LHS), std::get<ResourceCounterDirection>(LHS)};
-    const auto R = std::pair{std::get<dxil::ResourceBindingInfo>(RHS), std::get<ResourceCounterDirection>(RHS)};
-    return L == R;
-  });
+  const auto UniqueEnd = std::unique(
+      DiagCounterDirs.begin(), RemoveEnd, [](const auto &LHS, const auto &RHS) {
+        const auto L = std::pair{std::get<dxil::ResourceBindingInfo>(LHS),
+                                 std::get<ResourceCounterDirection>(LHS)};
+        const auto R = std::pair{std::get<dxil::ResourceBindingInfo>(RHS),
+                                 std::get<ResourceCounterDirection>(RHS)};
+        return L == R;
+      });
 
   // Actually erase the items invalidated by remove_if + unique
   DiagCounterDirs.erase(UniqueEnd, DiagCounterDirs.end());
 
   // If any duplicate entries still exist at this point then it must be a
   // resource that was both incremented and decremented which is not allowed.
-  const auto DuplicateEntry = std::adjacent_find(
-      DiagCounterDirs.begin(), DiagCounterDirs.end(),
-      [](const auto &LHS, const auto &RHS) {
-      return std::get<dxil::ResourceBindingInfo>(LHS) == std::get<dxil::ResourceBindingInfo>(RHS);
-  });
+  const auto DuplicateEntry =
+      std::adjacent_find(DiagCounterDirs.begin(), DiagCounterDirs.end(),
+                         [](const auto &LHS, const auto &RHS) {
+                           return std::get<dxil::ResourceBindingInfo>(LHS) ==
+                                  std::get<dxil::ResourceBindingInfo>(RHS);
+                         });
 
   // Copy the results into the final vec
   CounterDirections.clear();
   CounterDirections.reserve(DiagCounterDirs.size());
-  std::transform(DiagCounterDirs.begin(), DiagCounterDirs.end(), std::back_inserter(CounterDirections), [](const auto &Item){
-    return std::pair{std::get<dxil::ResourceBindingInfo>(Item), std::get<ResourceCounterDirection>(Item)};
-  });
+  std::transform(DiagCounterDirs.begin(), DiagCounterDirs.end(),
+                 std::back_inserter(CounterDirections), [](const auto &Item) {
+                   return std::pair{std::get<dxil::ResourceBindingInfo>(Item),
+                                    std::get<ResourceCounterDirection>(Item)};
+                 });
 
   if (DuplicateEntry == DiagCounterDirs.end())
     return;
 
-  const Function* F = std::get<const Function*>(*DuplicateEntry);
-  const CallInst* CI = std::get<const CallInst*>(*DuplicateEntry);
+  const Function *F = std::get<const Function *>(*DuplicateEntry);
+  const CallInst *CI = std::get<const CallInst *>(*DuplicateEntry);
   StringRef Message = "RWStructuredBuffers may increment or decrement their "
                       "counters, but not both.";
-  M.getContext().diagnose(DiagnosticInfoGenericWithLoc(Message, *F, CI->getDebugLoc()));
+  M.getContext().diagnose(
+      DiagnosticInfoGenericWithLoc(Message, *F, CI->getDebugLoc()));
 }
 
 void DXILResourceCounterDirectionWrapperPass::getAnalysisUsage(

>From 67c76a0f338a3d774fbb3ac02ccdcacf3445690a Mon Sep 17 00:00:00 2001
From: Ashley Coleman <ascoleman at microsoft.com>
Date: Wed, 12 Mar 2025 17:30:22 -0600
Subject: [PATCH 10/19] Mark resources with invalid use in map

---
 llvm/include/llvm/Analysis/DXILResource.h |  1 +
 llvm/lib/Analysis/DXILResource.cpp        | 43 ++++++++++++++---------
 2 files changed, 28 insertions(+), 16 deletions(-)

diff --git a/llvm/include/llvm/Analysis/DXILResource.h b/llvm/include/llvm/Analysis/DXILResource.h
index f4ba17f8e396b..6552357b156b4 100644
--- a/llvm/include/llvm/Analysis/DXILResource.h
+++ b/llvm/include/llvm/Analysis/DXILResource.h
@@ -581,6 +581,7 @@ enum ResourceCounterDirection {
   Increment,
   Decrement,
   Unknown,
+  MyInvalid,
 };
 
 class DXILResourceCounterDirectionMap {
diff --git a/llvm/lib/Analysis/DXILResource.cpp b/llvm/lib/Analysis/DXILResource.cpp
index a06b77b1ac8be..1080d460fd1d9 100644
--- a/llvm/lib/Analysis/DXILResource.cpp
+++ b/llvm/lib/Analysis/DXILResource.cpp
@@ -898,12 +898,33 @@ void DXILResourceCounterDirectionMap::populate(Module &M, DXILBindingMap &DBM) {
 
   // If any duplicate entries still exist at this point then it must be a
   // resource that was both incremented and decremented which is not allowed.
-  const auto DuplicateEntry =
-      std::adjacent_find(DiagCounterDirs.begin(), DiagCounterDirs.end(),
-                         [](const auto &LHS, const auto &RHS) {
-                           return std::get<dxil::ResourceBindingInfo>(LHS) ==
-                                  std::get<dxil::ResourceBindingInfo>(RHS);
-                         });
+  // Mark all those entries as invalid.
+  {
+  auto DupFirst = DiagCounterDirs.begin();
+  auto DupNext = DupFirst + 1;
+  auto DupLast = DiagCounterDirs.end();
+  for (; DupFirst < DupLast && DupNext < DupLast; ++DupFirst, ++DupNext) {
+    if (std::get<dxil::ResourceBindingInfo>(*DupFirst) == std::get<dxil::ResourceBindingInfo>(*DupNext)) {
+      std::get<ResourceCounterDirection>(*DupFirst) = ResourceCounterDirection::MyInvalid;
+      std::get<ResourceCounterDirection>(*DupNext) = ResourceCounterDirection::MyInvalid;
+    }
+  }
+  }
+
+  // Raise an error for every invalid entry
+  for (const auto Entry : DiagCounterDirs) {
+    ResourceCounterDirection Dir = std::get<ResourceCounterDirection>(Entry);
+    const Function *F = std::get<const Function *>(Entry);
+    const CallInst *CI = std::get<const CallInst *>(Entry);
+
+    if (Dir != ResourceCounterDirection::MyInvalid)
+      continue;
+
+    StringRef Message = "RWStructuredBuffers may increment or decrement their "
+                        "counters, but not both.";
+    M.getContext().diagnose(
+        DiagnosticInfoGenericWithLoc(Message, *F, CI->getDebugLoc()));
+  }
 
   // Copy the results into the final vec
   CounterDirections.clear();
@@ -913,16 +934,6 @@ void DXILResourceCounterDirectionMap::populate(Module &M, DXILBindingMap &DBM) {
                    return std::pair{std::get<dxil::ResourceBindingInfo>(Item),
                                     std::get<ResourceCounterDirection>(Item)};
                  });
-
-  if (DuplicateEntry == DiagCounterDirs.end())
-    return;
-
-  const Function *F = std::get<const Function *>(*DuplicateEntry);
-  const CallInst *CI = std::get<const CallInst *>(*DuplicateEntry);
-  StringRef Message = "RWStructuredBuffers may increment or decrement their "
-                      "counters, but not both.";
-  M.getContext().diagnose(
-      DiagnosticInfoGenericWithLoc(Message, *F, CI->getDebugLoc()));
 }
 
 void DXILResourceCounterDirectionWrapperPass::getAnalysisUsage(

>From ef30e9a4a1b42bdc1e128d126b75b4a104ff4f3f Mon Sep 17 00:00:00 2001
From: Ashley Coleman <ascoleman at microsoft.com>
Date: Wed, 12 Mar 2025 17:30:41 -0600
Subject: [PATCH 11/19] format

---
 llvm/lib/Analysis/DXILResource.cpp | 19 +++++++++++--------
 1 file changed, 11 insertions(+), 8 deletions(-)

diff --git a/llvm/lib/Analysis/DXILResource.cpp b/llvm/lib/Analysis/DXILResource.cpp
index 1080d460fd1d9..0cbfb45083abf 100644
--- a/llvm/lib/Analysis/DXILResource.cpp
+++ b/llvm/lib/Analysis/DXILResource.cpp
@@ -900,16 +900,19 @@ void DXILResourceCounterDirectionMap::populate(Module &M, DXILBindingMap &DBM) {
   // resource that was both incremented and decremented which is not allowed.
   // Mark all those entries as invalid.
   {
-  auto DupFirst = DiagCounterDirs.begin();
-  auto DupNext = DupFirst + 1;
-  auto DupLast = DiagCounterDirs.end();
-  for (; DupFirst < DupLast && DupNext < DupLast; ++DupFirst, ++DupNext) {
-    if (std::get<dxil::ResourceBindingInfo>(*DupFirst) == std::get<dxil::ResourceBindingInfo>(*DupNext)) {
-      std::get<ResourceCounterDirection>(*DupFirst) = ResourceCounterDirection::MyInvalid;
-      std::get<ResourceCounterDirection>(*DupNext) = ResourceCounterDirection::MyInvalid;
+    auto DupFirst = DiagCounterDirs.begin();
+    auto DupNext = DupFirst + 1;
+    auto DupLast = DiagCounterDirs.end();
+    for (; DupFirst < DupLast && DupNext < DupLast; ++DupFirst, ++DupNext) {
+      if (std::get<dxil::ResourceBindingInfo>(*DupFirst) ==
+          std::get<dxil::ResourceBindingInfo>(*DupNext)) {
+        std::get<ResourceCounterDirection>(*DupFirst) =
+            ResourceCounterDirection::MyInvalid;
+        std::get<ResourceCounterDirection>(*DupNext) =
+            ResourceCounterDirection::MyInvalid;
+      }
     }
   }
-  }
 
   // Raise an error for every invalid entry
   for (const auto Entry : DiagCounterDirs) {

>From b1a4f4ddba7c82ae9c48ffbe1e65b48dd1231923 Mon Sep 17 00:00:00 2001
From: Ashley Coleman <ascoleman at microsoft.com>
Date: Mon, 17 Mar 2025 15:15:12 -0600
Subject: [PATCH 12/19] Fix enum name

---
 llvm/include/llvm/Analysis/DXILResource.h | 4 ++--
 llvm/lib/Analysis/DXILResource.cpp        | 6 +++---
 2 files changed, 5 insertions(+), 5 deletions(-)

diff --git a/llvm/include/llvm/Analysis/DXILResource.h b/llvm/include/llvm/Analysis/DXILResource.h
index 6552357b156b4..aa7dfffa399b2 100644
--- a/llvm/include/llvm/Analysis/DXILResource.h
+++ b/llvm/include/llvm/Analysis/DXILResource.h
@@ -577,11 +577,11 @@ class DXILResourceBindingWrapperPass : public ModulePass {
 
 ModulePass *createDXILResourceBindingWrapperPassPass();
 
-enum ResourceCounterDirection {
+enum class ResourceCounterDirection {
   Increment,
   Decrement,
   Unknown,
-  MyInvalid,
+  Invalid,
 };
 
 class DXILResourceCounterDirectionMap {
diff --git a/llvm/lib/Analysis/DXILResource.cpp b/llvm/lib/Analysis/DXILResource.cpp
index 0cbfb45083abf..278c219c58f3f 100644
--- a/llvm/lib/Analysis/DXILResource.cpp
+++ b/llvm/lib/Analysis/DXILResource.cpp
@@ -907,9 +907,9 @@ void DXILResourceCounterDirectionMap::populate(Module &M, DXILBindingMap &DBM) {
       if (std::get<dxil::ResourceBindingInfo>(*DupFirst) ==
           std::get<dxil::ResourceBindingInfo>(*DupNext)) {
         std::get<ResourceCounterDirection>(*DupFirst) =
-            ResourceCounterDirection::MyInvalid;
+            ResourceCounterDirection::Invalid;
         std::get<ResourceCounterDirection>(*DupNext) =
-            ResourceCounterDirection::MyInvalid;
+            ResourceCounterDirection::Invalid;
       }
     }
   }
@@ -920,7 +920,7 @@ void DXILResourceCounterDirectionMap::populate(Module &M, DXILBindingMap &DBM) {
     const Function *F = std::get<const Function *>(Entry);
     const CallInst *CI = std::get<const CallInst *>(Entry);
 
-    if (Dir != ResourceCounterDirection::MyInvalid)
+    if (Dir != ResourceCounterDirection::Invalid)
       continue;
 
     StringRef Message = "RWStructuredBuffers may increment or decrement their "

>From 1f011b70e30e3121b133e22cfaf9e0dfcc807d69 Mon Sep 17 00:00:00 2001
From: Ashley Coleman <ascoleman at microsoft.com>
Date: Mon, 24 Mar 2025 10:10:08 -0600
Subject: [PATCH 13/19] address comments

---
 .../DirectX/UniqueResourceFromUseTests.cpp    | 54 ++++++++-----------
 1 file changed, 21 insertions(+), 33 deletions(-)

diff --git a/llvm/unittests/Target/DirectX/UniqueResourceFromUseTests.cpp b/llvm/unittests/Target/DirectX/UniqueResourceFromUseTests.cpp
index 76de33e061a3d..e2f913816bcc7 100644
--- a/llvm/unittests/Target/DirectX/UniqueResourceFromUseTests.cpp
+++ b/llvm/unittests/Target/DirectX/UniqueResourceFromUseTests.cpp
@@ -48,13 +48,12 @@ TEST_F(UniqueResourceFromUseTest, TestTrivialUse) {
   StringRef Assembly = R"(
 define void @main() {
 entry:
-  %handle = call target("dx.RawBuffer", float, 1, 0) @llvm.dx.resource.handlefrombinding.tdx.RawBuffer_f32_1_0t(i32 1, i32 2, i32 3, i32 4, i1 false)
+  %handle = call target("dx.RawBuffer", float, 1, 0) @llvm.dx.resource.handlefrombinding(i32 1, i32 2, i32 3, i32 4, i1 false)
   call void @a.func(target("dx.RawBuffer", float, 1, 0) %handle)
   call void @a.func(target("dx.RawBuffer", float, 1, 0) %handle)
   ret void
 }
 
-declare target("dx.RawBuffer", float, 1, 0) @llvm.dx.resource.handlefrombinding.tdx.RawBuffer_f32_1_0t(i32, i32, i32, i32, i1)
 declare void @a.func(target("dx.RawBuffer", float, 1, 0) %handle)
   )";
 
@@ -95,7 +94,7 @@ declare void @a.func(target("dx.RawBuffer", float, 1, 0) %handle)
 TEST_F(UniqueResourceFromUseTest, TestIndirectUse) {
   StringRef Assembly = R"(
 define void @foo() {
-  %handle = call target("dx.RawBuffer", float, 1, 0) @llvm.dx.resource.handlefrombinding.tdx.RawBuffer_f32_1_0t(i32 1, i32 2, i32 3, i32 4, i1 false)
+  %handle = call target("dx.RawBuffer", float, 1, 0) @llvm.dx.resource.handlefrombinding(i32 1, i32 2, i32 3, i32 4, i1 false)
   %handle2 = call target("dx.RawBuffer", float, 1, 0) @ind.func(target("dx.RawBuffer", float, 1, 0) %handle)
   %handle3 = call target("dx.RawBuffer", float, 1, 0) @ind.func(target("dx.RawBuffer", float, 1, 0) %handle2)
   %handle4 = call target("dx.RawBuffer", float, 1, 0) @ind.func(target("dx.RawBuffer", float, 1, 0) %handle3)
@@ -103,7 +102,6 @@ define void @foo() {
   ret void
 }
 
-declare target("dx.RawBuffer", float, 1, 0) @llvm.dx.resource.handlefrombinding.tdx.RawBuffer_f32_1_0t(i32, i32, i32, i32, i1)
 declare void @a.func(target("dx.RawBuffer", float, 1, 0) %handle)
 declare target("dx.RawBuffer", float, 1, 0) @ind.func(target("dx.RawBuffer", float, 1, 0) %handle)
   )";
@@ -145,10 +143,10 @@ declare target("dx.RawBuffer", float, 1, 0) @ind.func(target("dx.RawBuffer", flo
 TEST_F(UniqueResourceFromUseTest, TestAmbigousIndirectUse) {
   StringRef Assembly = R"(
 define void @foo() {
-  %foo = call target("dx.RawBuffer", float, 1, 0) @llvm.dx.resource.handlefrombinding.tdx.RawBuffer_f32_1_0t(i32 1, i32 1, i32 1, i32 1, i1 false)
-  %bar = call target("dx.RawBuffer", float, 1, 0) @llvm.dx.resource.handlefrombinding.tdx.RawBuffer_f32_1_0t(i32 2, i32 2, i32 2, i32 2, i1 false)
-  %baz = call target("dx.RawBuffer", float, 1, 0) @llvm.dx.resource.handlefrombinding.tdx.RawBuffer_f32_1_0t(i32 3, i32 3, i32 3, i32 3, i1 false)
-  %bat = call target("dx.RawBuffer", float, 1, 0) @llvm.dx.resource.handlefrombinding.tdx.RawBuffer_f32_1_0t(i32 4, i32 4, i32 4, i32 4, i1 false)
+  %foo = call target("dx.RawBuffer", float, 1, 0) @llvm.dx.resource.handlefrombinding(i32 1, i32 1, i32 1, i32 1, i1 false)
+  %bar = call target("dx.RawBuffer", float, 1, 0) @llvm.dx.resource.handlefrombinding(i32 2, i32 2, i32 2, i32 2, i1 false)
+  %baz = call target("dx.RawBuffer", float, 1, 0) @llvm.dx.resource.handlefrombinding(i32 3, i32 3, i32 3, i32 3, i1 false)
+  %bat = call target("dx.RawBuffer", float, 1, 0) @llvm.dx.resource.handlefrombinding(i32 4, i32 4, i32 4, i32 4, i1 false)
   %a = call target("dx.RawBuffer", float, 1, 0) @ind.func(target("dx.RawBuffer", float, 1, 0) %foo, target("dx.RawBuffer", float, 1, 0) %bar)
   %b = call target("dx.RawBuffer", float, 1, 0) @ind.func(target("dx.RawBuffer", float, 1, 0) %baz, target("dx.RawBuffer", float, 1, 0) %bat)
   %handle = call target("dx.RawBuffer", float, 1, 0) @ind.func(target("dx.RawBuffer", float, 1, 0) %a, target("dx.RawBuffer", float, 1, 0) %b)
@@ -156,7 +154,6 @@ define void @foo() {
   ret void
 }
 
-declare target("dx.RawBuffer", float, 1, 0) @llvm.dx.resource.handlefrombinding.tdx.RawBuffer_f32_1_0t(i32, i32, i32, i32, i1)
 declare void @a.func(target("dx.RawBuffer", float, 1, 0) %handle)
 declare target("dx.RawBuffer", float, 1, 0) @ind.func(target("dx.RawBuffer", float, 1, 0) %x, target("dx.RawBuffer", float, 1, 0) %y)
   )";
@@ -217,8 +214,8 @@ TEST_F(UniqueResourceFromUseTest, TestConditionalUse) {
   StringRef Assembly = R"(
 define void @foo(i32 %n) {
 entry:
-  %x = call target("dx.RawBuffer", float, 1, 0) @llvm.dx.resource.handlefrombinding.tdx.RawBuffer_f32_1_0t(i32 1, i32 1, i32 1, i32 1, i1 false)
-  %y = call target("dx.RawBuffer", float, 1, 0) @llvm.dx.resource.handlefrombinding.tdx.RawBuffer_f32_1_0t(i32 4, i32 4, i32 4, i32 4, i1 false)
+  %x = call target("dx.RawBuffer", float, 1, 0) @llvm.dx.resource.handlefrombinding(i32 1, i32 1, i32 1, i32 1, i1 false)
+  %y = call target("dx.RawBuffer", float, 1, 0) @llvm.dx.resource.handlefrombinding(i32 4, i32 4, i32 4, i32 4, i1 false)
   %cond = icmp eq i32 %n, 0
   br i1 %cond, label %bb.true, label %bb.false
 
@@ -236,7 +233,6 @@ bb.exit:
   ret void
 }
 
-declare target("dx.RawBuffer", float, 1, 0) @llvm.dx.resource.handlefrombinding.tdx.RawBuffer_f32_1_0t(i32, i32, i32, i32, i1)
 declare void @a.func(target("dx.RawBuffer", float, 1, 0) %handle)
 declare target("dx.RawBuffer", float, 1, 0) @ind.func(target("dx.RawBuffer", float, 1, 0) %x)
   )";
@@ -287,16 +283,14 @@ TEST_F(UniqueResourceFromUseTest, TestResourceCounterDecrement) {
   StringRef Assembly = R"(
 define void @main() {
 entry:
-  %handle = call target("dx.RawBuffer", float, 1, 0) @llvm.dx.resource.handlefrombinding.tdx.RawBuffer_f32_1_0t(i32 1, i32 2, i32 3, i32 4, i1 false)
-  call i32 @llvm.dx.resource.updatecounter.tdx.RawBuffer_f32_1_0t(target("dx.RawBuffer", float, 1, 0) %handle, i8 -1)
-  call i32 @llvm.dx.resource.updatecounter.tdx.RawBuffer_f32_1_0t(target("dx.RawBuffer", float, 1, 0) %handle, i8 -1)
-  call i32 @llvm.dx.resource.updatecounter.tdx.RawBuffer_f32_1_0t(target("dx.RawBuffer", float, 1, 0) %handle, i8 -1)
+  %handle = call target("dx.RawBuffer", float, 1, 0) @llvm.dx.resource.handlefrombinding(i32 1, i32 2, i32 3, i32 4, i1 false)
+  call i32 @llvm.dx.resource.updatecounter(target("dx.RawBuffer", float, 1, 0) %handle, i8 -1)
+  call i32 @llvm.dx.resource.updatecounter(target("dx.RawBuffer", float, 1, 0) %handle, i8 -1)
+  call i32 @llvm.dx.resource.updatecounter(target("dx.RawBuffer", float, 1, 0) %handle, i8 -1)
   call void @a.func(target("dx.RawBuffer", float, 1, 0) %handle)
   ret void
 }
 
-declare target("dx.RawBuffer", float, 1, 0) @llvm.dx.resource.handlefrombinding.tdx.RawBuffer_f32_1_0t(i32, i32, i32, i32, i1)
-declare i32 @llvm.dx.resource.updatecounter.tdx.RawBuffer_f32_1_0t(target("dx.RawBuffer", float, 1, 0), i8)
 declare void @a.func(target("dx.RawBuffer", float, 1, 0) %handle)
   )";
 
@@ -330,16 +324,14 @@ TEST_F(UniqueResourceFromUseTest, TestResourceCounterIncrement) {
   StringRef Assembly = R"(
 define void @main() {
 entry:
-  %handle = call target("dx.RawBuffer", float, 1, 0) @llvm.dx.resource.handlefrombinding.tdx.RawBuffer_f32_1_0t(i32 1, i32 2, i32 3, i32 4, i1 false)
-  call i32 @llvm.dx.resource.updatecounter.tdx.RawBuffer_f32_1_0t(target("dx.RawBuffer", float, 1, 0) %handle, i8 1)
-  call i32 @llvm.dx.resource.updatecounter.tdx.RawBuffer_f32_1_0t(target("dx.RawBuffer", float, 1, 0) %handle, i8 1)
-  call i32 @llvm.dx.resource.updatecounter.tdx.RawBuffer_f32_1_0t(target("dx.RawBuffer", float, 1, 0) %handle, i8 1)
+  %handle = call target("dx.RawBuffer", float, 1, 0) @llvm.dx.resource.handlefrombinding(i32 1, i32 2, i32 3, i32 4, i1 false)
+  call i32 @llvm.dx.resource.updatecounter(target("dx.RawBuffer", float, 1, 0) %handle, i8 1)
+  call i32 @llvm.dx.resource.updatecounter(target("dx.RawBuffer", float, 1, 0) %handle, i8 1)
+  call i32 @llvm.dx.resource.updatecounter(target("dx.RawBuffer", float, 1, 0) %handle, i8 1)
   call void @a.func(target("dx.RawBuffer", float, 1, 0) %handle)
   ret void
 }
 
-declare target("dx.RawBuffer", float, 1, 0) @llvm.dx.resource.handlefrombinding.tdx.RawBuffer_f32_1_0t(i32, i32, i32, i32, i1)
-declare i32 @llvm.dx.resource.updatecounter.tdx.RawBuffer_f32_1_0t(target("dx.RawBuffer", float, 1, 0), i8)
 declare void @a.func(target("dx.RawBuffer", float, 1, 0) %handle)
   )";
 
@@ -373,13 +365,11 @@ TEST_F(UniqueResourceFromUseTest, TestResourceCounterUnknown) {
   StringRef Assembly = R"(
 define void @main() {
 entry:
-  %handle = call target("dx.RawBuffer", float, 1, 0) @llvm.dx.resource.handlefrombinding.tdx.RawBuffer_f32_1_0t(i32 1, i32 2, i32 3, i32 4, i1 false)
+  %handle = call target("dx.RawBuffer", float, 1, 0) @llvm.dx.resource.handlefrombinding(i32 1, i32 2, i32 3, i32 4, i1 false)
   call void @a.func(target("dx.RawBuffer", float, 1, 0) %handle)
   ret void
 }
 
-declare target("dx.RawBuffer", float, 1, 0) @llvm.dx.resource.handlefrombinding.tdx.RawBuffer_f32_1_0t(i32, i32, i32, i32, i1)
-declare i32 @llvm.dx.resource.updatecounter.tdx.RawBuffer_f32_1_0t(target("dx.RawBuffer", float, 1, 0), i8)
 declare void @a.func(target("dx.RawBuffer", float, 1, 0) %handle)
   )";
 
@@ -413,17 +403,15 @@ TEST_F(UniqueResourceFromUseTest, TestResourceCounterMultiple) {
   StringRef Assembly = R"(
 define void @main() {
 entry:
-  %handle1 = call target("dx.RawBuffer", float, 1, 0) @llvm.dx.resource.handlefrombinding.tdx.RawBuffer_f32_1_0t(i32 1, i32 2, i32 3, i32 4, i1 false)
-  %handle2 = call target("dx.RawBuffer", float, 1, 0) @llvm.dx.resource.handlefrombinding.tdx.RawBuffer_f32_1_0t(i32 4, i32 3, i32 2, i32 1, i1 false)
-  call i32 @llvm.dx.resource.updatecounter.tdx.RawBuffer_f32_1_0t(target("dx.RawBuffer", float, 1, 0) %handle1, i8 -1)
-  call i32 @llvm.dx.resource.updatecounter.tdx.RawBuffer_f32_1_0t(target("dx.RawBuffer", float, 1, 0) %handle2, i8 1)
+  %handle1 = call target("dx.RawBuffer", float, 1, 0) @llvm.dx.resource.handlefrombinding(i32 1, i32 2, i32 3, i32 4, i1 false)
+  %handle2 = call target("dx.RawBuffer", float, 1, 0) @llvm.dx.resource.handlefrombinding(i32 4, i32 3, i32 2, i32 1, i1 false)
+  call i32 @llvm.dx.resource.updatecounter(target("dx.RawBuffer", float, 1, 0) %handle1, i8 -1)
+  call i32 @llvm.dx.resource.updatecounter(target("dx.RawBuffer", float, 1, 0) %handle2, i8 1)
   call void @a.func(target("dx.RawBuffer", float, 1, 0) %handle1)
   call void @b.func(target("dx.RawBuffer", float, 1, 0) %handle2)
   ret void
 }
 
-declare target("dx.RawBuffer", float, 1, 0) @llvm.dx.resource.handlefrombinding.tdx.RawBuffer_f32_1_0t(i32, i32, i32, i32, i1)
-declare i32 @llvm.dx.resource.updatecounter.tdx.RawBuffer_f32_1_0t(target("dx.RawBuffer", float, 1, 0), i8)
 declare void @a.func(target("dx.RawBuffer", float, 1, 0) %handle)
 declare void @b.func(target("dx.RawBuffer", float, 1, 0) %handle)
   )";

>From f7b82c03264480bec8954be625d571b0a8f80c15 Mon Sep 17 00:00:00 2001
From: Ashley Coleman <ascoleman at microsoft.com>
Date: Mon, 24 Mar 2025 10:50:14 -0600
Subject: [PATCH 14/19] address comments

---
 .../DirectX/UniqueResourceFromUseTests.cpp    | 46 ++++++-------------
 1 file changed, 15 insertions(+), 31 deletions(-)

diff --git a/llvm/unittests/Target/DirectX/UniqueResourceFromUseTests.cpp b/llvm/unittests/Target/DirectX/UniqueResourceFromUseTests.cpp
index e2f913816bcc7..c065648c852a1 100644
--- a/llvm/unittests/Target/DirectX/UniqueResourceFromUseTests.cpp
+++ b/llvm/unittests/Target/DirectX/UniqueResourceFromUseTests.cpp
@@ -11,6 +11,7 @@
 #include "llvm/AsmParser/Parser.h"
 #include "llvm/CodeGen/CommandFlags.h"
 #include "llvm/IR/Instructions.h"
+#include "llvm/IR/IntrinsicsDirectX.h"
 #include "llvm/IR/LLVMContext.h"
 #include "llvm/IR/Module.h"
 #include "llvm/IR/Type.h"
@@ -287,11 +288,8 @@ define void @main() {
   call i32 @llvm.dx.resource.updatecounter(target("dx.RawBuffer", float, 1, 0) %handle, i8 -1)
   call i32 @llvm.dx.resource.updatecounter(target("dx.RawBuffer", float, 1, 0) %handle, i8 -1)
   call i32 @llvm.dx.resource.updatecounter(target("dx.RawBuffer", float, 1, 0) %handle, i8 -1)
-  call void @a.func(target("dx.RawBuffer", float, 1, 0) %handle)
   ret void
 }
-
-declare void @a.func(target("dx.RawBuffer", float, 1, 0) %handle)
   )";
 
   LLVMContext Context;
@@ -304,14 +302,13 @@ declare void @a.func(target("dx.RawBuffer", float, 1, 0) %handle)
       MAM->getResult<DXILResourceCounterDirectionAnalysis>(*M);
 
   for (const Function &F : M->functions()) {
-    if (F.getName() != "a.func") {
+    if (F.getIntrinsicID() != Intrinsic::dx_resource_handlefrombinding) {
       continue;
     }
 
     for (const User *U : F.users()) {
       const CallInst *CI = cast<CallInst>(U);
-      const Value *Handle = CI->getArgOperand(0);
-      const auto Bindings = DBM.findByUse(Handle);
+      const auto Bindings = DBM.findByUse(CI);
       ASSERT_EQ(Bindings.size(), 1u);
       ASSERT_EQ(DCDM[Bindings.front()], ResourceCounterDirection::Decrement);
     }
@@ -328,11 +325,8 @@ define void @main() {
   call i32 @llvm.dx.resource.updatecounter(target("dx.RawBuffer", float, 1, 0) %handle, i8 1)
   call i32 @llvm.dx.resource.updatecounter(target("dx.RawBuffer", float, 1, 0) %handle, i8 1)
   call i32 @llvm.dx.resource.updatecounter(target("dx.RawBuffer", float, 1, 0) %handle, i8 1)
-  call void @a.func(target("dx.RawBuffer", float, 1, 0) %handle)
   ret void
 }
-
-declare void @a.func(target("dx.RawBuffer", float, 1, 0) %handle)
   )";
 
   LLVMContext Context;
@@ -345,14 +339,13 @@ declare void @a.func(target("dx.RawBuffer", float, 1, 0) %handle)
       MAM->getResult<DXILResourceCounterDirectionAnalysis>(*M);
 
   for (const Function &F : M->functions()) {
-    if (F.getName() != "a.func") {
+    if (F.getIntrinsicID() != Intrinsic::dx_resource_handlefrombinding) {
       continue;
     }
 
     for (const User *U : F.users()) {
       const CallInst *CI = cast<CallInst>(U);
-      const Value *Handle = CI->getArgOperand(0);
-      const auto Bindings = DBM.findByUse(Handle);
+      const auto Bindings = DBM.findByUse(CI);
       ASSERT_EQ(Bindings.size(), 1u);
       ASSERT_EQ(DCDM[Bindings.front()], ResourceCounterDirection::Increment);
     }
@@ -366,11 +359,8 @@ TEST_F(UniqueResourceFromUseTest, TestResourceCounterUnknown) {
 define void @main() {
 entry:
   %handle = call target("dx.RawBuffer", float, 1, 0) @llvm.dx.resource.handlefrombinding(i32 1, i32 2, i32 3, i32 4, i1 false)
-  call void @a.func(target("dx.RawBuffer", float, 1, 0) %handle)
   ret void
 }
-
-declare void @a.func(target("dx.RawBuffer", float, 1, 0) %handle)
   )";
 
   LLVMContext Context;
@@ -383,14 +373,13 @@ declare void @a.func(target("dx.RawBuffer", float, 1, 0) %handle)
       MAM->getResult<DXILResourceCounterDirectionAnalysis>(*M);
 
   for (const Function &F : M->functions()) {
-    if (F.getName() != "a.func") {
+    if (F.getIntrinsicID() != Intrinsic::dx_resource_handlefrombinding) {
       continue;
     }
 
     for (const User *U : F.users()) {
       const CallInst *CI = cast<CallInst>(U);
-      const Value *Handle = CI->getArgOperand(0);
-      const auto Bindings = DBM.findByUse(Handle);
+      const auto Bindings = DBM.findByUse(CI);
       ASSERT_EQ(Bindings.size(), 1u);
       ASSERT_EQ(DCDM[Bindings.front()], ResourceCounterDirection::Unknown);
     }
@@ -407,13 +396,8 @@ define void @main() {
   %handle2 = call target("dx.RawBuffer", float, 1, 0) @llvm.dx.resource.handlefrombinding(i32 4, i32 3, i32 2, i32 1, i1 false)
   call i32 @llvm.dx.resource.updatecounter(target("dx.RawBuffer", float, 1, 0) %handle1, i8 -1)
   call i32 @llvm.dx.resource.updatecounter(target("dx.RawBuffer", float, 1, 0) %handle2, i8 1)
-  call void @a.func(target("dx.RawBuffer", float, 1, 0) %handle1)
-  call void @b.func(target("dx.RawBuffer", float, 1, 0) %handle2)
   ret void
 }
-
-declare void @a.func(target("dx.RawBuffer", float, 1, 0) %handle)
-declare void @b.func(target("dx.RawBuffer", float, 1, 0) %handle)
   )";
 
   LLVMContext Context;
@@ -425,21 +409,21 @@ declare void @b.func(target("dx.RawBuffer", float, 1, 0) %handle)
   const DXILResourceCounterDirectionMap &DCDM =
       MAM->getResult<DXILResourceCounterDirectionAnalysis>(*M);
 
+  ResourceCounterDirection Dirs[2] = {ResourceCounterDirection::Decrement,
+                                      ResourceCounterDirection::Increment};
+  ResourceCounterDirection *Dir = Dirs;
+
   for (const Function &F : M->functions()) {
-    StringRef FName = F.getName();
-    if (FName != "a.func" && FName != "b.func") {
+    if (F.getIntrinsicID() != Intrinsic::dx_resource_handlefrombinding) {
       continue;
     }
 
-    auto Dir = FName == "a.func" ? ResourceCounterDirection::Decrement
-                                 : ResourceCounterDirection::Increment;
-
     for (const User *U : F.users()) {
       const CallInst *CI = cast<CallInst>(U);
-      const Value *Handle = CI->getArgOperand(0);
-      const auto Bindings = DBM.findByUse(Handle);
+      const auto Bindings = DBM.findByUse(CI);
       ASSERT_EQ(Bindings.size(), 1u);
-      ASSERT_EQ(DCDM[Bindings.front()], Dir);
+      ASSERT_EQ(DCDM[Bindings.front()], *Dir);
+      Dir++;
     }
   }
 }

>From c82249db23dd32b9d4ca24224ba4cee458318ac4 Mon Sep 17 00:00:00 2001
From: Ashley Coleman <ascoleman at microsoft.com>
Date: Mon, 24 Mar 2025 14:14:56 -0600
Subject: [PATCH 15/19] address comments

---
 .../DirectX/UniqueResourceFromUseTests.cpp    | 20 ++++++++-----------
 1 file changed, 8 insertions(+), 12 deletions(-)

diff --git a/llvm/unittests/Target/DirectX/UniqueResourceFromUseTests.cpp b/llvm/unittests/Target/DirectX/UniqueResourceFromUseTests.cpp
index c065648c852a1..fdec0df4a7f89 100644
--- a/llvm/unittests/Target/DirectX/UniqueResourceFromUseTests.cpp
+++ b/llvm/unittests/Target/DirectX/UniqueResourceFromUseTests.cpp
@@ -308,9 +308,8 @@ define void @main() {
 
     for (const User *U : F.users()) {
       const CallInst *CI = cast<CallInst>(U);
-      const auto Bindings = DBM.findByUse(CI);
-      ASSERT_EQ(Bindings.size(), 1u);
-      ASSERT_EQ(DCDM[Bindings.front()], ResourceCounterDirection::Decrement);
+      const auto *const Binding = DBM.find(CI);
+      ASSERT_EQ(DCDM[*Binding], ResourceCounterDirection::Decrement);
     }
   }
 }
@@ -345,9 +344,8 @@ define void @main() {
 
     for (const User *U : F.users()) {
       const CallInst *CI = cast<CallInst>(U);
-      const auto Bindings = DBM.findByUse(CI);
-      ASSERT_EQ(Bindings.size(), 1u);
-      ASSERT_EQ(DCDM[Bindings.front()], ResourceCounterDirection::Increment);
+      const auto *const Binding = DBM.find(CI);
+      ASSERT_EQ(DCDM[*Binding], ResourceCounterDirection::Increment);
     }
   }
 }
@@ -379,9 +377,8 @@ define void @main() {
 
     for (const User *U : F.users()) {
       const CallInst *CI = cast<CallInst>(U);
-      const auto Bindings = DBM.findByUse(CI);
-      ASSERT_EQ(Bindings.size(), 1u);
-      ASSERT_EQ(DCDM[Bindings.front()], ResourceCounterDirection::Unknown);
+      const auto *const Binding = DBM.find(CI);
+      ASSERT_EQ(DCDM[*Binding], ResourceCounterDirection::Unknown);
     }
   }
 }
@@ -420,9 +417,8 @@ define void @main() {
 
     for (const User *U : F.users()) {
       const CallInst *CI = cast<CallInst>(U);
-      const auto Bindings = DBM.findByUse(CI);
-      ASSERT_EQ(Bindings.size(), 1u);
-      ASSERT_EQ(DCDM[Bindings.front()], *Dir);
+      const auto *const Binding = DBM.find(CI);
+      ASSERT_EQ(DCDM[*Binding], *Dir);
       Dir++;
     }
   }

>From 61d371feb8a106fa15748c89536fd75b72b06bee Mon Sep 17 00:00:00 2001
From: Ashley Coleman <ascoleman at microsoft.com>
Date: Mon, 24 Mar 2025 16:44:14 -0600
Subject: [PATCH 16/19] address comments

---
 llvm/include/llvm/Analysis/DXILResource.h  |  7 ++--
 llvm/lib/Analysis/DXILResource.cpp         | 38 +++++++++-------------
 llvm/lib/Target/DirectX/DXILOpLowering.cpp |  6 ++++
 3 files changed, 25 insertions(+), 26 deletions(-)

diff --git a/llvm/include/llvm/Analysis/DXILResource.h b/llvm/include/llvm/Analysis/DXILResource.h
index aa7dfffa399b2..1647d37ef8353 100644
--- a/llvm/include/llvm/Analysis/DXILResource.h
+++ b/llvm/include/llvm/Analysis/DXILResource.h
@@ -593,10 +593,9 @@ class DXILResourceCounterDirectionMap {
 
   ResourceCounterDirection
   operator[](const dxil::ResourceBindingInfo &Info) const {
-    auto Lower = std::lower_bound(
-        CounterDirections.begin(), CounterDirections.end(),
-        std::pair{Info, ResourceCounterDirection::Unknown},
-        [](auto LHS, auto RHS) { return LHS.first < RHS.first; });
+    auto Lower = llvm::lower_bound(
+        CounterDirections, Info,
+        [](const auto &LHS, const auto &RHS) { return LHS.first < RHS; });
 
     if (Lower == CounterDirections.end()) {
       return ResourceCounterDirection::Unknown;
diff --git a/llvm/lib/Analysis/DXILResource.cpp b/llvm/lib/Analysis/DXILResource.cpp
index 278c219c58f3f..c09ce8400b98d 100644
--- a/llvm/lib/Analysis/DXILResource.cpp
+++ b/llvm/lib/Analysis/DXILResource.cpp
@@ -832,7 +832,7 @@ static bool isUpdateCounterIntrinsic(Function &F) {
 }
 
 void DXILResourceCounterDirectionMap::populate(Module &M, DXILBindingMap &DBM) {
-  std::vector<std::tuple<dxil::ResourceBindingInfo, ResourceCounterDirection,
+  SmallVector<std::tuple<dxil::ResourceBindingInfo, ResourceCounterDirection,
                          const Function *, const CallInst *>>
       DiagCounterDirs;
 
@@ -846,14 +846,16 @@ void DXILResourceCounterDirectionMap::populate(Module &M, DXILBindingMap &DBM) {
 
       // Determine if the use is an increment or decrement
       Value *CountArg = CI->getArgOperand(1);
-      ConstantInt *CountValue = dyn_cast<ConstantInt>(CountArg);
+      ConstantInt *CountValue = cast<ConstantInt>(CountArg);
       int64_t CountLiteral = CountValue->getSExtValue();
 
-      ResourceCounterDirection Direction = ResourceCounterDirection::Unknown;
+      // 0 is an unknown direction and shouldn't result in an insert
+      if (CountLiteral == 0)
+        continue;
+
+      ResourceCounterDirection Direction = ResourceCounterDirection::Decrement;
       if (CountLiteral > 0)
         Direction = ResourceCounterDirection::Increment;
-      if (CountLiteral < 0)
-        Direction = ResourceCounterDirection::Decrement;
 
       // Collect all potential creation points for the handle arg
       Value *HandleArg = CI->getArgOperand(0);
@@ -863,17 +865,8 @@ void DXILResourceCounterDirectionMap::populate(Module &M, DXILBindingMap &DBM) {
     }
   }
 
-  // An entry that is not in the map is considered unknown so its wasted
-  // overhead and increased complexity to keep an entry explicitly marked
-  // unknown
-  const auto RemoveEnd = std::remove_if(
-      DiagCounterDirs.begin(), DiagCounterDirs.end(), [](const auto &Item) {
-        return std::get<ResourceCounterDirection>(Item) ==
-               ResourceCounterDirection::Unknown;
-      });
-
   // Sort by the Binding and Direction for fast lookup
-  std::sort(DiagCounterDirs.begin(), RemoveEnd,
+  std::sort(DiagCounterDirs.begin(), DiagCounterDirs.end(),
             [](const auto &LHS, const auto &RHS) {
               const auto L = std::pair{std::get<dxil::ResourceBindingInfo>(LHS),
                                        std::get<ResourceCounterDirection>(LHS)};
@@ -884,8 +877,9 @@ void DXILResourceCounterDirectionMap::populate(Module &M, DXILBindingMap &DBM) {
 
   // Remove the duplicate entries. Since direction is considered for equality
   // a unique resource with more than one direction will not be deduped.
-  const auto UniqueEnd = std::unique(
-      DiagCounterDirs.begin(), RemoveEnd, [](const auto &LHS, const auto &RHS) {
+  auto *const UniqueEnd = std::unique(
+      DiagCounterDirs.begin(), DiagCounterDirs.end(),
+      [](const auto &LHS, const auto &RHS) {
         const auto L = std::pair{std::get<dxil::ResourceBindingInfo>(LHS),
                                  std::get<ResourceCounterDirection>(LHS)};
         const auto R = std::pair{std::get<dxil::ResourceBindingInfo>(RHS),
@@ -893,16 +887,16 @@ void DXILResourceCounterDirectionMap::populate(Module &M, DXILBindingMap &DBM) {
         return L == R;
       });
 
-  // Actually erase the items invalidated by remove_if + unique
+  // Actually erase the invalidated items
   DiagCounterDirs.erase(UniqueEnd, DiagCounterDirs.end());
 
   // If any duplicate entries still exist at this point then it must be a
   // resource that was both incremented and decremented which is not allowed.
   // Mark all those entries as invalid.
   {
-    auto DupFirst = DiagCounterDirs.begin();
-    auto DupNext = DupFirst + 1;
-    auto DupLast = DiagCounterDirs.end();
+    auto *DupFirst = DiagCounterDirs.begin();
+    auto *DupNext = DupFirst + 1;
+    auto *DupLast = DiagCounterDirs.end();
     for (; DupFirst < DupLast && DupNext < DupLast; ++DupFirst, ++DupNext) {
       if (std::get<dxil::ResourceBindingInfo>(*DupFirst) ==
           std::get<dxil::ResourceBindingInfo>(*DupNext)) {
@@ -915,7 +909,7 @@ void DXILResourceCounterDirectionMap::populate(Module &M, DXILBindingMap &DBM) {
   }
 
   // Raise an error for every invalid entry
-  for (const auto Entry : DiagCounterDirs) {
+  for (const auto &Entry : DiagCounterDirs) {
     ResourceCounterDirection Dir = std::get<ResourceCounterDirection>(Entry);
     const Function *F = std::get<const Function *>(Entry);
     const CallInst *CI = std::get<const CallInst *>(Entry);
diff --git a/llvm/lib/Target/DirectX/DXILOpLowering.cpp b/llvm/lib/Target/DirectX/DXILOpLowering.cpp
index cfa65e69ea0bb..c5ce3fc4167b0 100644
--- a/llvm/lib/Target/DirectX/DXILOpLowering.cpp
+++ b/llvm/lib/Target/DirectX/DXILOpLowering.cpp
@@ -858,8 +858,14 @@ class OpLowerer {
 PreservedAnalyses DXILOpLowering::run(Module &M, ModuleAnalysisManager &MAM) {
   DXILBindingMap &DBM = MAM.getResult<DXILResourceBindingAnalysis>(M);
   DXILResourceTypeMap &DRTM = MAM.getResult<DXILResourceTypeAnalysis>(M);
+
+  // TODO: This needs to be called even though its not currently being used in
+  // order for tests to pass. It will eventually need to be used as part of
+  // https://github.com/llvm/llvm-project/issues/125126 which will have the same
+  // effect. Until then discard the result.
   DXILResourceCounterDirectionMap &DRCDM =
       MAM.getResult<DXILResourceCounterDirectionAnalysis>(M);
+  (void)DRCDM;
 
   bool MadeChanges = OpLowerer(M, DBM, DRTM).lowerIntrinsics();
   if (!MadeChanges)

>From 1202e86dc9a88cc4392a93c2e349bfe30d754571 Mon Sep 17 00:00:00 2001
From: Ashley Coleman <ascoleman at microsoft.com>
Date: Mon, 24 Mar 2025 17:25:19 -0600
Subject: [PATCH 17/19] address comments

---
 llvm/lib/Analysis/DXILResource.cpp | 18 ++++++++++--------
 1 file changed, 10 insertions(+), 8 deletions(-)

diff --git a/llvm/lib/Analysis/DXILResource.cpp b/llvm/lib/Analysis/DXILResource.cpp
index c09ce8400b98d..ea0083bc13b82 100644
--- a/llvm/lib/Analysis/DXILResource.cpp
+++ b/llvm/lib/Analysis/DXILResource.cpp
@@ -866,14 +866,16 @@ void DXILResourceCounterDirectionMap::populate(Module &M, DXILBindingMap &DBM) {
   }
 
   // Sort by the Binding and Direction for fast lookup
-  std::sort(DiagCounterDirs.begin(), DiagCounterDirs.end(),
-            [](const auto &LHS, const auto &RHS) {
-              const auto L = std::pair{std::get<dxil::ResourceBindingInfo>(LHS),
-                                       std::get<ResourceCounterDirection>(LHS)};
-              const auto R = std::pair{std::get<dxil::ResourceBindingInfo>(RHS),
-                                       std::get<ResourceCounterDirection>(RHS)};
-              return L < R;
-            });
+  std::stable_sort(DiagCounterDirs.begin(), DiagCounterDirs.end(),
+                   [](const auto &LHS, const auto &RHS) {
+                     const auto L =
+                         std::pair{std::get<dxil::ResourceBindingInfo>(LHS),
+                                   std::get<ResourceCounterDirection>(LHS)};
+                     const auto R =
+                         std::pair{std::get<dxil::ResourceBindingInfo>(RHS),
+                                   std::get<ResourceCounterDirection>(RHS)};
+                     return L < R;
+                   });
 
   // Remove the duplicate entries. Since direction is considered for equality
   // a unique resource with more than one direction will not be deduped.

>From 940b928245ba67eb670d3cfc9c88d71bb8140098 Mon Sep 17 00:00:00 2001
From: Ashley Coleman <me at ashleycoleman.me>
Date: Tue, 25 Mar 2025 10:01:00 -0600
Subject: [PATCH 18/19] Update llvm/include/llvm/Analysis/DXILResource.h

Co-authored-by: Helena Kotas <hekotas at microsoft.com>
---
 llvm/include/llvm/Analysis/DXILResource.h | 7 ++-----
 1 file changed, 2 insertions(+), 5 deletions(-)

diff --git a/llvm/include/llvm/Analysis/DXILResource.h b/llvm/include/llvm/Analysis/DXILResource.h
index 1647d37ef8353..99e53126d897e 100644
--- a/llvm/include/llvm/Analysis/DXILResource.h
+++ b/llvm/include/llvm/Analysis/DXILResource.h
@@ -597,13 +597,10 @@ class DXILResourceCounterDirectionMap {
         CounterDirections, Info,
         [](const auto &LHS, const auto &RHS) { return LHS.first < RHS; });
 
-    if (Lower == CounterDirections.end()) {
+    if (Lower == CounterDirections.end())
       return ResourceCounterDirection::Unknown;
-    }
-
-    if (Lower->first != Info) {
+    if (Lower->first != Info)
       return ResourceCounterDirection::Unknown;
-    }
 
     return Lower->second;
   }

>From 336689770832c51d71bd8f7b33f4a8613b0d83f3 Mon Sep 17 00:00:00 2001
From: Ashley Coleman <ascoleman at microsoft.com>
Date: Tue, 25 Mar 2025 15:08:09 -0600
Subject: [PATCH 19/19] address comments

---
 llvm/include/llvm/Analysis/DXILResource.h     | 10 ++--
 llvm/lib/Analysis/DXILResource.cpp            | 49 ++++++++++---------
 .../DirectX/UniqueResourceFromUseTests.cpp    | 16 +++---
 3 files changed, 41 insertions(+), 34 deletions(-)

diff --git a/llvm/include/llvm/Analysis/DXILResource.h b/llvm/include/llvm/Analysis/DXILResource.h
index 99e53126d897e..a5acca6ec32bb 100644
--- a/llvm/include/llvm/Analysis/DXILResource.h
+++ b/llvm/include/llvm/Analysis/DXILResource.h
@@ -474,7 +474,8 @@ class DXILBindingMap {
   /// ambiguous so multiple creation instructions may be returned. The resulting
   /// ResourceBindingInfo can be used to depuplicate unique handles that
   /// reference the same resource
-  SmallVector<dxil::ResourceBindingInfo> findByUse(const Value *Key) const;
+  SmallVector<const dxil::ResourceBindingInfo *>
+  findByUse(const Value *Key) const;
 
   const_iterator find(const CallInst *Key) const {
     auto Pos = CallMap.find(Key);
@@ -585,7 +586,8 @@ enum class ResourceCounterDirection {
 };
 
 class DXILResourceCounterDirectionMap {
-  std::vector<std::pair<dxil::ResourceBindingInfo, ResourceCounterDirection>>
+  std::vector<
+      std::pair<const dxil::ResourceBindingInfo *, ResourceCounterDirection>>
       CounterDirections;
 
 public:
@@ -595,11 +597,11 @@ class DXILResourceCounterDirectionMap {
   operator[](const dxil::ResourceBindingInfo &Info) const {
     auto Lower = llvm::lower_bound(
         CounterDirections, Info,
-        [](const auto &LHS, const auto &RHS) { return LHS.first < RHS; });
+        [](const auto &LHS, const auto &RHS) { return *LHS.first < RHS; });
 
     if (Lower == CounterDirections.end())
       return ResourceCounterDirection::Unknown;
-    if (Lower->first != Info)
+    if (*Lower->first != Info)
       return ResourceCounterDirection::Unknown;
 
     return Lower->second;
diff --git a/llvm/lib/Analysis/DXILResource.cpp b/llvm/lib/Analysis/DXILResource.cpp
index ea0083bc13b82..668480153c723 100644
--- a/llvm/lib/Analysis/DXILResource.cpp
+++ b/llvm/lib/Analysis/DXILResource.cpp
@@ -786,10 +786,10 @@ void DXILBindingMap::print(raw_ostream &OS, DXILResourceTypeMap &DRTM,
   }
 }
 
-SmallVector<dxil::ResourceBindingInfo>
+SmallVector<const dxil::ResourceBindingInfo *>
 DXILBindingMap::findByUse(const Value *Key) const {
   if (const PHINode *Phi = dyn_cast<PHINode>(Key)) {
-    SmallVector<dxil::ResourceBindingInfo> Children;
+    SmallVector<const dxil::ResourceBindingInfo *> Children;
     for (const Value *V : Phi->operands()) {
       Children.append(findByUse(V));
     }
@@ -805,7 +805,7 @@ DXILBindingMap::findByUse(const Value *Key) const {
   case Intrinsic::dx_resource_handlefrombinding: {
     const auto *It = find(CI);
     assert(It != Infos.end() && "HandleFromBinding must be in resource map");
-    return {*It};
+    return {It};
   }
   default:
     break;
@@ -814,7 +814,7 @@ DXILBindingMap::findByUse(const Value *Key) const {
   // Check if any of the parameters are the resource we are following. If so
   // keep searching. If none of them are return an empty list
   const Type *UseType = CI->getType();
-  SmallVector<dxil::ResourceBindingInfo> Children;
+  SmallVector<const dxil::ResourceBindingInfo *> Children;
   for (const Value *V : CI->args()) {
     if (V->getType() != UseType)
       continue;
@@ -832,8 +832,9 @@ static bool isUpdateCounterIntrinsic(Function &F) {
 }
 
 void DXILResourceCounterDirectionMap::populate(Module &M, DXILBindingMap &DBM) {
-  SmallVector<std::tuple<dxil::ResourceBindingInfo, ResourceCounterDirection,
-                         const Function *, const CallInst *>>
+  SmallVector<
+      std::tuple<const dxil::ResourceBindingInfo *, ResourceCounterDirection,
+                 const Function *, const CallInst *>>
       DiagCounterDirs;
 
   for (Function &F : M.functions()) {
@@ -859,8 +860,9 @@ void DXILResourceCounterDirectionMap::populate(Module &M, DXILBindingMap &DBM) {
 
       // Collect all potential creation points for the handle arg
       Value *HandleArg = CI->getArgOperand(0);
-      SmallVector<dxil::ResourceBindingInfo> RBInfos = DBM.findByUse(HandleArg);
-      for (const dxil::ResourceBindingInfo RBInfo : RBInfos)
+      SmallVector<const dxil::ResourceBindingInfo *> RBInfos =
+          DBM.findByUse(HandleArg);
+      for (const dxil::ResourceBindingInfo *RBInfo : RBInfos)
         DiagCounterDirs.emplace_back(RBInfo, Direction, &F, CI);
     }
   }
@@ -868,12 +870,12 @@ void DXILResourceCounterDirectionMap::populate(Module &M, DXILBindingMap &DBM) {
   // Sort by the Binding and Direction for fast lookup
   std::stable_sort(DiagCounterDirs.begin(), DiagCounterDirs.end(),
                    [](const auto &LHS, const auto &RHS) {
-                     const auto L =
-                         std::pair{std::get<dxil::ResourceBindingInfo>(LHS),
-                                   std::get<ResourceCounterDirection>(LHS)};
-                     const auto R =
-                         std::pair{std::get<dxil::ResourceBindingInfo>(RHS),
-                                   std::get<ResourceCounterDirection>(RHS)};
+                     const auto L = std::pair{
+                         std::get<const dxil::ResourceBindingInfo *>(LHS),
+                         std::get<ResourceCounterDirection>(LHS)};
+                     const auto R = std::pair{
+                         std::get<const dxil::ResourceBindingInfo *>(RHS),
+                         std::get<ResourceCounterDirection>(RHS)};
                      return L < R;
                    });
 
@@ -882,10 +884,12 @@ void DXILResourceCounterDirectionMap::populate(Module &M, DXILBindingMap &DBM) {
   auto *const UniqueEnd = std::unique(
       DiagCounterDirs.begin(), DiagCounterDirs.end(),
       [](const auto &LHS, const auto &RHS) {
-        const auto L = std::pair{std::get<dxil::ResourceBindingInfo>(LHS),
-                                 std::get<ResourceCounterDirection>(LHS)};
-        const auto R = std::pair{std::get<dxil::ResourceBindingInfo>(RHS),
-                                 std::get<ResourceCounterDirection>(RHS)};
+        const auto L =
+            std::pair{std::get<const dxil::ResourceBindingInfo *>(LHS),
+                      std::get<ResourceCounterDirection>(LHS)};
+        const auto R =
+            std::pair{std::get<const dxil::ResourceBindingInfo *>(RHS),
+                      std::get<ResourceCounterDirection>(RHS)};
         return L == R;
       });
 
@@ -900,8 +904,8 @@ void DXILResourceCounterDirectionMap::populate(Module &M, DXILBindingMap &DBM) {
     auto *DupNext = DupFirst + 1;
     auto *DupLast = DiagCounterDirs.end();
     for (; DupFirst < DupLast && DupNext < DupLast; ++DupFirst, ++DupNext) {
-      if (std::get<dxil::ResourceBindingInfo>(*DupFirst) ==
-          std::get<dxil::ResourceBindingInfo>(*DupNext)) {
+      if (std::get<const dxil::ResourceBindingInfo *>(*DupFirst) ==
+          std::get<const dxil::ResourceBindingInfo *>(*DupNext)) {
         std::get<ResourceCounterDirection>(*DupFirst) =
             ResourceCounterDirection::Invalid;
         std::get<ResourceCounterDirection>(*DupNext) =
@@ -930,8 +934,9 @@ void DXILResourceCounterDirectionMap::populate(Module &M, DXILBindingMap &DBM) {
   CounterDirections.reserve(DiagCounterDirs.size());
   std::transform(DiagCounterDirs.begin(), DiagCounterDirs.end(),
                  std::back_inserter(CounterDirections), [](const auto &Item) {
-                   return std::pair{std::get<dxil::ResourceBindingInfo>(Item),
-                                    std::get<ResourceCounterDirection>(Item)};
+                   return std::pair{
+                       std::get<const dxil::ResourceBindingInfo *>(Item),
+                       std::get<ResourceCounterDirection>(Item)};
                  });
 }
 
diff --git a/llvm/unittests/Target/DirectX/UniqueResourceFromUseTests.cpp b/llvm/unittests/Target/DirectX/UniqueResourceFromUseTests.cpp
index fdec0df4a7f89..fcb609a7576b1 100644
--- a/llvm/unittests/Target/DirectX/UniqueResourceFromUseTests.cpp
+++ b/llvm/unittests/Target/DirectX/UniqueResourceFromUseTests.cpp
@@ -78,7 +78,7 @@ declare void @a.func(target("dx.RawBuffer", float, 1, 0) %handle)
       ASSERT_EQ(Bindings.size(), 1u)
           << "Handle should resolve into one resource";
 
-      auto Binding = Bindings[0].getBinding();
+      auto Binding = Bindings[0]->getBinding();
       EXPECT_EQ(0u, Binding.RecordID);
       EXPECT_EQ(1u, Binding.Space);
       EXPECT_EQ(2u, Binding.LowerBound);
@@ -127,7 +127,7 @@ declare target("dx.RawBuffer", float, 1, 0) @ind.func(target("dx.RawBuffer", flo
       ASSERT_EQ(Bindings.size(), 1u)
           << "Handle should resolve into one resource";
 
-      auto Binding = Bindings[0].getBinding();
+      auto Binding = Bindings[0]->getBinding();
       EXPECT_EQ(0u, Binding.RecordID);
       EXPECT_EQ(1u, Binding.Space);
       EXPECT_EQ(2u, Binding.LowerBound);
@@ -179,25 +179,25 @@ declare target("dx.RawBuffer", float, 1, 0) @ind.func(target("dx.RawBuffer", flo
       ASSERT_EQ(Bindings.size(), 4u)
           << "Handle should resolve into four resources";
 
-      auto Binding = Bindings[0].getBinding();
+      auto Binding = Bindings[0]->getBinding();
       EXPECT_EQ(0u, Binding.RecordID);
       EXPECT_EQ(1u, Binding.Space);
       EXPECT_EQ(1u, Binding.LowerBound);
       EXPECT_EQ(1u, Binding.Size);
 
-      Binding = Bindings[1].getBinding();
+      Binding = Bindings[1]->getBinding();
       EXPECT_EQ(1u, Binding.RecordID);
       EXPECT_EQ(2u, Binding.Space);
       EXPECT_EQ(2u, Binding.LowerBound);
       EXPECT_EQ(2u, Binding.Size);
 
-      Binding = Bindings[2].getBinding();
+      Binding = Bindings[2]->getBinding();
       EXPECT_EQ(2u, Binding.RecordID);
       EXPECT_EQ(3u, Binding.Space);
       EXPECT_EQ(3u, Binding.LowerBound);
       EXPECT_EQ(3u, Binding.Size);
 
-      Binding = Bindings[3].getBinding();
+      Binding = Bindings[3]->getBinding();
       EXPECT_EQ(3u, Binding.RecordID);
       EXPECT_EQ(4u, Binding.Space);
       EXPECT_EQ(4u, Binding.LowerBound);
@@ -258,13 +258,13 @@ declare target("dx.RawBuffer", float, 1, 0) @ind.func(target("dx.RawBuffer", flo
       ASSERT_EQ(Bindings.size(), 2u)
           << "Handle should resolve into four resources";
 
-      auto Binding = Bindings[0].getBinding();
+      auto Binding = Bindings[0]->getBinding();
       EXPECT_EQ(0u, Binding.RecordID);
       EXPECT_EQ(1u, Binding.Space);
       EXPECT_EQ(1u, Binding.LowerBound);
       EXPECT_EQ(1u, Binding.Size);
 
-      Binding = Bindings[1].getBinding();
+      Binding = Bindings[1]->getBinding();
       EXPECT_EQ(1u, Binding.RecordID);
       EXPECT_EQ(4u, Binding.Space);
       EXPECT_EQ(4u, Binding.LowerBound);



More information about the llvm-commits mailing list