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

Ashley Coleman via llvm-commits llvm-commits at lists.llvm.org
Thu Mar 27 15:56:01 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/26] [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/26] 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/26] 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/26] 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/26] 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/26] 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/26] 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/26] 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/26] 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/26] 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/26] 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/26] 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/26] 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/26] 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/26] 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/26] 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/26] 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/26] 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/26] 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);

>From 6de3c49b2df1afb89d237fc16f22783c539dace5 Mon Sep 17 00:00:00 2001
From: Ashley Coleman <ascoleman at microsoft.com>
Date: Tue, 25 Mar 2025 18:02:43 -0600
Subject: [PATCH 20/26] address comments

---
 llvm/include/llvm/Analysis/DXILResource.h | 14 ++----
 llvm/lib/Analysis/DXILResource.cpp        | 54 ++++++++++++++++++++---
 2 files changed, 52 insertions(+), 16 deletions(-)

diff --git a/llvm/include/llvm/Analysis/DXILResource.h b/llvm/include/llvm/Analysis/DXILResource.h
index a5acca6ec32bb..d7f619e18fe73 100644
--- a/llvm/include/llvm/Analysis/DXILResource.h
+++ b/llvm/include/llvm/Analysis/DXILResource.h
@@ -594,18 +594,9 @@ class DXILResourceCounterDirectionMap {
   void populate(Module &M, DXILBindingMap &DBM);
 
   ResourceCounterDirection
-  operator[](const dxil::ResourceBindingInfo &Info) const {
-    auto Lower = llvm::lower_bound(
-        CounterDirections, Info,
-        [](const auto &LHS, const auto &RHS) { return *LHS.first < RHS; });
+  operator[](const dxil::ResourceBindingInfo &Info) const;
 
-    if (Lower == CounterDirections.end())
-      return ResourceCounterDirection::Unknown;
-    if (*Lower->first != Info)
-      return ResourceCounterDirection::Unknown;
-
-    return Lower->second;
-  }
+  void print(raw_ostream &OS) const;
 };
 
 class DXILResourceCounterDirectionAnalysis
@@ -646,6 +637,7 @@ class DXILResourceCounterDirectionWrapperPass : public ModulePass {
   void releaseMemory() override;
 
   void print(raw_ostream &OS, const Module *M) const override;
+  void dump() const;
 };
 
 ModulePass *createDXILResourceCounterDirectionWrapperPassPass();
diff --git a/llvm/lib/Analysis/DXILResource.cpp b/llvm/lib/Analysis/DXILResource.cpp
index 668480153c723..8a7197397739f 100644
--- a/llvm/lib/Analysis/DXILResource.cpp
+++ b/llvm/lib/Analysis/DXILResource.cpp
@@ -940,6 +940,46 @@ void DXILResourceCounterDirectionMap::populate(Module &M, DXILBindingMap &DBM) {
                  });
 }
 
+ResourceCounterDirection DXILResourceCounterDirectionMap::operator[](
+    const dxil::ResourceBindingInfo &Info) const {
+  auto Lower = llvm::lower_bound(
+      CounterDirections, Info,
+      [](const auto &LHS, const auto &RHS) { return *LHS.first < RHS; });
+
+  if (Lower == CounterDirections.end())
+    return ResourceCounterDirection::Unknown;
+  if (*Lower->first != Info)
+    return ResourceCounterDirection::Unknown;
+
+  return Lower->second;
+}
+
+void DXILResourceCounterDirectionMap::print(raw_ostream &OS) const {
+  OS << "Counter Directions:\n";
+  for (const auto &Dir : CounterDirections) {
+    const dxil::ResourceBindingInfo::ResourceBinding &RB =
+        Dir.first->getBinding();
+
+    OS << "  Binding(" << RB.RecordID << ", " << RB.Size << ", "
+       << RB.LowerBound << ", " << RB.Size << ", " << ")'s counter is ";
+
+    switch (Dir.second) {
+    case ResourceCounterDirection::Increment:
+      OS << "incremented\n";
+      break;
+    case ResourceCounterDirection::Decrement:
+      OS << "decremented\n";
+      break;
+    case ResourceCounterDirection::Unknown:
+      OS << "unknown\n";
+      break;
+    case ResourceCounterDirection::Invalid:
+      OS << "invalid\n";
+      break;
+    }
+  }
+}
+
 void DXILResourceCounterDirectionWrapperPass::getAnalysisUsage(
     AnalysisUsage &AU) const {
   AU.addRequiredTransitive<DXILResourceBindingWrapperPass>();
@@ -963,13 +1003,17 @@ void DXILResourceCounterDirectionWrapperPass::print(raw_ostream &OS,
     OS << "No resource directions have been built!\n";
     return;
   }
-  // Map->print(OS, *DRTM, M->getDataLayout());
+
+  Map->print(OS);
 }
 
