From 899080a87ad96d5f590ad8bb469b9a33e6de6795 Mon Sep 17 00:00:00 2001 From: Finn Plummer Date: Tue, 3 Mar 2026 11:34:50 -0800 Subject: [PATCH] [Analysis][DXILResource] Correct bound computation (#184198) The range is an unsigned integer where a value of `UINT32_MAX` denotes an unbounded range The current implementation implied that any size interpreted as a signed integer that is negative was unbounded, which is incorrect. Adds a note to the docs --- llvm/docs/DirectX/DXILResources.rst | 2 +- llvm/lib/Analysis/DXILResource.cpp | 11 +++-- .../buffer-frombinding-unbounded.ll | 48 +++++++++++++++++++ 3 files changed, 56 insertions(+), 5 deletions(-) create mode 100644 llvm/test/Analysis/DXILResource/buffer-frombinding-unbounded.ll diff --git a/llvm/docs/DirectX/DXILResources.rst b/llvm/docs/DirectX/DXILResources.rst index fb8d6fa580c6..d1841dfe0afc 100644 --- a/llvm/docs/DirectX/DXILResources.rst +++ b/llvm/docs/DirectX/DXILResources.rst @@ -191,7 +191,7 @@ arguments. * - ``%range_size`` - 3 - ``i32`` - - Range size of the binding. + - Range size of the binding, where ``UINT32_MAX (~0U)`` denotes an unbounded range. * - ``%index`` - 4 - ``i32`` diff --git a/llvm/lib/Analysis/DXILResource.cpp b/llvm/lib/Analysis/DXILResource.cpp index 033f516abe01..f01a6f80161a 100644 --- a/llvm/lib/Analysis/DXILResource.cpp +++ b/llvm/lib/Analysis/DXILResource.cpp @@ -1067,15 +1067,18 @@ void DXILResourceBindingInfo::populate(Module &M, DXILResourceTypeMap &DRTM) { cast(CI->getArgOperand(0))->getZExtValue(); uint32_t LowerBound = cast(CI->getArgOperand(1))->getZExtValue(); - int32_t Size = + uint32_t Size = cast(CI->getArgOperand(2))->getZExtValue(); Value *Name = CI->getArgOperand(4); - // negative size means unbounded resource array; + // UINT32_MAX (~0U) size means unbounded resource array; // upper bound register overflow should be detected in Sema - assert((Size < 0 || (unsigned)LowerBound + Size - 1 <= UINT32_MAX) && + assert((Size == UINT32_MAX || + (uint64_t)LowerBound + (uint64_t)Size - 1ULL <= + (uint64_t)UINT32_MAX) && "upper bound register overflow"); - uint32_t UpperBound = Size < 0 ? UINT32_MAX : LowerBound + Size - 1; + uint32_t UpperBound = + Size == UINT32_MAX ? UINT32_MAX : LowerBound + Size - 1; Builder.trackBinding(RTI.getResourceClass(), Space, LowerBound, UpperBound, Name); } diff --git a/llvm/test/Analysis/DXILResource/buffer-frombinding-unbounded.ll b/llvm/test/Analysis/DXILResource/buffer-frombinding-unbounded.ll new file mode 100644 index 000000000000..ee47bd4bb1bd --- /dev/null +++ b/llvm/test/Analysis/DXILResource/buffer-frombinding-unbounded.ll @@ -0,0 +1,48 @@ +; RUN: opt -S -disable-output -passes="print" %s 2>&1 | FileCheck %s + +@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 + +define void @test_typedbuffer() { + ; Buffer Buf[] : register(t0, space0) + %srv = call target("dx.TypedBuffer", <4 x i32>, 0, 0, 0) + @llvm.dx.resource.handlefrombinding(i32 0, i32 0, i32 -1, i32 0, ptr @One.str) + ; CHECK: Resource [[#SRV:]]: + ; CHECK: Name: One + ; CHECK: Binding: + ; CHECK: Record ID: 0 + ; CHECK: Space: 0 + ; CHECK: Lower Bound: 0 + ; CHECK: Size: 4294967295 + ; CHECK: Globally Coherent: 0 + ; CHECK: Counter Direction: Unknown + ; CHECK: Class: SRV + ; CHECK: Kind: Buffer + ; CHECK: Element Type: u32 + ; CHECK: Element Count: 4 + + ; RWBuffer BufferArray[4294967262] : register(u0, space0) + %uav = call target("dx.TypedBuffer", <4 x float>, 1, 0, 0) + @llvm.dx.resource.handlefrombinding(i32 0, i32 0, i32 4294967262, i32 0, ptr @Two.str) + ; CHECK: Resource [[#UAV:]]: + ; CHECK: Name: Two + ; CHECK: Binding: + ; CHECK: Record ID: 0 + ; CHECK: Space: 0 + ; CHECK: Lower Bound: 0 + ; CHECK: Size: 4294967262 + ; CHECK: Globally Coherent: 0 + ; CHECK: Counter Direction: Unknown + ; CHECK: Class: UAV + ; CHECK: Kind: Buffer + ; CHECK: IsROV: 0 + ; CHECK: Element Type: f32 + ; CHECK: Element Count: 4 + + ret void +} + +; CHECK-DAG: Call bound to [[#SRV]]: %srv = +; CHECK-DAG: Call bound to [[#UAV]]: %uav = + +attributes #0 = { nocallback nofree nosync nounwind willreturn memory(none) }