[llvm] f12fb2f - [HLSL] Analyze updateCounter usage (#135669)
via llvm-commits
llvm-commits at lists.llvm.org
Thu Apr 24 12:17:27 PDT 2025
Author: Ashley Coleman
Date: 2025-04-24T13:17:24-06:00
New Revision: f12fb2ff74ee2a1a5d7d4ae6ecc7dd1ee7b622cb
URL: https://github.com/llvm/llvm-project/commit/f12fb2ff74ee2a1a5d7d4ae6ecc7dd1ee7b622cb
DIFF: https://github.com/llvm/llvm-project/commit/f12fb2ff74ee2a1a5d7d4ae6ecc7dd1ee7b622cb.diff
LOG: [HLSL] Analyze updateCounter usage (#135669)
Fixes https://github.com/llvm/llvm-project/issues/135667
Analyze and annotate `ResourceInfo` with the derived direction of calls
to updateCounter (if any).
This change only sets the value. Any diagnostics that should be raised
must be done somewhere else.
Added:
Modified:
llvm/include/llvm/Analysis/DXILResource.h
llvm/lib/Analysis/DXILResource.cpp
llvm/test/Analysis/DXILResource/buffer-frombinding.ll
llvm/unittests/Target/DirectX/UniqueResourceFromUseTests.cpp
Removed:
################################################################################
diff --git a/llvm/include/llvm/Analysis/DXILResource.h b/llvm/include/llvm/Analysis/DXILResource.h
index 9f0b5f18d127d..1d871a448c16c 100644
--- a/llvm/include/llvm/Analysis/DXILResource.h
+++ b/llvm/include/llvm/Analysis/DXILResource.h
@@ -457,8 +457,19 @@ class DXILResourceMap {
unsigned FirstCBuffer = 0;
unsigned FirstSampler = 0;
- /// Populate the map given the resource binding calls in the given module.
+ /// Populate all the resource instance data.
void populate(Module &M, DXILResourceTypeMap &DRTM);
+ /// Populate the map given the resource binding calls in the given module.
+ void populateResourceInfos(Module &M, DXILResourceTypeMap &DRTM);
+ /// Analyze and populate the directions of the resource counters.
+ void populateCounterDirections(Module &M);
+
+ /// Resolves a resource handle into a vector of ResourceInfos that
+ /// represent the possible unique creations of the handle. Certain cases are
+ /// ambiguous so multiple creation instructions may be returned. The resulting
+ /// ResourceInfo can be used to depuplicate unique handles that
+ /// reference the same resource
+ SmallVector<dxil::ResourceInfo *> findByUse(const Value *Key);
public:
using iterator = SmallVector<dxil::ResourceInfo>::iterator;
@@ -476,13 +487,6 @@ class DXILResourceMap {
return Pos == CallMap.end() ? Infos.end() : (Infos.begin() + Pos->second);
}
- /// Resolves a resource handle into a vector of ResourceInfos that
- /// represent the possible unique creations of the handle. Certain cases are
- /// ambiguous so multiple creation instructions may be returned. The resulting
- /// ResourceInfo can be used to depuplicate unique handles that
- /// reference the same resource
- SmallVector<dxil::ResourceInfo> findByUse(const Value *Key) const;
-
const_iterator find(const CallInst *Key) const {
auto Pos = CallMap.find(Key);
return Pos == CallMap.end() ? Infos.end() : (Infos.begin() + Pos->second);
diff --git a/llvm/lib/Analysis/DXILResource.cpp b/llvm/lib/Analysis/DXILResource.cpp
index 6334f5d82213d..cc1d931c9e077 100644
--- a/llvm/lib/Analysis/DXILResource.cpp
+++ b/llvm/lib/Analysis/DXILResource.cpp
@@ -697,8 +697,12 @@ bool DXILResourceTypeMap::invalidate(Module &M, const PreservedAnalyses &PA,
}
//===----------------------------------------------------------------------===//
+static bool isUpdateCounterIntrinsic(Function &F) {
+ return F.getIntrinsicID() == Intrinsic::dx_resource_updatecounter;
+}
-void DXILResourceMap::populate(Module &M, DXILResourceTypeMap &DRTM) {
+void DXILResourceMap::populateResourceInfos(Module &M,
+ DXILResourceTypeMap &DRTM) {
SmallVector<std::tuple<CallInst *, ResourceInfo, ResourceTypeInfo>> CIToInfos;
for (Function &F : M.functions()) {
@@ -777,6 +781,48 @@ void DXILResourceMap::populate(Module &M, DXILResourceTypeMap &DRTM) {
}
}
+void DXILResourceMap::populateCounterDirections(Module &M) {
+ for (Function &F : M.functions()) {
+ if (!isUpdateCounterIntrinsic(F))
+ continue;
+
+ LLVM_DEBUG(dbgs() << "Update Counter Function: " << F.getName() << "\n");
+
+ 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 = cast<ConstantInt>(CountArg);
+ int64_t CountLiteral = CountValue->getSExtValue();
+
+ // 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;
+
+ // Collect all potential creation points for the handle arg
+ Value *HandleArg = CI->getArgOperand(0);
+ SmallVector<ResourceInfo *> RBInfos = findByUse(HandleArg);
+ for (ResourceInfo *RBInfo : RBInfos) {
+ if (RBInfo->CounterDirection == ResourceCounterDirection::Unknown)
+ RBInfo->CounterDirection = Direction;
+ else if (RBInfo->CounterDirection != Direction)
+ RBInfo->CounterDirection = ResourceCounterDirection::Invalid;
+ }
+ }
+ }
+}
+
+void DXILResourceMap::populate(Module &M, DXILResourceTypeMap &DRTM) {
+ populateResourceInfos(M, DRTM);
+ populateCounterDirections(M);
+}
+
void DXILResourceMap::print(raw_ostream &OS, DXILResourceTypeMap &DRTM,
const DataLayout &DL) const {
for (unsigned I = 0, E = Infos.size(); I != E; ++I) {
@@ -793,10 +839,9 @@ void DXILResourceMap::print(raw_ostream &OS, DXILResourceTypeMap &DRTM,
}
}
-SmallVector<dxil::ResourceInfo>
-DXILResourceMap::findByUse(const Value *Key) const {
+SmallVector<dxil::ResourceInfo *> DXILResourceMap::findByUse(const Value *Key) {
if (const PHINode *Phi = dyn_cast<PHINode>(Key)) {
- SmallVector<dxil::ResourceInfo> Children;
+ SmallVector<dxil::ResourceInfo *> Children;
for (const Value *V : Phi->operands()) {
Children.append(findByUse(V));
}
@@ -810,9 +855,9 @@ DXILResourceMap::findByUse(const Value *Key) const {
switch (CI->getIntrinsicID()) {
// Found the create, return the binding
case Intrinsic::dx_resource_handlefrombinding: {
- const auto *It = find(CI);
- assert(It != Infos.end() && "HandleFromBinding must be in resource map");
- return {*It};
+ auto Pos = CallMap.find(CI);
+ assert(Pos != CallMap.end() && "HandleFromBinding must be in resource map");
+ return {&Infos[Pos->second]};
}
default:
break;
@@ -821,7 +866,7 @@ DXILResourceMap::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::ResourceInfo> Children;
+ SmallVector<dxil::ResourceInfo *> Children;
for (const Value *V : CI->args()) {
if (V->getType() != UseType)
continue;
diff --git a/llvm/test/Analysis/DXILResource/buffer-frombinding.ll b/llvm/test/Analysis/DXILResource/buffer-frombinding.ll
index 81c8b5530afb6..378b1ff120885 100644
--- a/llvm/test/Analysis/DXILResource/buffer-frombinding.ll
+++ b/llvm/test/Analysis/DXILResource/buffer-frombinding.ll
@@ -5,8 +5,7 @@
define void @test_typedbuffer() {
; ByteAddressBuffer Buf : register(t8, space1)
%srv0 = call target("dx.RawBuffer", void, 0, 0)
- @llvm.dx.resource.handlefrombinding.tdx.RawBuffer_i8_0_0t(
- i32 1, i32 8, i32 1, i32 0, i1 false)
+ @llvm.dx.resource.handlefrombinding(i32 1, i32 8, i32 1, i32 0, i1 false)
; CHECK: Resource [[SRV0:[0-9]+]]:
; CHECK: Binding:
; CHECK: Record ID: 0
@@ -19,8 +18,7 @@ define void @test_typedbuffer() {
; struct S { float4 a; uint4 b; };
; StructuredBuffer<S> Buf : register(t2, space4)
%srv1 = call target("dx.RawBuffer", {<4 x float>, <4 x i32>}, 0, 0)
- @llvm.dx.resource.handlefrombinding.tdx.RawBuffer_sl_v4f32v4i32s_0_0t(
- i32 4, i32 2, i32 1, i32 0, i1 false)
+ @llvm.dx.resource.handlefrombinding(i32 4, i32 2, i32 1, i32 0, i1 false)
; CHECK: Resource [[SRV1:[0-9]+]]:
; CHECK: Binding:
; CHECK: Record ID: 1
@@ -34,8 +32,7 @@ define void @test_typedbuffer() {
; Buffer<uint4> Buf[24] : register(t3, space5)
%srv2 = call target("dx.TypedBuffer", <4 x i32>, 0, 0, 0)
- @llvm.dx.resource.handlefrombinding.tdx.TypedBuffer_i32_0_0t(
- i32 5, i32 3, i32 24, i32 0, i1 false)
+ @llvm.dx.resource.handlefrombinding(i32 5, i32 3, i32 24, i32 0, i1 false)
; CHECK: Resource [[SRV2:[0-9]+]]:
; CHECK: Binding:
; CHECK: Record ID: 2
@@ -49,8 +46,7 @@ define void @test_typedbuffer() {
; RWBuffer<int> Buf : register(u7, space2)
%uav0 = call target("dx.TypedBuffer", i32, 1, 0, 1)
- @llvm.dx.resource.handlefrombinding.tdx.TypedBuffer_i32_1_0t(
- i32 2, i32 7, i32 1, i32 0, i1 false)
+ @llvm.dx.resource.handlefrombinding(i32 2, i32 7, i32 1, i32 0, i1 false)
; CHECK: Resource [[UAV0:[0-9]+]]:
; CHECK: Binding:
; CHECK: Record ID: 0
@@ -67,8 +63,8 @@ define void @test_typedbuffer() {
; RWBuffer<float4> Buf : register(u5, space3)
%uav1 = call target("dx.TypedBuffer", <4 x float>, 1, 0, 0)
- @llvm.dx.resource.handlefrombinding.tdx.TypedBuffer_f32_1_0(
- i32 3, i32 5, i32 1, i32 0, i1 false)
+ @llvm.dx.resource.handlefrombinding(i32 3, i32 5, i32 1, i32 0, i1 false)
+ call i32 @llvm.dx.resource.updatecounter(target("dx.TypedBuffer", <4 x float>, 1, 0, 0) %uav1, i8 -1)
; CHECK: Resource [[UAV1:[0-9]+]]:
; CHECK: Binding:
; CHECK: Record ID: 1
@@ -76,7 +72,7 @@ define void @test_typedbuffer() {
; CHECK: Lower Bound: 5
; CHECK: Size: 1
; CHECK: Globally Coherent: 0
- ; CHECK: Counter Direction: Unknown
+ ; CHECK: Counter Direction: Decrement
; CHECK: Class: UAV
; CHECK: Kind: TypedBuffer
; CHECK: IsROV: 0
@@ -86,12 +82,11 @@ define void @test_typedbuffer() {
; RWBuffer<float4> BufferArray[10] : register(u0, space4)
; RWBuffer<float4> Buf = BufferArray[0]
%uav2_1 = call target("dx.TypedBuffer", <4 x float>, 1, 0, 0)
- @llvm.dx.resource.handlefrombinding.tdx.TypedBuffer_f32_1_0(
- i32 4, i32 0, i32 10, i32 0, i1 false)
+ @llvm.dx.resource.handlefrombinding(i32 4, i32 0, i32 10, i32 0, i1 false)
; RWBuffer<float4> Buf = BufferArray[5]
%uav2_2 = call target("dx.TypedBuffer", <4 x float>, 1, 0, 0)
- @llvm.dx.resource.handlefrombinding.tdx.TypedBuffer_f32_1_0(
- i32 4, i32 0, i32 10, i32 5, i1 false)
+ @llvm.dx.resource.handlefrombinding(i32 4, i32 0, i32 10, i32 5, i1 false)
+ call i32 @llvm.dx.resource.updatecounter(target("dx.TypedBuffer", <4 x float>, 1, 0, 0) %uav2_2, i8 1)
; CHECK: Resource [[UAV2:[0-9]+]]:
; CHECK: Binding:
; CHECK: Record ID: 2
@@ -99,7 +94,26 @@ define void @test_typedbuffer() {
; CHECK: Lower Bound: 0
; CHECK: Size: 10
; CHECK: Globally Coherent: 0
- ; CHECK: Counter Direction: Unknown
+ ; CHECK: Counter Direction: Increment
+ ; CHECK: Class: UAV
+ ; CHECK: Kind: TypedBuffer
+ ; CHECK: IsROV: 0
+ ; CHECK: Element Type: f32
+ ; CHECK: Element Count: 4
+
+ ; RWBuffer<float4> Buf : register(u0, space5)
+ %uav3 = call target("dx.TypedBuffer", <4 x float>, 1, 0, 0)
+ @llvm.dx.resource.handlefrombinding(i32 5, i32 0, i32 1, i32 0, i1 false)
+ call i32 @llvm.dx.resource.updatecounter(target("dx.TypedBuffer", <4 x float>, 1, 0, 0) %uav3, i8 -1)
+ call i32 @llvm.dx.resource.updatecounter(target("dx.TypedBuffer", <4 x float>, 1, 0, 0) %uav3, i8 1)
+ ; CHECK: Resource [[UAV3:[0-9]+]]:
+ ; CHECK: Binding:
+ ; CHECK: Record ID: 3
+ ; CHECK: Space: 5
+ ; CHECK: Lower Bound: 0
+ ; CHECK: Size: 1
+ ; CHECK: Globally Coherent: 0
+ ; CHECK: Counter Direction: Invalid
; CHECK: Class: UAV
; CHECK: Kind: TypedBuffer
; CHECK: IsROV: 0
@@ -107,7 +121,7 @@ define void @test_typedbuffer() {
; CHECK: Element Count: 4
%cb0 = call target("dx.CBuffer", {float})
- @llvm.dx.resource.handlefrombinding(i32 1, i32 0, i32 1, i32 0, i1 false)
+ @llvm.dx.resource.handlefrombinding(i32 1, i32 0, i32 1, i32 0, i1 false)
; CHECK: Resource [[CB0:[0-9]+]]:
; CHECK: Binding:
; CHECK: Record ID: 0
@@ -119,7 +133,7 @@ define void @test_typedbuffer() {
; CHECK: CBuffer size: 4
%cb1 = call target("dx.CBuffer", target("dx.Layout", {float}, 4, 0))
- @llvm.dx.resource.handlefrombinding(i32 1, i32 8, i32 1, i32 0, i1 false)
+ @llvm.dx.resource.handlefrombinding(i32 1, i32 8, i32 1, i32 0, i1 false)
; CHECK: Resource [[CB1:[0-9]+]]:
; CHECK: Binding:
; CHECK: Record ID: 1
diff --git a/llvm/unittests/Target/DirectX/UniqueResourceFromUseTests.cpp b/llvm/unittests/Target/DirectX/UniqueResourceFromUseTests.cpp
index 675a3dc19b912..249e1045b847f 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"
@@ -28,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);
@@ -37,246 +39,169 @@ class UniqueResourceFromUseTest : public testing::Test {
MAM->registerPass([&] { return DXILResourceAnalysis(); });
}
+ 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;
}
};
-TEST_F(UniqueResourceFromUseTest, TestTrivialUse) {
+// 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() {
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)
- call void @a.func(target("dx.RawBuffer", float, 1, 0) %handle)
+ %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)
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)
)";
- LLVMContext Context;
- SMDiagnostic Error;
- auto M = parseAssemblyString(Assembly, Error, Context);
- ASSERT_TRUE(M) << "Bad assembly?";
+ auto M = parseAsm(Assembly);
+
+ DXILResourceMap &DRM = MAM->getResult<DXILResourceAnalysis>(*M);
- const DXILResourceMap &DRM = MAM->getResult<DXILResourceAnalysis>(*M);
for (const Function &F : M->functions()) {
- if (F.getName() != "a.func") {
+ if (F.getIntrinsicID() != Intrinsic::dx_resource_handlefrombinding)
continue;
- }
-
- unsigned CalledResources = 0;
for (const User *U : F.users()) {
const CallInst *CI = cast<CallInst>(U);
- const Value *Handle = CI->getArgOperand(0);
- const auto Bindings = DRM.findByUse(Handle);
- ASSERT_EQ(Bindings.size(), 1u)
- << "Handle should resolve into one resource";
-
- auto Binding = Bindings[0].getBinding();
- EXPECT_EQ(0u, Binding.RecordID);
- EXPECT_EQ(1u, Binding.Space);
- EXPECT_EQ(2u, Binding.LowerBound);
- EXPECT_EQ(3u, Binding.Size);
-
- CalledResources++;
+ const auto *const Binding = DRM.find(CI);
+ ASSERT_EQ(Binding->CounterDirection, ResourceCounterDirection::Decrement);
}
-
- EXPECT_EQ(2u, CalledResources)
- << "Expected 2 resolved call to create resource";
}
}
-TEST_F(UniqueResourceFromUseTest, TestIndirectUse) {
+// 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 @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)
- %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)
- call void @a.func(target("dx.RawBuffer", float, 1, 0) %handle4)
+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)
+ call i32 @llvm.dx.resource.updatecounter(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 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);
+
+ DXILResourceMap &DRM = MAM->getResult<DXILResourceAnalysis>(*M);
- const DXILResourceMap &DRM = MAM->getResult<DXILResourceAnalysis>(*M);
for (const Function &F : M->functions()) {
- if (F.getName() != "a.func") {
+ if (F.getIntrinsicID() != Intrinsic::dx_resource_handlefrombinding)
continue;
- }
-
- unsigned CalledResources = 0;
for (const User *U : F.users()) {
const CallInst *CI = cast<CallInst>(U);
- const Value *Handle = CI->getArgOperand(0);
- const auto Bindings = DRM.findByUse(Handle);
- ASSERT_EQ(Bindings.size(), 1u)
- << "Handle should resolve into one resource";
-
- auto Binding = Bindings[0].getBinding();
- EXPECT_EQ(0u, Binding.RecordID);
- EXPECT_EQ(1u, Binding.Space);
- EXPECT_EQ(2u, Binding.LowerBound);
- EXPECT_EQ(3u, Binding.Size);
-
- CalledResources++;
+ const auto *const Binding = DRM.find(CI);
+ ASSERT_EQ(Binding->CounterDirection, ResourceCounterDirection::Increment);
}
-
- EXPECT_EQ(1u, CalledResources)
- << "Expected 1 resolved call to create resource";
}
}
-TEST_F(UniqueResourceFromUseTest, TestAmbigousIndirectUse) {
+// 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 @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)
- %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)
- call void @a.func(target("dx.RawBuffer", float, 1, 0) %handle)
+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)
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)
)";
- LLVMContext Context;
- SMDiagnostic Error;
- auto M = parseAssemblyString(Assembly, Error, Context);
- ASSERT_TRUE(M) << "Bad assembly?";
+ auto M = parseAsm(Assembly);
+
+ DXILResourceMap &DRM = MAM->getResult<DXILResourceAnalysis>(*M);
- const DXILResourceMap &DRM = MAM->getResult<DXILResourceAnalysis>(*M);
for (const Function &F : M->functions()) {
- if (F.getName() != "a.func") {
+ if (F.getIntrinsicID() != Intrinsic::dx_resource_handlefrombinding)
continue;
- }
-
- unsigned CalledResources = 0;
for (const User *U : F.users()) {
const CallInst *CI = cast<CallInst>(U);
- const Value *Handle = CI->getArgOperand(0);
- const auto Bindings = DRM.findByUse(Handle);
- ASSERT_EQ(Bindings.size(), 4u)
- << "Handle should resolve into four resources";
-
- 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();
- EXPECT_EQ(1u, Binding.RecordID);
- EXPECT_EQ(2u, Binding.Space);
- EXPECT_EQ(2u, Binding.LowerBound);
- EXPECT_EQ(2u, Binding.Size);
-
- 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();
- EXPECT_EQ(3u, Binding.RecordID);
- EXPECT_EQ(4u, Binding.Space);
- EXPECT_EQ(4u, Binding.LowerBound);
- EXPECT_EQ(4u, Binding.Size);
-
- CalledResources++;
+ const auto *const Binding = DRM.find(CI);
+ ASSERT_EQ(Binding->CounterDirection, ResourceCounterDirection::Unknown);
}
-
- EXPECT_EQ(1u, CalledResources)
- << "Expected 1 resolved call to create resource";
}
}
-TEST_F(UniqueResourceFromUseTest, TestConditionalUse) {
+// Test that multiple
diff erent resources with unique incs/decs aren't
+// marked invalid
+TEST_F(UniqueResourceFromUseTest, TestResourceCounterMultiple) {
StringRef Assembly = R"(
-define void @foo(i32 %n) {
+define void @main() {
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)
- %cond = icmp eq i32 %n, 0
- br i1 %cond, label %bb.true, label %bb.false
-
-bb.true:
- %handle_t = call target("dx.RawBuffer", float, 1, 0) @ind.func(target("dx.RawBuffer", float, 1, 0) %x)
- br label %bb.exit
-
-bb.false:
- %handle_f = call target("dx.RawBuffer", float, 1, 0) @ind.func(target("dx.RawBuffer", float, 1, 0) %y)
- br label %bb.exit
-
-bb.exit:
- %handle = phi target("dx.RawBuffer", float, 1, 0) [ %handle_t, %bb.true ], [ %handle_f, %bb.false ]
- call void @a.func(target("dx.RawBuffer", float, 1, 0) %handle)
+ %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)
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)
)";
- LLVMContext Context;
- SMDiagnostic Error;
- auto M = parseAssemblyString(Assembly, Error, Context);
- ASSERT_TRUE(M) << "Bad assembly?";
+ auto M = parseAsm(Assembly);
+
+ DXILResourceMap &DRM = MAM->getResult<DXILResourceAnalysis>(*M);
+
+ ResourceCounterDirection Dirs[2] = {ResourceCounterDirection::Decrement,
+ ResourceCounterDirection::Increment};
+ ResourceCounterDirection *Dir = Dirs;
- const DXILResourceMap &DRM = MAM->getResult<DXILResourceAnalysis>(*M);
for (const Function &F : M->functions()) {
- if (F.getName() != "a.func") {
+ if (F.getIntrinsicID() != Intrinsic::dx_resource_handlefrombinding)
continue;
+
+ uint32_t ExpectedDirsIndex = 0;
+ for (const User *U : F.users()) {
+ const CallInst *CI = cast<CallInst>(U);
+ const auto *const Binding = DRM.find(CI);
+ ASSERT_TRUE(ExpectedDirsIndex < 2);
+ ASSERT_EQ(Binding->CounterDirection, Dir[ExpectedDirsIndex]);
+ ExpectedDirsIndex++;
}
+ }
+}
- unsigned CalledResources = 0;
+// Test that single
diff erent 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);
+
+ DXILResourceMap &DRM = MAM->getResult<DXILResourceAnalysis>(*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 Value *Handle = CI->getArgOperand(0);
- const auto Bindings = DRM.findByUse(Handle);
- ASSERT_EQ(Bindings.size(), 2u)
- << "Handle should resolve into four resources";
-
- 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();
- EXPECT_EQ(1u, Binding.RecordID);
- EXPECT_EQ(4u, Binding.Space);
- EXPECT_EQ(4u, Binding.LowerBound);
- EXPECT_EQ(4u, Binding.Size);
-
- CalledResources++;
+ const auto *const Binding = DRM.find(CI);
+ ASSERT_EQ(Binding->CounterDirection, ResourceCounterDirection::Invalid);
}
-
- EXPECT_EQ(1u, CalledResources)
- << "Expected 1 resolved call to create resource";
}
}
More information about the llvm-commits
mailing list