-// #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;

>From f6a39c7a9bf250c898404c5f8a65d35ca74c67db Mon Sep 17 00:00:00 2001
From: Ashley Coleman <ascoleman at microsoft.com>
Date: Wed, 26 Mar 2025 12:38:00 -0600
Subject: [PATCH 21/26] address comments

---
 llvm/lib/Analysis/DXILResource.cpp | 28 +++++++++++++---------------
 1 file changed, 13 insertions(+), 15 deletions(-)

diff --git a/llvm/lib/Analysis/DXILResource.cpp b/llvm/lib/Analysis/DXILResource.cpp
index 8a7197397739f..28844d6eb0c64 100644
--- a/llvm/lib/Analysis/DXILResource.cpp
+++ b/llvm/lib/Analysis/DXILResource.cpp
@@ -910,25 +910,23 @@ void DXILResourceCounterDirectionMap::populate(Module &M, DXILBindingMap &DBM) {
             ResourceCounterDirection::Invalid;
         std::get<ResourceCounterDirection>(*DupNext) =
             ResourceCounterDirection::Invalid;
+
+        // Raise an error for every invalid entry
+        StringRef Message =
+            "RWStructuredBuffers may increment or decrement their "
+            "counters, but not both.";
+        const Function *FFirst = std::get<const Function *>(*DupFirst);
+        const CallInst *CIFirst = std::get<const CallInst *>(*DupFirst);
+        const Function *FNext = std::get<const Function *>(*DupNext);
+        const CallInst *CINext = std::get<const CallInst *>(*DupNext);
+        M.getContext().diagnose(DiagnosticInfoGenericWithLoc(
+            Message, *FFirst, CIFirst->getDebugLoc()));
+        M.getContext().diagnose(DiagnosticInfoGenericWithLoc(
+            Message, *FNext, CINext->getDebugLoc()));
       }
     }
   }
 
-  // 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::Invalid)
-      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();
   CounterDirections.reserve(DiagCounterDirs.size());

>From 6ae40ec151331a9e640f5981435481b4a9095f45 Mon Sep 17 00:00:00 2001
From: Ashley Coleman <ascoleman at microsoft.com>
Date: Wed, 26 Mar 2025 17:03:59 -0600
Subject: [PATCH 22/26] Remove unnecessary functions

---
 llvm/include/llvm/Analysis/DXILResource.h |  5 ---
 llvm/lib/Analysis/DXILResource.cpp        | 43 -----------------------
 2 files changed, 48 deletions(-)

diff --git a/llvm/include/llvm/Analysis/DXILResource.h b/llvm/include/llvm/Analysis/DXILResource.h
index d7f619e18fe73..05937ac6b00ae 100644
--- a/llvm/include/llvm/Analysis/DXILResource.h
+++ b/llvm/include/llvm/Analysis/DXILResource.h
@@ -595,8 +595,6 @@ class DXILResourceCounterDirectionMap {
 
   ResourceCounterDirection
   operator[](const dxil::ResourceBindingInfo &Info) const;
-
-  void print(raw_ostream &OS) const;
 };
 
 class DXILResourceCounterDirectionAnalysis
