Commit e5fcc8192d

jonascloud <bahnes.jonas@icloud.com>
2025-10-20 07:18:44
spir-v: Fix .storage_buffer pointer indexing
Renames arePointersLogical to shouldBlockPointerOps for clarity adds capability check to allow pointer ops on .storage_buffer when variable_pointers capability is enabled. Fixes #25638
1 parent 93d54cb
Changed files (2)
src/Sema.zig
@@ -9156,7 +9156,7 @@ fn checkMergeAllowed(sema: *Sema, block: *Block, src: LazySrcLoc, peer_ty: Type)
     }
 
     const as = peer_ty.ptrAddressSpace(zcu);
-    if (!target_util.arePointersLogical(target, as)) {
+    if (!target_util.shouldBlockPointerOps(target, as)) {
         return;
     }
 
@@ -22669,7 +22669,7 @@ fn ptrCastFull(
 
     try sema.validateRuntimeValue(block, operand_src, operand);
 
-    const can_cast_to_int = !target_util.arePointersLogical(zcu.getTarget(), operand_ty.ptrAddressSpace(zcu));
+    const can_cast_to_int = !target_util.shouldBlockPointerOps(zcu.getTarget(), operand_ty.ptrAddressSpace(zcu));
     const need_null_check = can_cast_to_int and block.wantSafety() and operand_ty.ptrAllowsZero(zcu) and !dest_ty.ptrAllowsZero(zcu);
     const need_align_check = can_cast_to_int and block.wantSafety() and dest_align.compare(.gt, src_align);
 
@@ -23247,7 +23247,7 @@ fn checkLogicalPtrOperation(sema: *Sema, block: *Block, src: LazySrcLoc, ty: Typ
     if (zcu.intern_pool.indexToKey(ty.toIntern()) == .ptr_type) {
         const target = zcu.getTarget();
         const as = ty.ptrAddressSpace(zcu);
-        if (target_util.arePointersLogical(target, as)) {
+        if (target_util.shouldBlockPointerOps(target, as)) {
             return sema.failWithOwnedErrorMsg(block, msg: {
                 const msg = try sema.errMsg(src, "illegal operation on logical pointer of type '{f}'", .{ty.fmt(pt)});
                 errdefer msg.destroy(sema.gpa);
@@ -28100,7 +28100,7 @@ fn validateRuntimeElemAccess(
     if (zcu.intern_pool.indexToKey(parent_ty.toIntern()) == .ptr_type) {
         const target = zcu.getTarget();
         const as = parent_ty.ptrAddressSpace(zcu);
-        if (target_util.arePointersLogical(target, as)) {
+        if (target_util.shouldBlockPointerOps(target, as)) {
             return sema.fail(block, elem_index_src, "cannot access element of logical pointer '{f}'", .{parent_ty.fmt(pt)});
         }
     }
src/target.zig
@@ -549,31 +549,35 @@ pub fn addrSpaceCastIsValid(
     }
 }
 
-/// Under SPIR-V with Vulkan, pointers are not 'real' (physical), but rather 'logical'. Effectively,
-/// this means that all such pointers have to be resolvable to a location at compile time, and places
-/// a number of restrictions on usage of such pointers. For example, a logical pointer may not be
-/// part of a merge (result of a branch) and may not be stored in memory at all. This function returns
-/// for a particular architecture and address space wether such pointers are logical.
-pub fn arePointersLogical(target: *const std.Target, as: AddressSpace) bool {
+/// Returns whether pointer operations (arithmetic, indexing, etc.) should be blocked
+/// for the given address space on the target architecture.
+///
+/// Under SPIR-V with Vulkan
+/// (a) all physical pointers (.physical_storage_buffer, .global) always support pointer operations,
+/// (b) by default logical pointers (.constant, .input, .output, etc.) never support operations
+/// (c) some logical pointers (.storage_buffer, .shared) do support operations when
+///     the VariablePointers capability is enabled (which enables OpPtrAccessChain).
+pub fn shouldBlockPointerOps(target: *const std.Target, as: AddressSpace) bool {
     if (target.os.tag != .vulkan) return false;
 
     return switch (as) {
         // TODO: Vulkan doesn't support pointers in the generic address space, we
         // should remove this case but this requires a change in defaultAddressSpace().
-        // For now, at least disable them from being regarded as physical.
         .generic => true,
         // For now, all global pointers are represented using StorageBuffer or CrossWorkgroup,
         // so these are real pointers.
-        .global => false,
-        .physical_storage_buffer => false,
+        // Physical pointers always support operations
+        .global, .physical_storage_buffer => false,
+        // Logical pointers that support operations with VariablePointers capability
         .shared => !target.cpu.features.isEnabled(@intFromEnum(std.Target.spirv.Feature.variable_pointers)),
+        .storage_buffer => !target.cpu.features.isEnabled(@intFromEnum(std.Target.spirv.Feature.variable_pointers)),
+        // Logical pointers that never support operations
         .constant,
         .local,
         .input,
         .output,
         .uniform,
         .push_constant,
-        .storage_buffer,
         => true,
         else => unreachable,
     };