authorgravatar for alex@alexrp.comAlex Rønne Petersen <alex@alexrp.com> 2025-07-24 07:44:08+02:00
committergravatar for noreply@github.comGitHub <noreply@github.com> 2025-07-24 07:44:08+02:00
log5fb36d2600b686a5132b42c4824f99dc2412f037
tree18e3f648542d574c893d1cfd04ce1bfbefbdabb2
parentb8955a2e0aea692b6c76dc39962b3620649b6e1f
parent4328f71d9fbb67b1e9949b5c398578eab6f59314
signaturebadge-check Signed by PGP key B5690EEEBB952194

Merge pull request #24557 from pavelverigo/wasm-try-ptr


4 files changed, 99 insertions(+), 22 deletions(-)

src/arch/wasm/CodeGen.zig+9-12
......@@ -1886,8 +1886,10 @@ fn genInst(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void {
18861886 .call_never_tail => cg.airCall(inst, .never_tail),
18871887 .call_never_inline => cg.airCall(inst, .never_inline),
18881888
1889 .is_err => cg.airIsErr(inst, .i32_ne),
1890 .is_non_err => cg.airIsErr(inst, .i32_eq),
1889 .is_err => cg.airIsErr(inst, .i32_ne, .value),
1890 .is_non_err => cg.airIsErr(inst, .i32_eq, .value),
1891 .is_err_ptr => cg.airIsErr(inst, .i32_ne, .ptr),
1892 .is_non_err_ptr => cg.airIsErr(inst, .i32_eq, .ptr),
18911893
18921894 .is_null => cg.airIsNull(inst, .i32_eq, .value),
18931895 .is_non_null => cg.airIsNull(inst, .i32_ne, .value),
......@@ -1970,8 +1972,6 @@ fn genInst(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void {
19701972 .runtime_nav_ptr => cg.airRuntimeNavPtr(inst),
19711973
19721974 .assembly,
1973 .is_err_ptr,
1974 .is_non_err_ptr,
19751975
19761976 .err_return_trace,
19771977 .set_err_return_trace,
......@@ -4105,7 +4105,7 @@ fn airSwitchDispatch(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void {
41054105 return cg.finishAir(inst, .none, &.{br.operand});
41064106}
41074107
4108fn airIsErr(cg: *CodeGen, inst: Air.Inst.Index, opcode: std.wasm.Opcode) InnerError!void {
4108fn airIsErr(cg: *CodeGen, inst: Air.Inst.Index, opcode: std.wasm.Opcode, op_kind: enum { value, ptr }) InnerError!void {
41094109 const zcu = cg.pt.zcu;
41104110 const un_op = cg.air.instructions.items(.data)[@intFromEnum(inst)].un_op;
41114111 const operand = try cg.resolveInst(un_op);
......@@ -4122,7 +4122,7 @@ fn airIsErr(cg: *CodeGen, inst: Air.Inst.Index, opcode: std.wasm.Opcode) InnerEr
41224122 }
41234123
41244124 try cg.emitWValue(operand);
4125 if (pl_ty.hasRuntimeBitsIgnoreComptime(zcu)) {
4125 if (op_kind == .ptr or pl_ty.hasRuntimeBitsIgnoreComptime(zcu)) {
41264126 try cg.addMemArg(.i32_load16_u, .{
41274127 .offset = operand.offset() + @as(u32, @intCast(errUnionErrorOffset(pl_ty, zcu))),
41284128 .alignment = @intCast(Type.anyerror.abiAlignment(zcu).toByteUnits().?),
......@@ -6462,9 +6462,6 @@ fn lowerTry(
64626462 operand_is_ptr: bool,
64636463) InnerError!WValue {
64646464 const zcu = cg.pt.zcu;
6465 if (operand_is_ptr) {
6466 return cg.fail("TODO: lowerTry for pointers", .{});
6467 }
64686465
64696466 const pl_ty = err_union_ty.errorUnionPayload(zcu);
64706467 const pl_has_bits = pl_ty.hasRuntimeBitsIgnoreComptime(zcu);
......@@ -6475,7 +6472,7 @@ fn lowerTry(
64756472
64766473 // check if the error tag is set for the error union.
64776474 try cg.emitWValue(err_union);
6478 if (pl_has_bits) {
6475 if (pl_has_bits or operand_is_ptr) {
64796476 const err_offset: u32 = @intCast(errUnionErrorOffset(pl_ty, zcu));
64806477 try cg.addMemArg(.i32_load16_u, .{
64816478 .offset = err_union.offset() + err_offset,
......@@ -6497,12 +6494,12 @@ fn lowerTry(
64976494 }
64986495
64996496 // if we reach here it means error was not set, and we want the payload
6500 if (!pl_has_bits) {
6497 if (!pl_has_bits and !operand_is_ptr) {
65016498 return .none;
65026499 }
65036500
65046501 const pl_offset: u32 = @intCast(errUnionPayloadOffset(pl_ty, zcu));
6505 if (isByRef(pl_ty, zcu, cg.target)) {
6502 if (operand_is_ptr or isByRef(pl_ty, zcu, cg.target)) {
65066503 return buildPointerOffset(cg, err_union, pl_offset, .new);
65076504 }
65086505 const payload = try cg.load(err_union, pl_ty, pl_offset);
test/behavior/try.zig+79
......@@ -121,3 +121,82 @@ test "'return try' through conditional" {
121121 comptime std.debug.assert(result == 123);
122122 }
123123}
124
125test "try ptr propagation const" {
126 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
127 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
128 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
129 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest;
130 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
131
132 const S = struct {
133 fn foo0() !u32 {
134 return 0;
135 }
136
137 fn foo1() error{Bad}!u32 {
138 return 1;
139 }
140
141 fn foo2() anyerror!u32 {
142 return 2;
143 }
144
145 fn doTheTest() !void {
146 const res0: *const u32 = &(try foo0());
147 const res1: *const u32 = &(try foo1());
148 const res2: *const u32 = &(try foo2());
149 try expect(res0.* == 0);
150 try expect(res1.* == 1);
151 try expect(res2.* == 2);
152 }
153 };
154 try S.doTheTest();
155 try comptime S.doTheTest();
156}
157
158test "try ptr propagation mutate" {
159 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
160 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
161 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
162 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest;
163 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
164
165 const S = struct {
166 fn foo0() !u32 {
167 return 0;
168 }
169
170 fn foo1() error{Bad}!u32 {
171 return 1;
172 }
173
174 fn foo2() anyerror!u32 {
175 return 2;
176 }
177
178 fn doTheTest() !void {
179 var f0 = foo0();
180 var f1 = foo1();
181 var f2 = foo2();
182
183 const res0: *u32 = &(try f0);
184 const res1: *u32 = &(try f1);
185 const res2: *u32 = &(try f2);
186
187 res0.* += 1;
188 res1.* += 1;
189 res2.* += 1;
190
191 try expect(f0 catch unreachable == 1);
192 try expect(f1 catch unreachable == 2);
193 try expect(f2 catch unreachable == 3);
194
195 try expect(res0.* == 1);
196 try expect(res1.* == 2);
197 try expect(res2.* == 3);
198 }
199 };
200 try S.doTheTest();
201 try comptime S.doTheTest();
202}
test/src/Cases.zig+2
......@@ -800,6 +800,8 @@ const TestManifestConfigDefaults = struct {
800800 }
801801 // Windows
802802 defaults = defaults ++ "x86_64-windows" ++ ",";
803 // Wasm
804 defaults = defaults ++ "wasm32-wasi";
803805 break :blk defaults;
804806 };
805807 } else if (std.mem.eql(u8, key, "output_mode")) {
test/tests.zig+9-10
......@@ -1369,16 +1369,15 @@ const test_targets = blk: {
13691369
13701370 // WASI Targets
13711371
1372 // TODO: lowerTry for pointers
1373 //.{
1374 // .target = .{
1375 // .cpu_arch = .wasm32,
1376 // .os_tag = .wasi,
1377 // .abi = .none,
1378 // },
1379 // .use_llvm = false,
1380 // .use_lld = false,
1381 //},
1372 .{
1373 .target = .{
1374 .cpu_arch = .wasm32,
1375 .os_tag = .wasi,
1376 .abi = .none,
1377 },
1378 .use_llvm = false,
1379 .use_lld = false,
1380 },
13821381 .{
13831382 .target = .{
13841383 .cpu_arch = .wasm32,