@@ -635,9 +633,6 @@ class DXILResourceCounterDirectionWrapperPass : public ModulePass {
   void getAnalysisUsage(AnalysisUsage &AU) const override;
   bool runOnModule(Module &M) override;
   void releaseMemory() override;
-
-  void print(raw_ostream &OS, const Module *M) const override;
-  void dump() const;
 };
 
 ModulePass *createDXILResourceCounterDirectionWrapperPassPass();
diff --git a/llvm/lib/Analysis/DXILResource.cpp b/llvm/lib/Analysis/DXILResource.cpp
index 28844d6eb0c64..b8d4afa5e3f96 100644
--- a/llvm/lib/Analysis/DXILResource.cpp
+++ b/llvm/lib/Analysis/DXILResource.cpp
@@ -952,32 +952,6 @@ ResourceCounterDirection DXILResourceCounterDirectionMap::operator[](
   return Lower->second;
 }
 
-void DXILResourceCounterDirectionMap::print(raw_ostream &OS) const {
-  OS << "Counter Directions:\n";
-  for (const auto &Dir : CounterDirections) {
-    const dxil::ResourceBindingInfo::ResourceBinding &RB =
-        Dir.first->getBinding();
-
-    OS << "  Binding(" << RB.RecordID << ", " << RB.Size << ", "
-       << RB.LowerBound << ", " << RB.Size << ", " << ")'s counter is ";
-
-    switch (Dir.second) {
-    case ResourceCounterDirection::Increment:
-      OS << "incremented\n";
-      break;
-    case ResourceCounterDirection::Decrement:
-      OS << "decremented\n";
-      break;
-    case ResourceCounterDirection::Unknown:
-      OS << "unknown\n";
-      break;
-    case ResourceCounterDirection::Invalid:
-      OS << "invalid\n";
-      break;
-    }
-  }
-}
-
 void DXILResourceCounterDirectionWrapperPass::getAnalysisUsage(
     AnalysisUsage &AU) const {
   AU.addRequiredTransitive<DXILResourceBindingWrapperPass>();
@@ -995,23 +969,6 @@ bool DXILResourceCounterDirectionWrapperPass::runOnModule(Module &M) {
 
 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);
-}
-
-#if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP)
-LLVM_DUMP_METHOD
-void DXILResourceCounterDirectionWrapperPass::dump() const {
-  print(dbgs(), nullptr);
-}
-#endif
-
 //===----------------------------------------------------------------------===//
 
 AnalysisKey DXILResourceTypeAnalysis::Key;

>From 34a9b123d0130b50fc69ce518807ed62c0c9659f Mon Sep 17 00:00:00 2001
From: Ashley Coleman <ascoleman at microsoft.com>
Date: Thu, 27 Mar 2025 11:15:30 -0600
Subject: [PATCH 23/26] Raise error for each invalid use

---
 llvm/lib/Analysis/DXILResource.cpp | 85 ++++++++++++++++--------------
 1 file changed, 44 insertions(+), 41 deletions(-)

