Skip to content

[HLSL] Analyze updateCounter usage #135669

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 4 commits into from
Apr 24, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
20 changes: 12 additions & 8 deletions llvm/include/llvm/Analysis/DXILResource.h
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -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);
Expand Down
61 changes: 53 additions & 8 deletions llvm/lib/Analysis/DXILResource.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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()) {
Expand Down Expand Up @@ -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;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What does this case mean? The CounterDirection was previously set and was wrong? Or there is conflicting information?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Conflicting information!

If CounterDirection is detected as both Increment and Decrement that is considered invalid (because only one direction is allowed)

}
}
}
}

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) {
Expand All @@ -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));
}
Expand All @@ -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;
Expand All @@ -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;
Expand Down
50 changes: 32 additions & 18 deletions llvm/test/Analysis/DXILResource/buffer-frombinding.ll
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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
Expand All @@ -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
Expand All @@ -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
Expand All @@ -67,16 +63,16 @@ 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
; CHECK: Space: 3
; 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
Expand All @@ -86,28 +82,46 @@ 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
; CHECK: Space: 4
; 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
; CHECK: Element Type: f32
; 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
Expand All @@ -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
Expand Down
Loading
Loading