[llvm] [HLSL] Analyze update counter usage (PR #130356)
Ashley Coleman via llvm-commits
llvm-commits at lists.llvm.org
Fri Mar 7 14:03:24 PST 2025
https://github.com/V-FEXrt created https://github.com/llvm/llvm-project/pull/130356
Analyzes calls to Increment/Decrement count and stores the analysis. Pass also verifies that a given resource is only incremented or decremented but never both.
>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 1/4] [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 2/4] 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 3/4] 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 4/4] 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);
More information about the llvm-commits
mailing list