Commit 296b17f37b

Ali Cheraghi <alichraghi@proton.me>
2025-04-25 01:32:20
spirv: allow `offset_and_cast` for vectors when possible
1 parent fc55c1b
Changed files (1)
src
codegen
src/codegen/spirv.zig
@@ -1065,6 +1065,7 @@ const NavGen = struct {
 
     fn derivePtr(self: *NavGen, derivation: Value.PointerDeriveStep) Error!IdRef {
         const pt = self.pt;
+        const zcu = pt.zcu;
         switch (derivation) {
             .comptime_alloc_ptr, .comptime_field_ptr => unreachable,
             .int => |int| {
@@ -1104,23 +1105,36 @@ const NavGen = struct {
             .offset_and_cast => |oac| {
                 const parent_ptr_id = try self.derivePtr(oac.parent.*);
                 const parent_ptr_ty = try oac.parent.ptrType(pt);
-                disallow: {
-                    if (oac.byte_offset != 0) break :disallow;
-                    // Allow changing the pointer type child only to restructure arrays.
-                    // e.g. [3][2]T to T is fine, as is [2]T -> [2][1]T.
-                    const result_ty_id = try self.resolveType(oac.new_ptr_ty, .direct);
-                    const result_ptr_id = self.spv.allocId();
-                    try self.func.body.emit(self.spv.gpa, .OpBitcast, .{
-                        .id_result_type = result_ty_id,
-                        .id_result = result_ptr_id,
-                        .operand = parent_ptr_id,
-                    });
-                    return result_ptr_id;
+                const result_ty_id = try self.resolveType(oac.new_ptr_ty, .direct);
+
+                if (oac.byte_offset != 0) {
+                    const child_size = oac.new_ptr_ty.childType(zcu).abiSize(zcu);
+                    if (oac.byte_offset % child_size != 0) {
+                        return self.fail("cannot perform pointer cast: '{}' to '{}'", .{
+                            parent_ptr_ty.fmt(pt),
+                            oac.new_ptr_ty.fmt(pt),
+                        });
+                    }
+
+                    // Vector element ptr accesses are derived as offset_and_cast.
+                    // We can just use OpAccessChain.
+                    assert(parent_ptr_ty.childType(zcu).zigTypeTag(zcu) == .vector);
+                    return self.accessChain(
+                        result_ty_id,
+                        parent_ptr_id,
+                        &.{@intCast(@divExact(oac.byte_offset, child_size))},
+                    );
                 }
-                return self.fail("cannot perform pointer cast: '{}' to '{}'", .{
-                    parent_ptr_ty.fmt(pt),
-                    oac.new_ptr_ty.fmt(pt),
+
+                // Allow changing the pointer type child only to restructure arrays.
+                // e.g. [3][2]T to T is fine, as is [2]T -> [2][1]T.
+                const result_ptr_id = self.spv.allocId();
+                try self.func.body.emit(self.spv.gpa, .OpBitcast, .{
+                    .id_result_type = result_ty_id,
+                    .id_result = result_ptr_id,
+                    .operand = parent_ptr_id,
                 });
+                return result_ptr_id;
             },
         }
     }