[llvm-branch-commits] [llvm] [AMDGPU] Pre-commit num_records of arbitrary width tests for LowerBufferFatPointers (PR #217137)
Krzysztof Drewniak via llvm-branch-commits
llvm-branch-commits at lists.llvm.org
Tue Aug 25 08:05:57 PDT 2026
https://github.com/krzysz00 updated https://github.com/llvm/llvm-project/pull/217137
>From 8c98f8d1cdd230ca0e96a61ff62f5d4aa2dc8269 Mon Sep 17 00:00:00 2001
From: Krzysztof Drewniak <Krzysztof.Drewniak at amd.com>
Date: Tue, 18 Aug 2026 19:32:28 +0000
Subject: [PATCH 1/3] [AMDGPU] Pre-commit num_records of arbitrary width tests
for LowerBufferFatPointers
Add tests to ensure that the reasoning for whether an access can be
partially out of bounds and needs to be scalarized work correctly when
num_records has a width different from the hardware width.
AI disclosure: Claude generated these and I've looked at them
---
...r-buffer-fat-pointers-num-records-width.ll | 236 ++++++++++++++++++
1 file changed, 236 insertions(+)
create mode 100644 llvm/test/CodeGen/AMDGPU/lower-buffer-fat-pointers-num-records-width.ll
diff --git a/llvm/test/CodeGen/AMDGPU/lower-buffer-fat-pointers-num-records-width.ll b/llvm/test/CodeGen/AMDGPU/lower-buffer-fat-pointers-num-records-width.ll
new file mode 100644
index 0000000000000..851cb7fd87336
--- /dev/null
+++ b/llvm/test/CodeGen/AMDGPU/lower-buffer-fat-pointers-num-records-width.ll
@@ -0,0 +1,236 @@
+; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --version 6
+; RUN: opt -S -passes=amdgpu-lower-buffer-fat-pointers -mtriple=amdgpu9.00-- -mattr=+unaligned-access-mode < %s | FileCheck %s --check-prefixes=CHECK,RECORDS32
+; RUN: opt -S -passes=amdgpu-lower-buffer-fat-pointers -mtriple=amdgpu12.50-- -mattr=+unaligned-access-mode < %s | FileCheck %s --check-prefixes=CHECK,RECORDS45
+;; alignment reasons instead.
+; RUN: opt -S -passes=amdgpu-lower-buffer-fat-pointers -mtriple=amdgcn-- -mattr=+unaligned-access-mode,+unaligned-buffer-access < %s | FileCheck %s --check-prefixes=CHECK,UNKNOWN
+
+; Ensure that "this isn't out of bounds" tests work correctly even when
+; when size manipulation is needed.
+
+define <8 x half> @bound_i64_2p44(ptr addrspace(1) inreg %ptr, i32 %off) {
+; CHECK-LABEL: define <8 x half> @bound_i64_2p44(
+; CHECK-SAME: ptr addrspace(1) inreg [[PTR:%.*]], i32 [[OFF:%.*]]) #[[ATTR0:[0-9]+]] {
+; CHECK-NEXT: [[BUF:%.*]] = call ptr addrspace(8) @llvm.amdgcn.make.buffer.rsrc.p8.p1.i64(ptr addrspace(1) [[PTR]], i16 0, i64 17592186044416, i32 0)
+; CHECK-NEXT: [[Q:%.*]] = call i32 @llvm.umin.i32(i32 [[OFF]], i32 1024)
+; CHECK-NEXT: [[RET:%.*]] = call <8 x half> @llvm.amdgcn.raw.ptr.buffer.load.v8f16(ptr addrspace(8) align 2 [[BUF]], i32 [[Q]], i32 0, i32 0)
+; CHECK-NEXT: ret <8 x half> [[RET]]
+;
+ %buf = call ptr addrspace(8) @llvm.amdgcn.make.buffer.rsrc.p8.p1.i64(ptr addrspace(1) %ptr, i16 0, i64 17592186044416, i32 0)
+ %p = addrspacecast ptr addrspace(8) %buf to ptr addrspace(7)
+ %off.clamped = call i32 @llvm.umin.i32(i32 %off, i32 1024)
+ %q = getelementptr i8, ptr addrspace(7) %p, i32 %off.clamped
+ %ret = load <8 x half>, ptr addrspace(7) %q, align 2
+ ret <8 x half> %ret
+}
+
+define <8 x half> @bound_i45_2p44(ptr addrspace(1) inreg %ptr, i32 %off) {
+; RECORDS32-LABEL: define <8 x half> @bound_i45_2p44(
+; RECORDS32-SAME: ptr addrspace(1) inreg [[PTR:%.*]], i32 [[OFF:%.*]]) #[[ATTR0]] {
+; RECORDS32-NEXT: [[BUF:%.*]] = call ptr addrspace(8) @llvm.amdgcn.make.buffer.rsrc.p8.p1.i45(ptr addrspace(1) [[PTR]], i16 0, i45 -17592186044416, i32 0)
+; RECORDS32-NEXT: [[Q:%.*]] = call i32 @llvm.umin.i32(i32 [[OFF]], i32 1024)
+; RECORDS32-NEXT: [[RET:%.*]] = call <8 x half> @llvm.amdgcn.raw.ptr.buffer.load.v8f16(ptr addrspace(8) align 2 [[BUF]], i32 [[Q]], i32 0, i32 0)
+; RECORDS32-NEXT: ret <8 x half> [[RET]]
+;
+; RECORDS45-LABEL: define <8 x half> @bound_i45_2p44(
+; RECORDS45-SAME: ptr addrspace(1) inreg [[PTR:%.*]], i32 [[OFF:%.*]]) #[[ATTR0]] {
+; RECORDS45-NEXT: [[BUF:%.*]] = call ptr addrspace(8) @llvm.amdgcn.make.buffer.rsrc.p8.p1.i45(ptr addrspace(1) [[PTR]], i16 0, i45 -17592186044416, i32 0)
+; RECORDS45-NEXT: [[Q:%.*]] = call i32 @llvm.umin.i32(i32 [[OFF]], i32 1024)
+; RECORDS45-NEXT: [[RET_OFF_0:%.*]] = call half @llvm.amdgcn.raw.ptr.buffer.load.f16(ptr addrspace(8) align 2 [[BUF]], i32 [[Q]], i32 0, i32 0)
+; RECORDS45-NEXT: [[RET_SLICE_0:%.*]] = insertelement <8 x half> poison, half [[RET_OFF_0]], i64 0
+; RECORDS45-NEXT: [[Q_OFF_PTR_2:%.*]] = add i32 [[Q]], 2
+; RECORDS45-NEXT: [[RET_OFF_2:%.*]] = call half @llvm.amdgcn.raw.ptr.buffer.load.f16(ptr addrspace(8) align 2 [[BUF]], i32 [[Q_OFF_PTR_2]], i32 0, i32 0)
+; RECORDS45-NEXT: [[RET_SLICE_1:%.*]] = insertelement <8 x half> [[RET_SLICE_0]], half [[RET_OFF_2]], i64 1
+; RECORDS45-NEXT: [[Q_OFF_PTR_4:%.*]] = add i32 [[Q]], 4
+; RECORDS45-NEXT: [[RET_OFF_4:%.*]] = call half @llvm.amdgcn.raw.ptr.buffer.load.f16(ptr addrspace(8) align 2 [[BUF]], i32 [[Q_OFF_PTR_4]], i32 0, i32 0)
+; RECORDS45-NEXT: [[RET_SLICE_2:%.*]] = insertelement <8 x half> [[RET_SLICE_1]], half [[RET_OFF_4]], i64 2
+; RECORDS45-NEXT: [[Q_OFF_PTR_6:%.*]] = add i32 [[Q]], 6
+; RECORDS45-NEXT: [[RET_OFF_6:%.*]] = call half @llvm.amdgcn.raw.ptr.buffer.load.f16(ptr addrspace(8) align 2 [[BUF]], i32 [[Q_OFF_PTR_6]], i32 0, i32 0)
+; RECORDS45-NEXT: [[RET_SLICE_3:%.*]] = insertelement <8 x half> [[RET_SLICE_2]], half [[RET_OFF_6]], i64 3
+; RECORDS45-NEXT: [[Q_OFF_PTR_8:%.*]] = add i32 [[Q]], 8
+; RECORDS45-NEXT: [[RET_OFF_8:%.*]] = call half @llvm.amdgcn.raw.ptr.buffer.load.f16(ptr addrspace(8) align 2 [[BUF]], i32 [[Q_OFF_PTR_8]], i32 0, i32 0)
+; RECORDS45-NEXT: [[RET_SLICE_4:%.*]] = insertelement <8 x half> [[RET_SLICE_3]], half [[RET_OFF_8]], i64 4
+; RECORDS45-NEXT: [[Q_OFF_PTR_10:%.*]] = add i32 [[Q]], 10
+; RECORDS45-NEXT: [[RET_OFF_10:%.*]] = call half @llvm.amdgcn.raw.ptr.buffer.load.f16(ptr addrspace(8) align 2 [[BUF]], i32 [[Q_OFF_PTR_10]], i32 0, i32 0)
+; RECORDS45-NEXT: [[RET_SLICE_5:%.*]] = insertelement <8 x half> [[RET_SLICE_4]], half [[RET_OFF_10]], i64 5
+; RECORDS45-NEXT: [[Q_OFF_PTR_12:%.*]] = add i32 [[Q]], 12
+; RECORDS45-NEXT: [[RET_OFF_12:%.*]] = call half @llvm.amdgcn.raw.ptr.buffer.load.f16(ptr addrspace(8) align 2 [[BUF]], i32 [[Q_OFF_PTR_12]], i32 0, i32 0)
+; RECORDS45-NEXT: [[RET_SLICE_6:%.*]] = insertelement <8 x half> [[RET_SLICE_5]], half [[RET_OFF_12]], i64 6
+; RECORDS45-NEXT: [[Q_OFF_PTR_14:%.*]] = add i32 [[Q]], 14
+; RECORDS45-NEXT: [[RET_OFF_14:%.*]] = call half @llvm.amdgcn.raw.ptr.buffer.load.f16(ptr addrspace(8) align 2 [[BUF]], i32 [[Q_OFF_PTR_14]], i32 0, i32 0)
+; RECORDS45-NEXT: [[RET:%.*]] = insertelement <8 x half> [[RET_SLICE_6]], half [[RET_OFF_14]], i64 7
+; RECORDS45-NEXT: ret <8 x half> [[RET]]
+;
+; UNKNOWN-LABEL: define <8 x half> @bound_i45_2p44(
+; UNKNOWN-SAME: ptr addrspace(1) inreg [[PTR:%.*]], i32 [[OFF:%.*]]) #[[ATTR0]] {
+; UNKNOWN-NEXT: [[BUF:%.*]] = call ptr addrspace(8) @llvm.amdgcn.make.buffer.rsrc.p8.p1.i45(ptr addrspace(1) [[PTR]], i16 0, i45 -17592186044416, i32 0)
+; UNKNOWN-NEXT: [[Q:%.*]] = call i32 @llvm.umin.i32(i32 [[OFF]], i32 1024)
+; UNKNOWN-NEXT: [[RET:%.*]] = call <8 x half> @llvm.amdgcn.raw.ptr.buffer.load.v8f16(ptr addrspace(8) align 2 [[BUF]], i32 [[Q]], i32 0, i32 0)
+; UNKNOWN-NEXT: ret <8 x half> [[RET]]
+;
+ %buf = call ptr addrspace(8) @llvm.amdgcn.make.buffer.rsrc.p8.p1.i45(ptr addrspace(1) %ptr, i16 0, i45 17592186044416, i32 0)
+ %p = addrspacecast ptr addrspace(8) %buf to ptr addrspace(7)
+ %off.clamped = call i32 @llvm.umin.i32(i32 %off, i32 1024)
+ %q = getelementptr i8, ptr addrspace(7) %p, i32 %off.clamped
+ %ret = load <8 x half>, ptr addrspace(7) %q, align 2
+ ret <8 x half> %ret
+}
+
+define <8 x half> @bound_i32_2p31(ptr addrspace(1) inreg %ptr, i32 %off) {
+; CHECK-LABEL: define <8 x half> @bound_i32_2p31(
+; CHECK-SAME: ptr addrspace(1) inreg [[PTR:%.*]], i32 [[OFF:%.*]]) #[[ATTR0]] {
+; CHECK-NEXT: [[BUF:%.*]] = call ptr addrspace(8) @llvm.amdgcn.make.buffer.rsrc.p8.p1.i32(ptr addrspace(1) [[PTR]], i16 0, i32 -2147483648, i32 0)
+; CHECK-NEXT: [[Q:%.*]] = call i32 @llvm.umin.i32(i32 [[OFF]], i32 1024)
+; CHECK-NEXT: [[RET_OFF_0:%.*]] = call half @llvm.amdgcn.raw.ptr.buffer.load.f16(ptr addrspace(8) align 2 [[BUF]], i32 [[Q]], i32 0, i32 0)
+; CHECK-NEXT: [[RET_SLICE_0:%.*]] = insertelement <8 x half> poison, half [[RET_OFF_0]], i64 0
+; CHECK-NEXT: [[Q_OFF_PTR_2:%.*]] = add i32 [[Q]], 2
+; CHECK-NEXT: [[RET_OFF_2:%.*]] = call half @llvm.amdgcn.raw.ptr.buffer.load.f16(ptr addrspace(8) align 2 [[BUF]], i32 [[Q_OFF_PTR_2]], i32 0, i32 0)
+; CHECK-NEXT: [[RET_SLICE_1:%.*]] = insertelement <8 x half> [[RET_SLICE_0]], half [[RET_OFF_2]], i64 1
+; CHECK-NEXT: [[Q_OFF_PTR_4:%.*]] = add i32 [[Q]], 4
+; CHECK-NEXT: [[RET_OFF_4:%.*]] = call half @llvm.amdgcn.raw.ptr.buffer.load.f16(ptr addrspace(8) align 2 [[BUF]], i32 [[Q_OFF_PTR_4]], i32 0, i32 0)
+; CHECK-NEXT: [[RET_SLICE_2:%.*]] = insertelement <8 x half> [[RET_SLICE_1]], half [[RET_OFF_4]], i64 2
+; CHECK-NEXT: [[Q_OFF_PTR_6:%.*]] = add i32 [[Q]], 6
+; CHECK-NEXT: [[RET_OFF_6:%.*]] = call half @llvm.amdgcn.raw.ptr.buffer.load.f16(ptr addrspace(8) align 2 [[BUF]], i32 [[Q_OFF_PTR_6]], i32 0, i32 0)
+; CHECK-NEXT: [[RET_SLICE_3:%.*]] = insertelement <8 x half> [[RET_SLICE_2]], half [[RET_OFF_6]], i64 3
+; CHECK-NEXT: [[Q_OFF_PTR_8:%.*]] = add i32 [[Q]], 8
+; CHECK-NEXT: [[RET_OFF_8:%.*]] = call half @llvm.amdgcn.raw.ptr.buffer.load.f16(ptr addrspace(8) align 2 [[BUF]], i32 [[Q_OFF_PTR_8]], i32 0, i32 0)
+; CHECK-NEXT: [[RET_SLICE_4:%.*]] = insertelement <8 x half> [[RET_SLICE_3]], half [[RET_OFF_8]], i64 4
+; CHECK-NEXT: [[Q_OFF_PTR_10:%.*]] = add i32 [[Q]], 10
+; CHECK-NEXT: [[RET_OFF_10:%.*]] = call half @llvm.amdgcn.raw.ptr.buffer.load.f16(ptr addrspace(8) align 2 [[BUF]], i32 [[Q_OFF_PTR_10]], i32 0, i32 0)
+; CHECK-NEXT: [[RET_SLICE_5:%.*]] = insertelement <8 x half> [[RET_SLICE_4]], half [[RET_OFF_10]], i64 5
+; CHECK-NEXT: [[Q_OFF_PTR_12:%.*]] = add i32 [[Q]], 12
+; CHECK-NEXT: [[RET_OFF_12:%.*]] = call half @llvm.amdgcn.raw.ptr.buffer.load.f16(ptr addrspace(8) align 2 [[BUF]], i32 [[Q_OFF_PTR_12]], i32 0, i32 0)
+; CHECK-NEXT: [[RET_SLICE_6:%.*]] = insertelement <8 x half> [[RET_SLICE_5]], half [[RET_OFF_12]], i64 6
+; CHECK-NEXT: [[Q_OFF_PTR_14:%.*]] = add i32 [[Q]], 14
+; CHECK-NEXT: [[RET_OFF_14:%.*]] = call half @llvm.amdgcn.raw.ptr.buffer.load.f16(ptr addrspace(8) align 2 [[BUF]], i32 [[Q_OFF_PTR_14]], i32 0, i32 0)
+; CHECK-NEXT: [[RET:%.*]] = insertelement <8 x half> [[RET_SLICE_6]], half [[RET_OFF_14]], i64 7
+; CHECK-NEXT: ret <8 x half> [[RET]]
+;
+ %buf = call ptr addrspace(8) @llvm.amdgcn.make.buffer.rsrc.p8.p1.i32(ptr addrspace(1) %ptr, i16 0, i32 2147483648, i32 0)
+ %p = addrspacecast ptr addrspace(8) %buf to ptr addrspace(7)
+ %off.clamped = call i32 @llvm.umin.i32(i32 %off, i32 1024)
+ %q = getelementptr i8, ptr addrspace(7) %p, i32 %off.clamped
+ %ret = load <8 x half>, ptr addrspace(7) %q, align 2
+ ret <8 x half> %ret
+}
+
+;; The two tests below use num_records values that are equal modulo 2^32 but
+;; that differ as 45-bit quantities, with a maximum offset that falls between
+;; those two bounds. Therefore, on targets with a 32-bit num_records, both
+;; loads can be partially out of bounds and must be scalarized, while on
+;; targets with a 45-bit num_records, only the i32 one can be.
+
+define <8 x half> @bound_i32_2p11(ptr addrspace(1) inreg %ptr, i32 %off) {
+; CHECK-LABEL: define <8 x half> @bound_i32_2p11(
+; CHECK-SAME: ptr addrspace(1) inreg [[PTR:%.*]], i32 [[OFF:%.*]]) #[[ATTR0]] {
+; CHECK-NEXT: [[BUF:%.*]] = call ptr addrspace(8) @llvm.amdgcn.make.buffer.rsrc.p8.p1.i32(ptr addrspace(1) [[PTR]], i16 0, i32 2048, i32 0)
+; CHECK-NEXT: [[Q:%.*]] = call i32 @llvm.umin.i32(i32 [[OFF]], i32 4096)
+; CHECK-NEXT: [[RET_OFF_0:%.*]] = call half @llvm.amdgcn.raw.ptr.buffer.load.f16(ptr addrspace(8) align 2 [[BUF]], i32 [[Q]], i32 0, i32 0)
+; CHECK-NEXT: [[RET_SLICE_0:%.*]] = insertelement <8 x half> poison, half [[RET_OFF_0]], i64 0
+; CHECK-NEXT: [[Q_OFF_PTR_2:%.*]] = add i32 [[Q]], 2
+; CHECK-NEXT: [[RET_OFF_2:%.*]] = call half @llvm.amdgcn.raw.ptr.buffer.load.f16(ptr addrspace(8) align 2 [[BUF]], i32 [[Q_OFF_PTR_2]], i32 0, i32 0)
+; CHECK-NEXT: [[RET_SLICE_1:%.*]] = insertelement <8 x half> [[RET_SLICE_0]], half [[RET_OFF_2]], i64 1
+; CHECK-NEXT: [[Q_OFF_PTR_4:%.*]] = add i32 [[Q]], 4
+; CHECK-NEXT: [[RET_OFF_4:%.*]] = call half @llvm.amdgcn.raw.ptr.buffer.load.f16(ptr addrspace(8) align 2 [[BUF]], i32 [[Q_OFF_PTR_4]], i32 0, i32 0)
+; CHECK-NEXT: [[RET_SLICE_2:%.*]] = insertelement <8 x half> [[RET_SLICE_1]], half [[RET_OFF_4]], i64 2
+; CHECK-NEXT: [[Q_OFF_PTR_6:%.*]] = add i32 [[Q]], 6
+; CHECK-NEXT: [[RET_OFF_6:%.*]] = call half @llvm.amdgcn.raw.ptr.buffer.load.f16(ptr addrspace(8) align 2 [[BUF]], i32 [[Q_OFF_PTR_6]], i32 0, i32 0)
+; CHECK-NEXT: [[RET_SLICE_3:%.*]] = insertelement <8 x half> [[RET_SLICE_2]], half [[RET_OFF_6]], i64 3
+; CHECK-NEXT: [[Q_OFF_PTR_8:%.*]] = add i32 [[Q]], 8
+; CHECK-NEXT: [[RET_OFF_8:%.*]] = call half @llvm.amdgcn.raw.ptr.buffer.load.f16(ptr addrspace(8) align 2 [[BUF]], i32 [[Q_OFF_PTR_8]], i32 0, i32 0)
+; CHECK-NEXT: [[RET_SLICE_4:%.*]] = insertelement <8 x half> [[RET_SLICE_3]], half [[RET_OFF_8]], i64 4
+; CHECK-NEXT: [[Q_OFF_PTR_10:%.*]] = add i32 [[Q]], 10
+; CHECK-NEXT: [[RET_OFF_10:%.*]] = call half @llvm.amdgcn.raw.ptr.buffer.load.f16(ptr addrspace(8) align 2 [[BUF]], i32 [[Q_OFF_PTR_10]], i32 0, i32 0)
+; CHECK-NEXT: [[RET_SLICE_5:%.*]] = insertelement <8 x half> [[RET_SLICE_4]], half [[RET_OFF_10]], i64 5
+; CHECK-NEXT: [[Q_OFF_PTR_12:%.*]] = add i32 [[Q]], 12
+; CHECK-NEXT: [[RET_OFF_12:%.*]] = call half @llvm.amdgcn.raw.ptr.buffer.load.f16(ptr addrspace(8) align 2 [[BUF]], i32 [[Q_OFF_PTR_12]], i32 0, i32 0)
+; CHECK-NEXT: [[RET_SLICE_6:%.*]] = insertelement <8 x half> [[RET_SLICE_5]], half [[RET_OFF_12]], i64 6
+; CHECK-NEXT: [[Q_OFF_PTR_14:%.*]] = add i32 [[Q]], 14
+; CHECK-NEXT: [[RET_OFF_14:%.*]] = call half @llvm.amdgcn.raw.ptr.buffer.load.f16(ptr addrspace(8) align 2 [[BUF]], i32 [[Q_OFF_PTR_14]], i32 0, i32 0)
+; CHECK-NEXT: [[RET:%.*]] = insertelement <8 x half> [[RET_SLICE_6]], half [[RET_OFF_14]], i64 7
+; CHECK-NEXT: ret <8 x half> [[RET]]
+;
+ %buf = call ptr addrspace(8) @llvm.amdgcn.make.buffer.rsrc.p8.p1.i32(ptr addrspace(1) %ptr, i16 0, i32 2048, i32 0)
+ %p = addrspacecast ptr addrspace(8) %buf to ptr addrspace(7)
+ %off.clamped = call i32 @llvm.umin.i32(i32 %off, i32 4096)
+ %q = getelementptr i8, ptr addrspace(7) %p, i32 %off.clamped
+ %ret = load <8 x half>, ptr addrspace(7) %q, align 2
+ ret <8 x half> %ret
+}
+
+define <8 x half> @bound_i45_2p32_plus_2p11(ptr addrspace(1) inreg %ptr, i32 %off) {
+; RECORDS32-LABEL: define <8 x half> @bound_i45_2p32_plus_2p11(
+; RECORDS32-SAME: ptr addrspace(1) inreg [[PTR:%.*]], i32 [[OFF:%.*]]) #[[ATTR0]] {
+; RECORDS32-NEXT: [[BUF:%.*]] = call ptr addrspace(8) @llvm.amdgcn.make.buffer.rsrc.p8.p1.i45(ptr addrspace(1) [[PTR]], i16 0, i45 4294969344, i32 0)
+; RECORDS32-NEXT: [[Q:%.*]] = call i32 @llvm.umin.i32(i32 [[OFF]], i32 4096)
+; RECORDS32-NEXT: [[RET_OFF_0:%.*]] = call half @llvm.amdgcn.raw.ptr.buffer.load.f16(ptr addrspace(8) align 2 [[BUF]], i32 [[Q]], i32 0, i32 0)
+; RECORDS32-NEXT: [[RET_SLICE_0:%.*]] = insertelement <8 x half> poison, half [[RET_OFF_0]], i64 0
+; RECORDS32-NEXT: [[Q_OFF_PTR_2:%.*]] = add i32 [[Q]], 2
+; RECORDS32-NEXT: [[RET_OFF_2:%.*]] = call half @llvm.amdgcn.raw.ptr.buffer.load.f16(ptr addrspace(8) align 2 [[BUF]], i32 [[Q_OFF_PTR_2]], i32 0, i32 0)
+; RECORDS32-NEXT: [[RET_SLICE_1:%.*]] = insertelement <8 x half> [[RET_SLICE_0]], half [[RET_OFF_2]], i64 1
+; RECORDS32-NEXT: [[Q_OFF_PTR_4:%.*]] = add i32 [[Q]], 4
+; RECORDS32-NEXT: [[RET_OFF_4:%.*]] = call half @llvm.amdgcn.raw.ptr.buffer.load.f16(ptr addrspace(8) align 2 [[BUF]], i32 [[Q_OFF_PTR_4]], i32 0, i32 0)
+; RECORDS32-NEXT: [[RET_SLICE_2:%.*]] = insertelement <8 x half> [[RET_SLICE_1]], half [[RET_OFF_4]], i64 2
+; RECORDS32-NEXT: [[Q_OFF_PTR_6:%.*]] = add i32 [[Q]], 6
+; RECORDS32-NEXT: [[RET_OFF_6:%.*]] = call half @llvm.amdgcn.raw.ptr.buffer.load.f16(ptr addrspace(8) align 2 [[BUF]], i32 [[Q_OFF_PTR_6]], i32 0, i32 0)
+; RECORDS32-NEXT: [[RET_SLICE_3:%.*]] = insertelement <8 x half> [[RET_SLICE_2]], half [[RET_OFF_6]], i64 3
+; RECORDS32-NEXT: [[Q_OFF_PTR_8:%.*]] = add i32 [[Q]], 8
+; RECORDS32-NEXT: [[RET_OFF_8:%.*]] = call half @llvm.amdgcn.raw.ptr.buffer.load.f16(ptr addrspace(8) align 2 [[BUF]], i32 [[Q_OFF_PTR_8]], i32 0, i32 0)
+; RECORDS32-NEXT: [[RET_SLICE_4:%.*]] = insertelement <8 x half> [[RET_SLICE_3]], half [[RET_OFF_8]], i64 4
+; RECORDS32-NEXT: [[Q_OFF_PTR_10:%.*]] = add i32 [[Q]], 10
+; RECORDS32-NEXT: [[RET_OFF_10:%.*]] = call half @llvm.amdgcn.raw.ptr.buffer.load.f16(ptr addrspace(8) align 2 [[BUF]], i32 [[Q_OFF_PTR_10]], i32 0, i32 0)
+; RECORDS32-NEXT: [[RET_SLICE_5:%.*]] = insertelement <8 x half> [[RET_SLICE_4]], half [[RET_OFF_10]], i64 5
+; RECORDS32-NEXT: [[Q_OFF_PTR_12:%.*]] = add i32 [[Q]], 12
+; RECORDS32-NEXT: [[RET_OFF_12:%.*]] = call half @llvm.amdgcn.raw.ptr.buffer.load.f16(ptr addrspace(8) align 2 [[BUF]], i32 [[Q_OFF_PTR_12]], i32 0, i32 0)
+; RECORDS32-NEXT: [[RET_SLICE_6:%.*]] = insertelement <8 x half> [[RET_SLICE_5]], half [[RET_OFF_12]], i64 6
+; RECORDS32-NEXT: [[Q_OFF_PTR_14:%.*]] = add i32 [[Q]], 14
+; RECORDS32-NEXT: [[RET_OFF_14:%.*]] = call half @llvm.amdgcn.raw.ptr.buffer.load.f16(ptr addrspace(8) align 2 [[BUF]], i32 [[Q_OFF_PTR_14]], i32 0, i32 0)
+; RECORDS32-NEXT: [[RET:%.*]] = insertelement <8 x half> [[RET_SLICE_6]], half [[RET_OFF_14]], i64 7
+; RECORDS32-NEXT: ret <8 x half> [[RET]]
+;
+; RECORDS45-LABEL: define <8 x half> @bound_i45_2p32_plus_2p11(
+; RECORDS45-SAME: ptr addrspace(1) inreg [[PTR:%.*]], i32 [[OFF:%.*]]) #[[ATTR0]] {
+; RECORDS45-NEXT: [[BUF:%.*]] = call ptr addrspace(8) @llvm.amdgcn.make.buffer.rsrc.p8.p1.i45(ptr addrspace(1) [[PTR]], i16 0, i45 4294969344, i32 0)
+; RECORDS45-NEXT: [[Q:%.*]] = call i32 @llvm.umin.i32(i32 [[OFF]], i32 4096)
+; RECORDS45-NEXT: [[RET:%.*]] = call <8 x half> @llvm.amdgcn.raw.ptr.buffer.load.v8f16(ptr addrspace(8) align 2 [[BUF]], i32 [[Q]], i32 0, i32 0)
+; RECORDS45-NEXT: ret <8 x half> [[RET]]
+;
+; UNKNOWN-LABEL: define <8 x half> @bound_i45_2p32_plus_2p11(
+; UNKNOWN-SAME: ptr addrspace(1) inreg [[PTR:%.*]], i32 [[OFF:%.*]]) #[[ATTR0]] {
+; UNKNOWN-NEXT: [[BUF:%.*]] = call ptr addrspace(8) @llvm.amdgcn.make.buffer.rsrc.p8.p1.i45(ptr addrspace(1) [[PTR]], i16 0, i45 4294969344, i32 0)
+; UNKNOWN-NEXT: [[Q:%.*]] = call i32 @llvm.umin.i32(i32 [[OFF]], i32 4096)
+; UNKNOWN-NEXT: [[RET_OFF_0:%.*]] = call half @llvm.amdgcn.raw.ptr.buffer.load.f16(ptr addrspace(8) align 2 [[BUF]], i32 [[Q]], i32 0, i32 0)
+; UNKNOWN-NEXT: [[RET_SLICE_0:%.*]] = insertelement <8 x half> poison, half [[RET_OFF_0]], i64 0
+; UNKNOWN-NEXT: [[Q_OFF_PTR_2:%.*]] = add i32 [[Q]], 2
+; UNKNOWN-NEXT: [[RET_OFF_2:%.*]] = call half @llvm.amdgcn.raw.ptr.buffer.load.f16(ptr addrspace(8) align 2 [[BUF]], i32 [[Q_OFF_PTR_2]], i32 0, i32 0)
+; UNKNOWN-NEXT: [[RET_SLICE_1:%.*]] = insertelement <8 x half> [[RET_SLICE_0]], half [[RET_OFF_2]], i64 1
+; UNKNOWN-NEXT: [[Q_OFF_PTR_4:%.*]] = add i32 [[Q]], 4
+; UNKNOWN-NEXT: [[RET_OFF_4:%.*]] = call half @llvm.amdgcn.raw.ptr.buffer.load.f16(ptr addrspace(8) align 2 [[BUF]], i32 [[Q_OFF_PTR_4]], i32 0, i32 0)
+; UNKNOWN-NEXT: [[RET_SLICE_2:%.*]] = insertelement <8 x half> [[RET_SLICE_1]], half [[RET_OFF_4]], i64 2
+; UNKNOWN-NEXT: [[Q_OFF_PTR_6:%.*]] = add i32 [[Q]], 6
+; UNKNOWN-NEXT: [[RET_OFF_6:%.*]] = call half @llvm.amdgcn.raw.ptr.buffer.load.f16(ptr addrspace(8) align 2 [[BUF]], i32 [[Q_OFF_PTR_6]], i32 0, i32 0)
+; UNKNOWN-NEXT: [[RET_SLICE_3:%.*]] = insertelement <8 x half> [[RET_SLICE_2]], half [[RET_OFF_6]], i64 3
+; UNKNOWN-NEXT: [[Q_OFF_PTR_8:%.*]] = add i32 [[Q]], 8
+; UNKNOWN-NEXT: [[RET_OFF_8:%.*]] = call half @llvm.amdgcn.raw.ptr.buffer.load.f16(ptr addrspace(8) align 2 [[BUF]], i32 [[Q_OFF_PTR_8]], i32 0, i32 0)
+; UNKNOWN-NEXT: [[RET_SLICE_4:%.*]] = insertelement <8 x half> [[RET_SLICE_3]], half [[RET_OFF_8]], i64 4
+; UNKNOWN-NEXT: [[Q_OFF_PTR_10:%.*]] = add i32 [[Q]], 10
+; UNKNOWN-NEXT: [[RET_OFF_10:%.*]] = call half @llvm.amdgcn.raw.ptr.buffer.load.f16(ptr addrspace(8) align 2 [[BUF]], i32 [[Q_OFF_PTR_10]], i32 0, i32 0)
+; UNKNOWN-NEXT: [[RET_SLICE_5:%.*]] = insertelement <8 x half> [[RET_SLICE_4]], half [[RET_OFF_10]], i64 5
+; UNKNOWN-NEXT: [[Q_OFF_PTR_12:%.*]] = add i32 [[Q]], 12
+; UNKNOWN-NEXT: [[RET_OFF_12:%.*]] = call half @llvm.amdgcn.raw.ptr.buffer.load.f16(ptr addrspace(8) align 2 [[BUF]], i32 [[Q_OFF_PTR_12]], i32 0, i32 0)
+; UNKNOWN-NEXT: [[RET_SLICE_6:%.*]] = insertelement <8 x half> [[RET_SLICE_5]], half [[RET_OFF_12]], i64 6
+; UNKNOWN-NEXT: [[Q_OFF_PTR_14:%.*]] = add i32 [[Q]], 14
+; UNKNOWN-NEXT: [[RET_OFF_14:%.*]] = call half @llvm.amdgcn.raw.ptr.buffer.load.f16(ptr addrspace(8) align 2 [[BUF]], i32 [[Q_OFF_PTR_14]], i32 0, i32 0)
+; UNKNOWN-NEXT: [[RET:%.*]] = insertelement <8 x half> [[RET_SLICE_6]], half [[RET_OFF_14]], i64 7
+; UNKNOWN-NEXT: ret <8 x half> [[RET]]
+;
+ %buf = call ptr addrspace(8) @llvm.amdgcn.make.buffer.rsrc.p8.p1.i45(ptr addrspace(1) %ptr, i16 0, i45 4294969344, i32 0)
+ %p = addrspacecast ptr addrspace(8) %buf to ptr addrspace(7)
+ %off.clamped = call i32 @llvm.umin.i32(i32 %off, i32 4096)
+ %q = getelementptr i8, ptr addrspace(7) %p, i32 %off.clamped
+ %ret = load <8 x half>, ptr addrspace(7) %q, align 2
+ ret <8 x half> %ret
+}
+
+!llvm.module.flags = !{!0}
+;; Strict buffer OOB mode
+!0 = !{i32 7, !"amdgpu.buffer.oob.mode", i32 2}
>From f7258eab861321cfe599eff0a465b96c57fcf5c4 Mon Sep 17 00:00:00 2001
From: Krzysztof Drewniak <Krzysztof.Drewniak at amd.com>
Date: Tue, 18 Aug 2026 21:45:56 +0000
Subject: [PATCH 2/3] Update generic target to something better
---
.../AMDGPU/lower-buffer-fat-pointers-num-records-width.ll | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/llvm/test/CodeGen/AMDGPU/lower-buffer-fat-pointers-num-records-width.ll b/llvm/test/CodeGen/AMDGPU/lower-buffer-fat-pointers-num-records-width.ll
index 851cb7fd87336..cb51c48b01a42 100644
--- a/llvm/test/CodeGen/AMDGPU/lower-buffer-fat-pointers-num-records-width.ll
+++ b/llvm/test/CodeGen/AMDGPU/lower-buffer-fat-pointers-num-records-width.ll
@@ -2,7 +2,7 @@
; RUN: opt -S -passes=amdgpu-lower-buffer-fat-pointers -mtriple=amdgpu9.00-- -mattr=+unaligned-access-mode < %s | FileCheck %s --check-prefixes=CHECK,RECORDS32
; RUN: opt -S -passes=amdgpu-lower-buffer-fat-pointers -mtriple=amdgpu12.50-- -mattr=+unaligned-access-mode < %s | FileCheck %s --check-prefixes=CHECK,RECORDS45
;; alignment reasons instead.
-; RUN: opt -S -passes=amdgpu-lower-buffer-fat-pointers -mtriple=amdgcn-- -mattr=+unaligned-access-mode,+unaligned-buffer-access < %s | FileCheck %s --check-prefixes=CHECK,UNKNOWN
+; RUN: opt -S -passes=amdgpu-lower-buffer-fat-pointers -mtriple=amdgpu-- -mattr=+unaligned-access-mode,+unaligned-buffer-access < %s | FileCheck %s --check-prefixes=CHECK,UNKNOWN
; Ensure that "this isn't out of bounds" tests work correctly even when
; when size manipulation is needed.
>From 9dd56903a96add0aed956286190f92ab1133eea1 Mon Sep 17 00:00:00 2001
From: Krzysztof Drewniak <Krzysztof.Drewniak at amd.com>
Date: Tue, 25 Aug 2026 15:04:39 +0000
Subject: [PATCH 3/3] Update test explanations
---
.../lower-buffer-fat-pointers-num-records-width.ll | 12 +++++-------
1 file changed, 5 insertions(+), 7 deletions(-)
diff --git a/llvm/test/CodeGen/AMDGPU/lower-buffer-fat-pointers-num-records-width.ll b/llvm/test/CodeGen/AMDGPU/lower-buffer-fat-pointers-num-records-width.ll
index cb51c48b01a42..e6aace5be6d36 100644
--- a/llvm/test/CodeGen/AMDGPU/lower-buffer-fat-pointers-num-records-width.ll
+++ b/llvm/test/CodeGen/AMDGPU/lower-buffer-fat-pointers-num-records-width.ll
@@ -1,12 +1,12 @@
; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --version 6
; RUN: opt -S -passes=amdgpu-lower-buffer-fat-pointers -mtriple=amdgpu9.00-- -mattr=+unaligned-access-mode < %s | FileCheck %s --check-prefixes=CHECK,RECORDS32
; RUN: opt -S -passes=amdgpu-lower-buffer-fat-pointers -mtriple=amdgpu12.50-- -mattr=+unaligned-access-mode < %s | FileCheck %s --check-prefixes=CHECK,RECORDS45
-;; alignment reasons instead.
; RUN: opt -S -passes=amdgpu-lower-buffer-fat-pointers -mtriple=amdgpu-- -mattr=+unaligned-access-mode,+unaligned-buffer-access < %s | FileCheck %s --check-prefixes=CHECK,UNKNOWN
; Ensure that "this isn't out of bounds" tests work correctly even when
; when size manipulation is needed.
+;; Make sure this always works with 2^44, even on 32-bit num_records.
define <8 x half> @bound_i64_2p44(ptr addrspace(1) inreg %ptr, i32 %off) {
; CHECK-LABEL: define <8 x half> @bound_i64_2p44(
; CHECK-SAME: ptr addrspace(1) inreg [[PTR:%.*]], i32 [[OFF:%.*]]) #[[ATTR0:[0-9]+]] {
@@ -23,6 +23,7 @@ define <8 x half> @bound_i64_2p44(ptr addrspace(1) inreg %ptr, i32 %off) {
ret <8 x half> %ret
}
+;; And when it's given as an i45.
define <8 x half> @bound_i45_2p44(ptr addrspace(1) inreg %ptr, i32 %off) {
; RECORDS32-LABEL: define <8 x half> @bound_i45_2p44(
; RECORDS32-SAME: ptr addrspace(1) inreg [[PTR:%.*]], i32 [[OFF:%.*]]) #[[ATTR0]] {
@@ -75,6 +76,7 @@ define <8 x half> @bound_i45_2p44(ptr addrspace(1) inreg %ptr, i32 %off) {
ret <8 x half> %ret
}
+;; Bound is int32_max.
define <8 x half> @bound_i32_2p31(ptr addrspace(1) inreg %ptr, i32 %off) {
; CHECK-LABEL: define <8 x half> @bound_i32_2p31(
; CHECK-SAME: ptr addrspace(1) inreg [[PTR:%.*]], i32 [[OFF:%.*]]) #[[ATTR0]] {
@@ -113,12 +115,8 @@ define <8 x half> @bound_i32_2p31(ptr addrspace(1) inreg %ptr, i32 %off) {
ret <8 x half> %ret
}
-;; The two tests below use num_records values that are equal modulo 2^32 but
-;; that differ as 45-bit quantities, with a maximum offset that falls between
-;; those two bounds. Therefore, on targets with a 32-bit num_records, both
-;; loads can be partially out of bounds and must be scalarized, while on
-;; targets with a 45-bit num_records, only the i32 one can be.
-
+;; Test cases where the num_records mod 2^32 would lead to requiring
+;; scalarization, but not if we read num_records as a 45-bit value.
define <8 x half> @bound_i32_2p11(ptr addrspace(1) inreg %ptr, i32 %off) {
; CHECK-LABEL: define <8 x half> @bound_i32_2p11(
; CHECK-SAME: ptr addrspace(1) inreg [[PTR:%.*]], i32 [[OFF:%.*]]) #[[ATTR0]] {
More information about the llvm-branch-commits
mailing list