[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
This commit is contained in:
Finn Plummer 2026-03-03 11:34:50 -08:00 committed by GitHub
parent b5baf5e062
commit 899080a87a
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
3 changed files with 56 additions and 5 deletions

View File

@ -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``

View File

@ -1067,15 +1067,18 @@ void DXILResourceBindingInfo::populate(Module &M, DXILResourceTypeMap &DRTM) {
cast<ConstantInt>(CI->getArgOperand(0))->getZExtValue();
uint32_t LowerBound =
cast<ConstantInt>(CI->getArgOperand(1))->getZExtValue();
int32_t Size =
uint32_t Size =
cast<ConstantInt>(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);
}

View File

@ -0,0 +1,48 @@
; RUN: opt -S -disable-output -passes="print<dxil-resources>" %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<uint4> 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<float4> 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) }