Skip to content

[DirectX] Gather resource names in DXIL resource analysis #140633

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 8 commits into from
May 28, 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
15 changes: 9 additions & 6 deletions llvm/include/llvm/Analysis/DXILResource.h
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,6 @@
#include "llvm/Support/Alignment.h"
#include "llvm/Support/Compiler.h"
#include "llvm/Support/DXILABI.h"
#include <climits>
#include <cstdint>

namespace llvm {
Expand All @@ -33,6 +32,10 @@ class DXILResourceTypeMap;

namespace dxil {

// Returns the resource name from dx_resource_handlefrombinding or
// dx_resource_handlefromimplicitbinding call
StringRef getResourceNameFromBindingCall(CallInst *CI);

/// The dx.RawBuffer target extension type
///
/// `target("dx.RawBuffer", Type, IsWriteable, IsROV)`
Expand Down Expand Up @@ -360,17 +363,18 @@ class ResourceInfo {
private:
ResourceBinding Binding;
TargetExtType *HandleTy;
StringRef Name;
Copy link
Contributor

Choose a reason for hiding this comment

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

The best reason I can see to include this here and not as part of the ResourceBinding member is to make it more readily accessible to getName, but I don't see that as being called at all? The other use of the name is in #140982 where it could be simplified as being part of the Binding compare instead of another parameter to std::tie. It works either way though.

Copy link
Contributor

Choose a reason for hiding this comment

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

I see that it is called for pretty print reasons, even so, the name could be retrieved from the binding member.

Copy link
Member Author

Choose a reason for hiding this comment

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

The name is also used for generating DXIL metadata related to resources (#140635) and for diagnostics. The ResourceBinding struct contains information related to the binding, I don't think the name should be included in the struct.

GlobalVariable *Symbol = nullptr;

public:
bool GloballyCoherent = false;
ResourceCounterDirection CounterDirection = ResourceCounterDirection::Unknown;

ResourceInfo(uint32_t RecordID, uint32_t Space, uint32_t LowerBound,
uint32_t Size, TargetExtType *HandleTy,
uint32_t Size, TargetExtType *HandleTy, StringRef Name = "",
GlobalVariable *Symbol = nullptr)
: Binding{RecordID, Space, LowerBound, Size}, HandleTy(HandleTy),
Symbol(Symbol) {}
Name(Name), Symbol(Symbol) {}

void setBindingID(unsigned ID) { Binding.RecordID = ID; }

Expand All @@ -380,11 +384,10 @@ class ResourceInfo {

const ResourceBinding &getBinding() const { return Binding; }
TargetExtType *getHandleTy() const { return HandleTy; }
StringRef getName() const { return Symbol ? Symbol->getName() : ""; }
const StringRef getName() const { return Name; }

bool hasSymbol() const { return Symbol; }
LLVM_ABI GlobalVariable *createSymbol(Module &M, StructType *Ty,
StringRef Name = "");
LLVM_ABI GlobalVariable *createSymbol(Module &M, StructType *Ty);
LLVM_ABI MDTuple *getAsMetadata(Module &M, dxil::ResourceTypeInfo &RTI) const;

LLVM_ABI std::pair<uint32_t, uint32_t>
Expand Down
36 changes: 32 additions & 4 deletions llvm/lib/Analysis/DXILResource.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,6 @@
#include "llvm/IR/Module.h"
#include "llvm/InitializePasses.h"
#include "llvm/Support/FormatVariadic.h"
#include <climits>
#include <cstdint>
#include <optional>

Expand Down Expand Up @@ -531,8 +530,7 @@ void ResourceTypeInfo::print(raw_ostream &OS, const DataLayout &DL) const {
}
}

GlobalVariable *ResourceInfo::createSymbol(Module &M, StructType *Ty,
StringRef Name) {
GlobalVariable *ResourceInfo::createSymbol(Module &M, StructType *Ty) {
assert(!Symbol && "Symbol has already been created");
Symbol = new GlobalVariable(M, Ty, /*isConstant=*/true,
GlobalValue::ExternalLinkage,
Expand Down Expand Up @@ -659,6 +657,9 @@ ResourceInfo::getAnnotateProps(Module &M, dxil::ResourceTypeInfo &RTI) const {

void ResourceInfo::print(raw_ostream &OS, dxil::ResourceTypeInfo &RTI,
const DataLayout &DL) const {
if (!Name.empty())
OS << " Name: " << Name << "\n";

if (Symbol) {
OS << " Symbol: ";
Symbol->printAsOperand(OS);
Expand Down Expand Up @@ -706,6 +707,30 @@ static bool isUpdateCounterIntrinsic(Function &F) {
return F.getIntrinsicID() == Intrinsic::dx_resource_updatecounter;
}

StringRef dxil::getResourceNameFromBindingCall(CallInst *CI) {
Value *Op = nullptr;
switch (CI->getCalledFunction()->getIntrinsicID()) {
default:
llvm_unreachable("unexpected handle creation intrinsic");
case Intrinsic::dx_resource_handlefrombinding:
case Intrinsic::dx_resource_handlefromimplicitbinding:
Op = CI->getArgOperand(5);
break;
}

auto *GV = dyn_cast<llvm::GlobalVariable>(Op);
if (!GV)
return "";

auto *CA = dyn_cast<ConstantDataArray>(GV->getInitializer());
assert(CA && CA->isString() && "expected constant string");
StringRef Name = CA->getAsString();
// strip trailing 0
if (Name.ends_with('\0'))
Name = Name.drop_back(1);
return Name;
}

void DXILResourceMap::populateResourceInfos(Module &M,
DXILResourceTypeMap &DRTM) {
SmallVector<std::tuple<CallInst *, ResourceInfo, ResourceTypeInfo>> CIToInfos;
Expand All @@ -731,8 +756,11 @@ void DXILResourceMap::populateResourceInfos(Module &M,
cast<ConstantInt>(CI->getArgOperand(1))->getZExtValue();
uint32_t Size =
cast<ConstantInt>(CI->getArgOperand(2))->getZExtValue();
StringRef Name = getResourceNameFromBindingCall(CI);

ResourceInfo RI =
ResourceInfo{/*RecordID=*/0, Space, LowerBound, Size, HandleTy};
ResourceInfo{/*RecordID=*/0, Space, LowerBound,
Size, HandleTy, Name};

CIToInfos.emplace_back(CI, RI, RTI);
}
Expand Down
39 changes: 29 additions & 10 deletions llvm/test/Analysis/DXILResource/buffer-frombinding.ll
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,22 @@

@G = external constant <4 x float>, align 4

@Zero.str = private unnamed_addr constant [5 x i8] c"Zero\00", align 1
@One.str = private unnamed_addr constant [4 x i8] c"One\00", align 1
@Two.str = private unnamed_addr constant [4 x i8] c"Two\00", align 1
@Three.str = private unnamed_addr constant [6 x i8] c"Three\00", align 1
@Four.str = private unnamed_addr constant [5 x i8] c"Four\00", align 1
@Array.str = private unnamed_addr constant [6 x i8] c"Array\00", align 1
@Five.str = private unnamed_addr constant [5 x i8] c"Five\00", align 1
@CB.str = private unnamed_addr constant [3 x i8] c"CB\00", align 1
@Constants.str = private unnamed_addr constant [10 x i8] c"Constants\00", align 1

define void @test_typedbuffer() {
; ByteAddressBuffer Buf : register(t8, space1)
%srv0 = call target("dx.RawBuffer", void, 0, 0)
@llvm.dx.resource.handlefrombinding(i32 1, i32 8, i32 1, i32 0, i1 false, ptr null)
@llvm.dx.resource.handlefrombinding(i32 1, i32 8, i32 1, i32 0, i1 false, ptr @Zero.str)
; CHECK: Resource [[SRV0:[0-9]+]]:
; CHECK: Name: Zero
; CHECK: Binding:
; CHECK: Record ID: 0
; CHECK: Space: 1
Expand All @@ -18,8 +29,9 @@ 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(i32 4, i32 2, i32 1, i32 0, i1 false, ptr null)
@llvm.dx.resource.handlefrombinding(i32 4, i32 2, i32 1, i32 0, i1 false, ptr @One.str)
; CHECK: Resource [[SRV1:[0-9]+]]:
; CHECK: Name: One
; CHECK: Binding:
; CHECK: Record ID: 1
; CHECK: Space: 4
Expand All @@ -32,8 +44,9 @@ 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(i32 5, i32 3, i32 24, i32 0, i1 false, ptr null)
@llvm.dx.resource.handlefrombinding(i32 5, i32 3, i32 24, i32 0, i1 false, ptr @Two.str)
; CHECK: Resource [[SRV2:[0-9]+]]:
; CHECK: Name: Two
; CHECK: Binding:
; CHECK: Record ID: 2
; CHECK: Space: 5
Expand All @@ -46,8 +59,9 @@ define void @test_typedbuffer() {

; RWBuffer<int> Buf : register(u7, space2)
%uav0 = call target("dx.TypedBuffer", i32, 1, 0, 1)
@llvm.dx.resource.handlefrombinding(i32 2, i32 7, i32 1, i32 0, i1 false, ptr null)
@llvm.dx.resource.handlefrombinding(i32 2, i32 7, i32 1, i32 0, i1 false, ptr @Three.str)
; CHECK: Resource [[UAV0:[0-9]+]]:
; CHECK: Name: Three
; CHECK: Binding:
; CHECK: Record ID: 0
; CHECK: Space: 2
Expand All @@ -63,9 +77,10 @@ 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(i32 3, i32 5, i32 1, i32 0, i1 false, ptr null)
@llvm.dx.resource.handlefrombinding(i32 3, i32 5, i32 1, i32 0, i1 false, ptr @Four.str)
call i32 @llvm.dx.resource.updatecounter(target("dx.TypedBuffer", <4 x float>, 1, 0, 0) %uav1, i8 -1)
; CHECK: Resource [[UAV1:[0-9]+]]:
; CHECK: Name: Four
; CHECK: Binding:
; CHECK: Record ID: 1
; CHECK: Space: 3
Expand All @@ -82,12 +97,13 @@ 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(i32 4, i32 0, i32 10, i32 0, i1 false, ptr null)
@llvm.dx.resource.handlefrombinding(i32 4, i32 0, i32 10, i32 0, i1 false, ptr @Array.str)
; RWBuffer<float4> Buf = BufferArray[5]
%uav2_2 = call target("dx.TypedBuffer", <4 x float>, 1, 0, 0)
@llvm.dx.resource.handlefrombinding(i32 4, i32 0, i32 10, i32 5, i1 false, ptr null)
@llvm.dx.resource.handlefrombinding(i32 4, i32 0, i32 10, i32 5, i1 false, ptr @Array.str)
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: Name: Array
; CHECK: Binding:
; CHECK: Record ID: 2
; CHECK: Space: 4
Expand All @@ -103,10 +119,11 @@ define void @test_typedbuffer() {

; 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, ptr null)
@llvm.dx.resource.handlefrombinding(i32 5, i32 0, i32 1, i32 0, i1 false, ptr @Five.str)
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: Name: Five
; CHECK: Binding:
; CHECK: Record ID: 3
; CHECK: Space: 5
Expand All @@ -121,8 +138,9 @@ 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, ptr null)
@llvm.dx.resource.handlefrombinding(i32 1, i32 0, i32 1, i32 0, i1 false, ptr @CB.str)
; CHECK: Resource [[CB0:[0-9]+]]:
; CHECK: Name: CB
; CHECK: Binding:
; CHECK: Record ID: 0
; CHECK: Space: 1
Expand All @@ -133,8 +151,9 @@ 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, ptr null)
@llvm.dx.resource.handlefrombinding(i32 1, i32 8, i32 1, i32 0, i1 false, ptr @Constants.str)
; CHECK: Resource [[CB1:[0-9]+]]:
; CHECK: Name: Constants
; CHECK: Binding:
; CHECK: Record ID: 1
; CHECK: Space: 1
Expand Down
Loading