diff --git a/llvm/lib/Analysis/DXILResource.cpp b/llvm/lib/Analysis/DXILResource.cpp
index b8d4afa5e3f96..3830d980f1129 100644
--- a/llvm/lib/Analysis/DXILResource.cpp
+++ b/llvm/lib/Analysis/DXILResource.cpp
@@ -879,58 +879,61 @@ void DXILResourceCounterDirectionMap::populate(Module &M, DXILBindingMap &DBM) {
                      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.
-  auto *const UniqueEnd = std::unique(
-      DiagCounterDirs.begin(), DiagCounterDirs.end(),
-      [](const auto &LHS, const auto &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;
-      });
-
-  // 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();
-    for (; DupFirst < DupLast && DupNext < DupLast; ++DupFirst, ++DupNext) {
-      if (std::get<const dxil::ResourceBindingInfo *>(*DupFirst) ==
-          std::get<const dxil::ResourceBindingInfo *>(*DupNext)) {
-        std::get<ResourceCounterDirection>(*DupFirst) =
-            ResourceCounterDirection::Invalid;
-        std::get<ResourceCounterDirection>(*DupNext) =
+    auto *SpanStart = DiagCounterDirs.begin();
+    auto *SpanEnd = SpanStart;
+    auto *ItEnd = DiagCounterDirs.end();
+
+    while (SpanStart < ItEnd) {
+      while (SpanEnd < ItEnd &&
+             std::get<const dxil::ResourceBindingInfo *>(*SpanStart) ==
+                 std::get<const dxil::ResourceBindingInfo *>(*SpanEnd))
+        SpanEnd++;
+
+      // SpanStart : SpanEnd-1 are the same binding. Its an error if they aren't
+      // all the same direction
+      ResourceCounterDirection ResourceDir =
+          std::get<ResourceCounterDirection>(*SpanStart);
+      bool ValidUse = true;
+      for (auto *CheckIt = SpanStart; CheckIt < SpanEnd; ++CheckIt) {
+        if (ResourceDir != std::get<ResourceCounterDirection>(*CheckIt)) {
+          ValidUse = false;
+          break;
+        }
+      }
+
+      // Update the direction and raise a diag when an invalid use is detected
+      for (auto *RaiseIt = SpanStart; !ValidUse && RaiseIt < SpanEnd;
+           ++RaiseIt) {
+        std::get<ResourceCounterDirection>(*RaiseIt) =
             ResourceCounterDirection::Invalid;
 
-        // Raise an error for every invalid entry
         StringRef Message =
             "RWStructuredBuffers may increment or decrement their "
             "counters, but not both.";
-        const Function *FFirst = std::get<const Function *>(*DupFirst);
-        const CallInst *CIFirst = std::get<const CallInst *>(*DupFirst);
-        const Function *FNext = std::get<const Function *>(*DupNext);
-        const CallInst *CINext = std::get<const CallInst *>(*DupNext);
-        M.getContext().diagnose(DiagnosticInfoGenericWithLoc(
-            Message, *FFirst, CIFirst->getDebugLoc()));
-        M.getContext().diagnose(DiagnosticInfoGenericWithLoc(
-            Message, *FNext, CINext->getDebugLoc()));
+        const Function *F = std::get<const Function *>(*RaiseIt);
+        const CallInst *CI = std::get<const CallInst *>(*RaiseIt);
+        M.getContext().diagnose(
+            DiagnosticInfoGenericWithLoc(Message, *F, CI->getDebugLoc()));
       }
+
+      SpanStart = SpanEnd;
     }
   }
 
-  // Copy the results into the final vec
+  // Remove the duplicate entries. All entries with the same resource have the
+  // same direction so it can be ignored.
+  auto *const UniqueEnd =
+      std::unique(DiagCounterDirs.begin(), DiagCounterDirs.end(),
+                  [](const auto &LHS, const auto &RHS) {
+                    return std::get<const dxil::ResourceBindingInfo *>(LHS) ==
+                           std::get<const dxil::ResourceBindingInfo *>(RHS);
+                  });
+
+  // Copy the results into the final location
   CounterDirections.clear();
-  CounterDirections.reserve(DiagCounterDirs.size());
-  std::transform(DiagCounterDirs.begin(), DiagCounterDirs.end(),
+  CounterDirections.reserve(UniqueEnd - DiagCounterDirs.begin());
+  std::transform(DiagCounterDirs.begin(), UniqueEnd,
                  std::back_inserter(CounterDirections), [](const auto &Item) {
                    return std::pair{
                        std::get<const dxil::ResourceBindingInfo *>(Item),

>From 649b5d41551e5063c4f88a8b260cf999ed979a15 Mon Sep 17 00:00:00 2001
From: Ashley Coleman <ascoleman at microsoft.com>
Date: Thu, 27 Mar 2025 11:39:13 -0600
Subject: [PATCH 24/26] stable_sort no longer needed

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

diff --git a/llvm/lib/Analysis/DXILResource.cpp b/llvm/lib/Analysis/DXILResource.cpp
index 3830d980f1129..0c8b48c995761 100644
--- a/llvm/lib/Analysis/DXILResource.cpp
+++ b/llvm/lib/Analysis/DXILResource.cpp
@@ -868,16 +868,16 @@ 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<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;
-                   });
+  std::sort(DiagCounterDirs.begin(), DiagCounterDirs.end(),
+            [](const auto &LHS, const auto &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;
+            });
 
   {
     auto *SpanStart = DiagCounterDirs.begin();

>From cbe278b5f47cbeedc6f33e55c43de35377af74c7 Mon Sep 17 00:00:00 2001
From: Ashley Coleman <ascoleman at microsoft.com>
Date: Thu, 27 Mar 2025 14:42:02 -0600
Subject: [PATCH 25/26] remove some test boilerplate

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

diff --git a/llvm/unittests/Target/DirectX/UniqueResourceFromUseTests.cpp b/llvm/unittests/Target/DirectX/UniqueResourceFromUseTests.cpp
index fcb609a7576b1..1e96295caa460 100644
--- a/llvm/unittests/Target/DirectX/UniqueResourceFromUseTests.cpp
+++ b/llvm/unittests/Target/DirectX/UniqueResourceFromUseTests.cpp
@@ -29,8 +29,9 @@ class UniqueResourceFromUseTest : public testing::Test {
 protected:
   PassBuilder *PB;
   ModuleAnalysisManager *MAM;
-
+  LLVMContext *Context;
   virtual void SetUp() {
+    Context = new LLVMContext();
     MAM = new ModuleAnalysisManager();
     PB = new PassBuilder();
     PB->registerModuleAnalyses(*MAM);
@@ -39,9 +40,17 @@ class UniqueResourceFromUseTest : public testing::Test {
     MAM->registerPass([&] { return DXILResourceCounterDirectionAnalysis(); });
   }
 
+  std::unique_ptr<Module> parseAsm(StringRef Asm) {
+    SMDiagnostic Error;
+    std::unique_ptr<Module> M = parseAssemblyString(Asm, Error, *Context);
+    EXPECT_TRUE(M) << "Bad assembly?: " << Error.getMessage();
+    return M;
+  }
+
   virtual void TearDown() {
     delete PB;
     delete MAM;
+    delete Context;
   }
 };
 
@@ -58,10 +67,7 @@ define void @main() {
 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?";
+  auto M = parseAsm(Assembly);
 
   const DXILBindingMap &DBM = MAM->getResult<DXILResourceBindingAnalysis>(*M);
   for (const Function &F : M->functions()) {
@@ -107,10 +113,7 @@ 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)
   )";
 
-  LLVMContext Context;
-  SMDiagnostic Error;
-  auto M = parseAssemblyString(Assembly, Error, Context);
-  ASSERT_TRUE(M) << "Bad assembly?";
+  auto M = parseAsm(Assembly);
 
   const DXILBindingMap &DBM = MAM->getResult<DXILResourceBindingAnalysis>(*M);
   for (const Function &F : M->functions()) {
@@ -159,10 +162,7 @@ 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)
   )";
 
-  LLVMContext Context;
-  SMDiagnostic Error;
-  auto M = parseAssemblyString(Assembly, Error, Context);
-  ASSERT_TRUE(M) << "Bad assembly?";
+  auto M = parseAsm(Assembly);
 
   const DXILBindingMap &DBM = MAM->getResult<DXILResourceBindingAnalysis>(*M);
   for (const Function &F : M->functions()) {
@@ -238,10 +238,7 @@ 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)
   )";
 
-  LLVMContext Context;
-  SMDiagnostic Error;
-  auto M = parseAssemblyString(Assembly, Error, Context);
-  ASSERT_TRUE(M) << "Bad assembly?";
+  auto M = parseAsm(Assembly);
 
   const DXILBindingMap &DBM = MAM->getResult<DXILResourceBindingAnalysis>(*M);
   for (const Function &F : M->functions()) {
@@ -292,10 +289,7 @@ define void @main() {
 }
   )";
 
-  LLVMContext Context;
-  SMDiagnostic Error;
-  auto M = parseAssemblyString(Assembly, Error, Context);
-  ASSERT_TRUE(M) << "Bad assembly?";
+  auto M = parseAsm(Assembly);
 
   const DXILBindingMap &DBM = MAM->getResult<DXILResourceBindingAnalysis>(*M);
   const DXILResourceCounterDirectionMap &DCDM =
@@ -328,10 +322,7 @@ define void @main() {
 }
   )";
 
-  LLVMContext Context;
-  SMDiagnostic Error;
-  auto M = parseAssemblyString(Assembly, Error, Context);
-  ASSERT_TRUE(M) << "Bad assembly?";
+  auto M = parseAsm(Assembly);
 
   const DXILBindingMap &DBM = MAM->getResult<DXILResourceBindingAnalysis>(*M);
   const DXILResourceCounterDirectionMap &DCDM =
@@ -361,10 +352,7 @@ define void @main() {
 }
   )";
 
-  LLVMContext Context;
-  SMDiagnostic Error;
-  auto M = parseAssemblyString(Assembly, Error, Context);
-  ASSERT_TRUE(M) << "Bad assembly?";
+  auto M = parseAsm(Assembly);
 
   const DXILBindingMap &DBM = MAM->getResult<DXILResourceBindingAnalysis>(*M);
   const DXILResourceCounterDirectionMap &DCDM =
@@ -397,10 +385,7 @@ define void @main() {
 }
   )";
 
-  LLVMContext Context;
-  SMDiagnostic Error;
-  auto M = parseAssemblyString(Assembly, Error, Context);
-  ASSERT_TRUE(M) << "Bad assembly?";
+  auto M = parseAsm(Assembly);
 
   const DXILBindingMap &DBM = MAM->getResult<DXILResourceBindingAnalysis>(*M);
   const DXILResourceCounterDirectionMap &DCDM =

>From f21043388bc52e3e913bab11a8dba50d17586798 Mon Sep 17 00:00:00 2001
From: Ashley Coleman <ascoleman at microsoft.com>
Date: Thu, 27 Mar 2025 16:54:57 -0600
Subject: [PATCH 26/26] Pare back to analysis only

---
 llvm/lib/Analysis/DXILResource.cpp            | 97 +++++--------------
 llvm/lib/Target/DirectX/DXILOpLowering.cpp    |  8 --
 .../CodeGen/DirectX/resource_counter_error.ll | 13 ---
 .../DirectX/UniqueResourceFromUseTests.cpp    | 35 ++++++-
 4 files changed, 58 insertions(+), 95 deletions(-)
 delete 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 0c8b48c995761..41c4daa53c057 100644
--- a/llvm/lib/Analysis/DXILResource.cpp
+++ b/llvm/lib/Analysis/DXILResource.cpp
@@ -11,7 +11,6 @@
 #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"
@@ -22,7 +21,6 @@
 #include "llvm/InitializePasses.h"
 #include "llvm/Support/FormatVariadic.h"
 #include <algorithm>
-#include <iterator>
 
 #define DEBUG_TYPE "dxil-resource"
 
@@ -832,11 +830,6 @@ static bool isUpdateCounterIntrinsic(Function &F) {
 }
 
 void DXILResourceCounterDirectionMap::populate(Module &M, DXILBindingMap &DBM) {
-  SmallVector<
-      std::tuple<const dxil::ResourceBindingInfo *, ResourceCounterDirection,
-                 const Function *, const CallInst *>>
-      DiagCounterDirs;
-
   for (Function &F : M.functions()) {
     if (!isUpdateCounterIntrinsic(F))
       continue;
@@ -863,82 +856,42 @@ void DXILResourceCounterDirectionMap::populate(Module &M, DXILBindingMap &DBM) {
       SmallVector<const dxil::ResourceBindingInfo *> RBInfos =
           DBM.findByUse(HandleArg);
       for (const dxil::ResourceBindingInfo *RBInfo : RBInfos)
-        DiagCounterDirs.emplace_back(RBInfo, Direction, &F, CI);
+        CounterDirections.emplace_back(RBInfo, Direction);
     }
   }
 
   // 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<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;
-            });
+  std::sort(CounterDirections.begin(), CounterDirections.end());
 
