[llvm] [SPIRV] Legalize byte-buffer reinterpretation ptrcasts (#192523) (PR #212999)
Farzon Lotfi via llvm-commits
llvm-commits at lists.llvm.org
Mon Aug 24 20:28:43 PDT 2026
================
@@ -76,3 +76,288 @@ entry:
}
attributes #0 = { "hlsl.numthreads"="1,1,1" "hlsl.shader"="compute" }
+
+ at .str = private unnamed_addr constant [4 x i8] c"Buf\00", align 1
+
+declare target("spirv.VulkanBuffer", [0 x i8], 12, 0) @llvm.spv.resource.handlefrombinding(i32, i32, i32, i32, ptr)
+declare ptr addrspace(11) @llvm.spv.resource.getpointer(target("spirv.VulkanBuffer", [0 x i8], 12, 0), i32)
+
+; Byte-addressable buffer tests model Clang's SPIR-V resource layout for HLSL
+; ByteAddressBuffer/RWByteAddressBuffer: the handle carries [0 x i8] as the
+; OpTypeRuntimeArray element type for storage-buffer blocks. That i8 names
+; byte-addressable layout in LLVM IR; it is not an HLSL surface type. Typed
+; HLSL accesses (e.g. Store(offset, uint)) lower to i32 load/store at a byte
+; offset in getpointer's index operand. emit-intrinsics tags getpointer as i8
+; from the layout, then inserts i8->T spv_ptrcast for the typed access;
+; legalize-pointer-cast removes the ptrcast and keeps the typed access.
+
+define void @byteBufferStore() {
+; CHECK-LABEL: define void @byteBufferStore(
+; CHECK-NOT: call {{.*}}@llvm.spv.ptrcast
+; CHECK: store i8 42, ptr addrspace(11)
+; CHECK: call ptr addrspace(11) @llvm.spv.resource.getpointer{{.*}} i32 1)
+; CHECK: store i8 0, ptr addrspace(11)
+entry:
+ %handle = tail call target("spirv.VulkanBuffer", [0 x i8], 12, 0) @llvm.spv.resource.handlefrombinding(i32 0, i32 0, i32 1, i32 0, ptr nonnull @.str)
+ %ptr = call ptr addrspace(11) @llvm.spv.resource.getpointer(target("spirv.VulkanBuffer", [0 x i8], 12, 0) %handle, i32 0)
+ store i32 42, ptr addrspace(11) %ptr, align 4
+ ret void
+}
+
+define void @byteBufferLoad() {
+; CHECK-LABEL: define void @byteBufferLoad(
+; CHECK-NOT: call {{.*}}@llvm.spv.ptrcast
+; CHECK: load i8, ptr addrspace(11)
+; CHECK: call ptr addrspace(11) @llvm.spv.resource.getpointer{{.*}} i32 1)
+; CHECK: load i8, ptr addrspace(11)
+entry:
+ %handle = tail call target("spirv.VulkanBuffer", [0 x i8], 12, 0) @llvm.spv.resource.handlefrombinding(i32 0, i32 0, i32 1, i32 0, ptr nonnull @.str)
+ %ptr = call ptr addrspace(11) @llvm.spv.resource.getpointer(target("spirv.VulkanBuffer", [0 x i8], 12, 0) %handle, i32 0)
+ %val = load i32, ptr addrspace(11) %ptr, align 4
+ ret void
+}
+
+ at slot = internal global target("spirv.VulkanBuffer", [0 x i8], 12, 0) poison, align 8
+
+; Regression for issue #192523: handle flows through memory before getpointer
+; (as in local RWByteAddressBuffer arrays), then typed store hits i8->i32 ptrcast.
----------------
farzonl wrote:
I don't love comments like this because it makes the reader have to be a code archeologist to figure out what it is this test was for just write it more like `Thit test confirms flow through memory before gep is .....` or Delete the comment if you think the checks do a good enough job to explain the purpose.
https://github.com/llvm/llvm-project/pull/212999
More information about the llvm-commits
mailing list