authorgravatar for alex@alexrp.comAlex Rønne Petersen <alex@alexrp.com> 2026-10-06 04:16:16+02:00
committergravatar for alex@alexrp.comAlex Rønne Petersen <alex@alexrp.com> 2026-10-06 04:16:16+02:00
loga7a6d1730db30d6541eedf3be1531d323eb7a93a
treee824b72f4c201d0d187cb4ee21efd32d266c7aa2
parent96b9286a1bff0cf7ce407448bc4aaadb1d446e22
parent89838eb5f005f206f22116768d6ed3d13507dbd8

Merge pull request 'spirv: fix three regressions that make Vulkan modules invalid' (#37050) from brianferri/zig:fix/spirv-regressions into master

Reviewed-on: https://codeberg.org/ziglang/zig/pulls/37050 Reviewed-by: Ali Cheraghi <alichraghi@noreply.codeberg.org>

3 files changed, 38 insertions(+), 17 deletions(-)

src/Air/Legalize.zig+1-1
...@@ -904,7 +904,7 @@ fn legalizeBody(l: *Legalize, body_start: usize, body_len: usize) Error!void {...@@ -904,7 +904,7 @@ fn legalizeBody(l: *Legalize, body_start: usize, body_len: usize) Error!void {
904 .splat => {904 .splat => {
905 const ty_op = l.air_instructions.items(.data)[@backingInt(inst)].ty_op;905 const ty_op = l.air_instructions.items(.data)[@backingInt(inst)].ty_op;
906 switch (ty_op.ty.zigTypeTag(zcu)) {906 switch (ty_op.ty.zigTypeTag(zcu)) {
907 .vector => switch (ty_op.ty.vectorLen(zcu)) {907 .vector => if (l.features.has(.splat_one_elem_to_bit_cast)) switch (ty_op.ty.vectorLen(zcu)) {
908 0 => unreachable,908 0 => unreachable,
909 1 => continue :inst l.replaceInst(inst, .bit_cast, .{ .ty_op = .{909 1 => continue :inst l.replaceInst(inst, .bit_cast, .{ .ty_op = .{
910 .ty = ty_op.ty,910 .ty = ty_op.ty,
src/codegen/spirv/CodeGen.zig+27-16
...@@ -1684,16 +1684,25 @@ fn constantPtr(cg: *CodeGen, ptr_val: Value) !Id {...@@ -1684,16 +1684,25 @@ fn constantPtr(cg: *CodeGen, ptr_val: Value) !Id {
1684 return cg.derivePtr(ptr_val.typeOf(zcu).ptrAddressSpace(zcu), derivation);1684 return cg.derivePtr(ptr_val.typeOf(zcu).ptrAddressSpace(zcu), derivation);
1685}1685}
16861686
1687/// Emits the pointer type that one step of a pointer derivation results in, along with its
1688/// pointee type. A derivation is the sequence of steps that builds a comptime-known pointer: a
1689/// base address, such as a declaration, an anonymous value or an integer, followed by field,
1690/// element and cast steps, each of which is lowered on its own.
1691/// This function emits instructions on every call, and they stay in the module whether or not they
1692/// are read, so it should only be called where the resulting type is used: a buffer struct emitted
1693/// without `Block` fails validation even when nothing refers to it.
1694fn derivedPtrType(cg: *CodeGen, @"addrspace": std.lang.AddressSpace, derivation: Value.PointerDerivation) !Id {
1695 return cg.ptrType(
1696 try cg.pointeeType(@"addrspace", derivation.elem_ty, false),
1697 cg.storageClass(@"addrspace"),
1698 );
1699}
1700
1687fn derivePtr(cg: *CodeGen, @"addrspace": std.lang.AddressSpace, derivation: Value.PointerDerivation) !Id {1701fn derivePtr(cg: *CodeGen, @"addrspace": std.lang.AddressSpace, derivation: Value.PointerDerivation) !Id {
1688 const gpa = cg.gpa;1702 const gpa = cg.gpa;
1689 const zcu = cg.zcu;1703 const zcu = cg.zcu;
1690 const target = zcu.getTarget();1704 const target = zcu.getTarget();
16911705
1692 const result_ty_id = try cg.ptrType(
1693 try cg.pointeeType(@"addrspace", derivation.elem_ty, false),
1694 cg.storageClass(@"addrspace"),
1695 );
1696
1697 switch (derivation.addr) {1706 switch (derivation.addr) {
1698 .comptime_alloc, .comptime_field => unreachable,1707 .comptime_alloc, .comptime_field => unreachable,
1699 .int => |int| {1708 .int => |int| {
...@@ -1708,6 +1717,7 @@ fn derivePtr(cg: *CodeGen, @"addrspace": std.lang.AddressSpace, derivation: Valu...@@ -1708,6 +1717,7 @@ fn derivePtr(cg: *CodeGen, @"addrspace": std.lang.AddressSpace, derivation: Valu
1708 // TODO: This can probably be an OpSpecConstantOp Bitcast, but1717 // TODO: This can probably be an OpSpecConstantOp Bitcast, but
1709 // that is not implemented by Mesa yet. Therefore, just generate it1718 // that is not implemented by Mesa yet. Therefore, just generate it
1710 // as a runtime operation.1719 // as a runtime operation.
1720 const result_ty_id = try cg.derivedPtrType(@"addrspace", derivation);
1711 const result_ptr_id = cg.allocId();1721 const result_ptr_id = cg.allocId();
1712 const value_id = try cg.constInt(.usize, int);1722 const value_id = try cg.constInt(.usize, int);
1713 try cg.body.emit(gpa, .OpConvertUToPtr, .{1723 try cg.body.emit(gpa, .OpConvertUToPtr, .{
...@@ -1727,10 +1737,10 @@ fn derivePtr(cg: *CodeGen, @"addrspace": std.lang.AddressSpace, derivation: Valu...@@ -1727,10 +1737,10 @@ fn derivePtr(cg: *CodeGen, @"addrspace": std.lang.AddressSpace, derivation: Valu
17271737
1728 if (ip.isFunctionType(nav_ty.toIntern())) {1738 if (ip.isFunctionType(nav_ty.toIntern())) {
1729 if (is_extern) return try cg.resolveExternFn(nav_index);1739 if (is_extern) return try cg.resolveExternFn(nav_index);
1730 return try cg.constUndef(result_ty_id);1740 return try cg.constUndef(try cg.derivedPtrType(@"addrspace", derivation));
1731 }1741 }
1732 if (!nav_ty.hasRuntimeBits(zcu) and nav_ty.zigTypeTag(zcu) != .spirv) {1742 if (!nav_ty.hasRuntimeBits(zcu) and nav_ty.zigTypeTag(zcu) != .spirv) {
1733 return cg.constUndef(result_ty_id);1743 return cg.constUndef(try cg.derivedPtrType(@"addrspace", derivation));
1734 }1744 }
1735 if (!is_extern) {1745 if (!is_extern) {
1736 return cg.todo("pointer to constant '{f}'", .{nav.fqn.fmt(ip)});1746 return cg.todo("pointer to constant '{f}'", .{nav.fqn.fmt(ip)});
...@@ -1739,20 +1749,20 @@ fn derivePtr(cg: *CodeGen, @"addrspace": std.lang.AddressSpace, derivation: Valu...@@ -1739,20 +1749,20 @@ fn derivePtr(cg: *CodeGen, @"addrspace": std.lang.AddressSpace, derivation: Valu
1739 const as = nav.resolved.?.@"addrspace";1749 const as = nav.resolved.?.@"addrspace";
1740 assert(as != .generic);1750 assert(as != .generic);
17411751
1742 const storage_class = cg.storageClass(as);
1743 const var_id = try cg.resolveNav(nav_index);1752 const var_id = try cg.resolveNav(nav_index);
1744 const nav_ty_id = try cg.resolveType(nav_ty, .indirect);
1745 const decl_ptr_ty_id = try cg.ptrType(nav_ty_id, storage_class);
1746 if (cg.needsLayout(as, nav_ty)) {1753 if (cg.needsLayout(as, nav_ty)) {
1747 try cg.block_var_ids.put(gpa, var_id, {});1754 try cg.block_var_ids.put(gpa, var_id, {});
1748 }1755 }
1749
1750 if (decl_ptr_ty_id == result_ty_id) return var_id;
1751 switch (target.os.tag) {1756 switch (target.os.tag) {
1752 .vulkan, .opengl => return var_id,1757 .vulkan, .opengl => return var_id,
1753 else => {},1758 else => {},
1754 }1759 }
17551760
1761 const nav_ty_id = try cg.resolveType(nav_ty, .indirect);
1762 const decl_ptr_ty_id = try cg.ptrType(nav_ty_id, cg.storageClass(as));
1763 const result_ty_id = try cg.derivedPtrType(@"addrspace", derivation);
1764 if (decl_ptr_ty_id == result_ty_id) return var_id;
1765
1756 const casted_ptr_id = cg.allocId();1766 const casted_ptr_id = cg.allocId();
1757 try cg.body.emit(gpa, .OpBitcast, .{1767 try cg.body.emit(gpa, .OpBitcast, .{
1758 .id_result_type = result_ty_id,1768 .id_result_type = result_ty_id,
...@@ -1772,7 +1782,7 @@ fn derivePtr(cg: *CodeGen, @"addrspace": std.lang.AddressSpace, derivation: Valu...@@ -1772,7 +1782,7 @@ fn derivePtr(cg: *CodeGen, @"addrspace": std.lang.AddressSpace, derivation: Valu
1772 }1782 }
17731783
1774 if (!uav_ty.hasRuntimeBits(zcu) and uav_ty.zigTypeTag(zcu) != .spirv) {1784 if (!uav_ty.hasRuntimeBits(zcu) and uav_ty.zigTypeTag(zcu) != .spirv) {
1775 return cg.constUndef(result_ty_id);1785 return cg.constUndef(try cg.derivedPtrType(@"addrspace", derivation));
1776 }1786 }
17771787
1778 if (cg.storageClass(@"addrspace") != .function) {1788 if (cg.storageClass(@"addrspace") != .function) {
...@@ -1789,7 +1799,7 @@ fn derivePtr(cg: *CodeGen, @"addrspace": std.lang.AddressSpace, derivation: Valu...@@ -1789,7 +1799,7 @@ fn derivePtr(cg: *CodeGen, @"addrspace": std.lang.AddressSpace, derivation: Valu
1789 .opt_payload => @panic("TODO"),1799 .opt_payload => @panic("TODO"),
1790 .field => |derived| return cg.structFieldPtr(1800 .field => |derived| return cg.structFieldPtr(
1791 @"addrspace",1801 @"addrspace",
1792 result_ty_id,1802 try cg.derivedPtrType(@"addrspace", derivation),
1793 derivation.elem_ty,1803 derivation.elem_ty,
1794 derived.parent.elem_ty,1804 derived.parent.elem_ty,
1795 try cg.derivePtr(@"addrspace", derived.parent.*),1805 try cg.derivePtr(@"addrspace", derived.parent.*),
...@@ -1801,7 +1811,7 @@ fn derivePtr(cg: *CodeGen, @"addrspace": std.lang.AddressSpace, derivation: Valu...@@ -1801,7 +1811,7 @@ fn derivePtr(cg: *CodeGen, @"addrspace": std.lang.AddressSpace, derivation: Valu
1801 .many => .many_ptr,1811 .many => .many_ptr,
1802 },1812 },
1803 @"addrspace",1813 @"addrspace",
1804 derived.parent.elem_ty,1814 derivation.elem_ty,
1805 try cg.derivePtr(@"addrspace", derived.parent.*),1815 try cg.derivePtr(@"addrspace", derived.parent.*),
1806 try cg.constInt(.usize, derived.elem_index),1816 try cg.constInt(.usize, derived.elem_index),
1807 ),1817 ),
...@@ -1841,12 +1851,13 @@ fn derivePtr(cg: *CodeGen, @"addrspace": std.lang.AddressSpace, derivation: Valu...@@ -1841,12 +1851,13 @@ fn derivePtr(cg: *CodeGen, @"addrspace": std.lang.AddressSpace, derivation: Valu
1841 const zero = try cg.constInt(.u32, 0);1851 const zero = try cg.constInt(.u32, 0);
1842 const ids = try cg.id_scratch.addManyAsSlice(gpa, depth);1852 const ids = try cg.id_scratch.addManyAsSlice(gpa, depth);
1843 @memset(ids, zero);1853 @memset(ids, zero);
1844 return cg.accessChainId(result_ty_id, parent_ptr_id, ids);1854 return cg.accessChainId(try cg.derivedPtrType(@"addrspace", derivation), parent_ptr_id, ids);
1845 } else {1855 } else {
1846 return parent_ptr_id;1856 return parent_ptr_id;
1847 }1857 }
1848 }1858 }
1849 if (target.os.tag == .opencl) {1859 if (target.os.tag == .opencl) {
1860 const result_ty_id = try cg.derivedPtrType(@"addrspace", derivation);
1850 const result_ptr_id = cg.allocId();1861 const result_ptr_id = cg.allocId();
1851 try cg.body.emit(gpa, .OpBitcast, .{1862 try cg.body.emit(gpa, .OpBitcast, .{
1852 .id_result_type = result_ty_id,1863 .id_result_type = result_ty_id,
test/behavior/splat.zig+10
...@@ -145,6 +145,16 @@ test "vector @splat" {...@@ -145,6 +145,16 @@ test "vector @splat" {
145 try testForT(8 * 2, @as(f16, 3.1415));145 try testForT(8 * 2, @as(f16, 3.1415));
146 try testForT(4 * 2, @as(f32, 3.1415));146 try testForT(4 * 2, @as(f32, 3.1415));
147 try testForT(2 * 2, @as(f64, 3.1415));147 try testForT(2 * 2, @as(f64, 3.1415));
148
149 // Splats into one-element vectors.
150 try testForT(1, @as(u8, 0xEE));
151 try testForT(1, @as(u16, 0xBEEF));
152 try testForT(1, @as(u32, 0xDEADBEEF));
153 try testForT(1, @as(u64, 0xCAFEF00DDEADBEEF));
154
155 try testForT(1, @as(f16, 3.1415));
156 try testForT(1, @as(f32, 3.1415));
157 try testForT(1, @as(f64, 3.1415));
148 }158 }
149 };159 };
150 try S.doTheTest();160 try S.doTheTest();