-  {
-    auto *SpanStart = DiagCounterDirs.begin();
-    auto *SpanEnd = SpanStart;
-    auto *ItEnd = DiagCounterDirs.end();
-
-    while (SpanStart < ItEnd) {
-      while (SpanEnd < ItEnd &&
-             std::get<const dxil::ResourceBindingInfo *>(*SpanStart) ==
-                 std::get<const dxil::ResourceBindingInfo *>(*SpanEnd))
-        SpanEnd++;
-
-      // SpanStart : SpanEnd-1 are the same binding. Its an error if they aren't
-      // all the same direction
-      ResourceCounterDirection ResourceDir =
-          std::get<ResourceCounterDirection>(*SpanStart);
-      bool ValidUse = true;
-      for (auto *CheckIt = SpanStart; CheckIt < SpanEnd; ++CheckIt) {
-        if (ResourceDir != std::get<ResourceCounterDirection>(*CheckIt)) {
-          ValidUse = false;
-          break;
-        }
-      }
+  // Remove the duplicate entries. Since direction is considered for equality
+  // a unique resource with more than one direction will not be deduped.
+  auto UniqueEnd =
+      std::unique(CounterDirections.begin(), CounterDirections.end());
 
-      // Update the direction and raise a diag when an invalid use is detected
-      for (auto *RaiseIt = SpanStart; !ValidUse && RaiseIt < SpanEnd;
-           ++RaiseIt) {
-        std::get<ResourceCounterDirection>(*RaiseIt) =
+  // 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 = CounterDirections.begin();
+    auto DupNext = DupFirst + 1;
+    auto DupLast = UniqueEnd;
+    for (; DupFirst < DupLast && DupNext < DupLast; ++DupFirst, ++DupNext) {
+      if (std::get<const dxil::ResourceBindingInfo *>(*DupFirst) ==
+          std::get<const dxil::ResourceBindingInfo *>(*DupNext)) {
+        std::get<ResourceCounterDirection>(*DupFirst) =
+            ResourceCounterDirection::Invalid;
+        std::get<ResourceCounterDirection>(*DupNext) =
             ResourceCounterDirection::Invalid;
-
-        StringRef Message =
-            "RWStructuredBuffers may increment or decrement their "
-            "counters, but not both.";
-        const Function *F = std::get<const Function *>(*RaiseIt);
-        const CallInst *CI = std::get<const CallInst *>(*RaiseIt);
-        M.getContext().diagnose(
-            DiagnosticInfoGenericWithLoc(Message, *F, CI->getDebugLoc()));
       }
-
-      SpanStart = SpanEnd;
     }
   }
 
-  // Remove the duplicate entries. All entries with the same resource have the
-  // same direction so it can be ignored.
-  auto *const UniqueEnd =
-      std::unique(DiagCounterDirs.begin(), DiagCounterDirs.end(),
-                  [](const auto &LHS, const auto &RHS) {
-                    return std::get<const dxil::ResourceBindingInfo *>(LHS) ==
-                           std::get<const dxil::ResourceBindingInfo *>(RHS);
-                  });
-
-  // Copy the results into the final location
-  CounterDirections.clear();
-  CounterDirections.reserve(UniqueEnd - DiagCounterDirs.begin());
-  std::transform(DiagCounterDirs.begin(), UniqueEnd,
-                 std::back_inserter(CounterDirections), [](const auto &Item) {
-                   return std::pair{
-                       std::get<const dxil::ResourceBindingInfo *>(Item),
-                       std::get<ResourceCounterDirection>(Item)};
-                 });
+  // Remove the duplicate entries again now that each duplicate resource has the
+  // same direction for each entry leaving one entry per RBI
+  UniqueEnd = std::unique(CounterDirections.begin(), UniqueEnd);
+
+  // Actually erase the invalidated items
+  CounterDirections.erase(UniqueEnd, CounterDirections.end());
 }
 
 ResourceCounterDirection DXILResourceCounterDirectionMap::operator[](
diff --git a/llvm/lib/Target/DirectX/DXILOpLowering.cpp b/llvm/lib/Target/DirectX/DXILOpLowering.cpp
index c5ce3fc4167b0..dff9f3e03079e 100644
--- a/llvm/lib/Target/DirectX/DXILOpLowering.cpp
+++ b/llvm/lib/Target/DirectX/DXILOpLowering.cpp
@@ -859,14 +859,6 @@ 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)
     return PreservedAnalyses::all();
diff --git a/llvm/test/CodeGen/DirectX/resource_counter_error.ll b/llvm/test/CodeGen/DirectX/resource_counter_error.ll
deleted file mode 100644
index bea8dcac572e5..0000000000000
--- a/llvm/test/CodeGen/DirectX/resource_counter_error.ll
+++ /dev/null
@@ -1,13 +0,0 @@
-; RUN: not opt -S -passes='dxil-op-lower' -mtriple=dxil-pc-shadermodel6.3-library %s 2>&1 | FileCheck %s
-; CHECK: <unknown>:0:0: 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 1e96295caa460..9d9ade897b6e2 100644
--- a/llvm/unittests/Target/DirectX/UniqueResourceFromUseTests.cpp
+++ b/llvm/unittests/Target/DirectX/UniqueResourceFromUseTests.cpp
@@ -371,8 +371,8 @@ define void @main() {
   }
 }
 
