[llvm] [HLSL] Analyze update counter usage (PR #130356)
via llvm-commits
llvm-commits at lists.llvm.org
Fri Mar 7 14:03:58 PST 2025
llvmbot wrote:
<!--LLVM PR SUMMARY COMMENT-->
@llvm/pr-subscribers-llvm-analysis
Author: Ashley Coleman (V-FEXrt)
<details>
<summary>Changes</summary>
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.
---
Full diff: https://github.com/llvm/llvm-project/pull/130356.diff
7 Files Affected:
- (modified) llvm/include/llvm/Analysis/DXILResource.h (+75)
- (modified) llvm/include/llvm/InitializePasses.h (+1)
- (modified) llvm/lib/Analysis/DXILResource.cpp (+101)
- (modified) llvm/lib/Passes/PassRegistry.def (+1)
- (modified) llvm/lib/Target/DirectX/DXILOpLowering.cpp (+2)
- (added) llvm/test/CodeGen/DirectX/resource_counter_error.ll (+13)
- (modified) llvm/unittests/Target/DirectX/UniqueResourceFromUseTests.cpp (+168)
``````````diff
diff --git a/llvm/include/llvm/Analysis/DXILResource.h b/llvm/include/llvm/Analysis/DXILResource.h
index d399457e16916..61ee3b99d250f 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,77 @@ 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..b5e28199593a4 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"
@@ -19,6 +20,7 @@
#include "llvm/IR/Module.h"
#include "llvm/InitializePasses.h"
#include "llvm/Support/FormatVariadic.h"
+#include <algorithm>
#define DEBUG_TYPE "dxil-resource"
@@ -818,8 +820,92 @@ 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 an entry explicitly marked
+ // unknown
+ 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;
+
+ StringRef Message = "RWStructuredBuffers may increment or decrement their "
+ "counters, but not both.";
+ 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();
+ return false;
+}
+
+void DXILResourceCounterDirectionWrapperPass::anchor() {}
+
+//===----------------------------------------------------------------------===//
+
AnalysisKey DXILResourceTypeAnalysis::Key;
AnalysisKey DXILResourceBindingAnalysis::Key;
+AnalysisKey DXILResourceCounterDirectionAnalysis::Key;
DXILBindingMap DXILResourceBindingAnalysis::run(Module &M,
ModuleAnalysisManager &AM) {
@@ -838,6 +924,16 @@ 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 +943,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/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..ba2f2d9096d03 100644
--- a/llvm/lib/Target/DirectX/DXILOpLowering.cpp
+++ b/llvm/lib/Target/DirectX/DXILOpLowering.cpp
@@ -816,6 +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);
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 f272381c0c250..b653bc3127ffc 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,171 @@ declare target("dx.RawBuffer", float, 1, 0) @ind.func(target("dx.RawBuffer", flo
}
}
+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)
+ 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);
+ }
+ }
+}
+
+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
``````````
</details>
https://github.com/llvm/llvm-project/pull/130356
More information about the llvm-commits
mailing list