-// Test that multiple different resources with unique incs/decs don't
-// raise a Diagnostic and can be individually checked for direction
+// Test that multiple different resources with unique incs/decs aren't
+// marked invalid
 TEST_F(UniqueResourceFromUseTest, TestResourceCounterMultiple) {
   StringRef Assembly = R"(
 define void @main() {
@@ -409,4 +409,35 @@ define void @main() {
   }
 }
 
+// Test that single different resources with unique incs/decs is marked invalid
+TEST_F(UniqueResourceFromUseTest, TestResourceCounterInvalid) {
+  StringRef Assembly = R"(
+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 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)
+  ret void
+}
+  )";
+
+  auto M = parseAsm(Assembly);
+
+  const DXILBindingMap &DBM = MAM->getResult<DXILResourceBindingAnalysis>(*M);
+  const DXILResourceCounterDirectionMap &DCDM =
+      MAM->getResult<DXILResourceCounterDirectionAnalysis>(*M);
+
+  for (const Function &F : M->functions()) {
+    if (F.getIntrinsicID() != Intrinsic::dx_resource_handlefrombinding) {
+      continue;
+    }
+
+    for (const User *U : F.users()) {
+      const CallInst *CI = cast<CallInst>(U);
+      const auto *const Binding = DBM.find(CI);
+      ASSERT_EQ(DCDM[*Binding], ResourceCounterDirection::Invalid);
+    }
+  }
+}
+
 } // namespace



More information about the llvm-commits mailing list