authorgravatar for paul.verigo@gmail.comPavel Verigo <paul.verigo@gmail.com> 2025-02-28 00:47:18+01:00
committergravatar for paul.verigo@gmail.comPavel Verigo <paul.verigo@gmail.com> 2025-03-24 15:00:00+01:00
log07f14bd43b983de4467095b37613325b49022835
tree94db5a85e55da6ce1689b117b570930f54ec08b0
parent0e109add37e304bf97b2f5f5d91be0870d18506c

stage2-wasm: fix error union handling


2 files changed, 28 insertions(+), 15 deletions(-)

src/arch/wasm/CodeGen.zig+28-12
...@@ -3130,7 +3130,13 @@ fn lowerPtr(cg: *CodeGen, ptr_val: InternPool.Index, prev_offset: u64) InnerErro...@@ -3130,7 +3130,13 @@ fn lowerPtr(cg: *CodeGen, ptr_val: InternPool.Index, prev_offset: u64) InnerErro
3130 .nav => |nav| return .{ .nav_ref = .{ .nav_index = nav, .offset = @intCast(offset) } },3130 .nav => |nav| return .{ .nav_ref = .{ .nav_index = nav, .offset = @intCast(offset) } },
3131 .uav => |uav| return .{ .uav_ref = .{ .ip_index = uav.val, .offset = @intCast(offset), .orig_ptr_ty = uav.orig_ty } },3131 .uav => |uav| return .{ .uav_ref = .{ .ip_index = uav.val, .offset = @intCast(offset), .orig_ptr_ty = uav.orig_ty } },
3132 .int => return cg.lowerConstant(try pt.intValue(Type.usize, offset), Type.usize),3132 .int => return cg.lowerConstant(try pt.intValue(Type.usize, offset), Type.usize),
3133 .eu_payload => return cg.fail("Wasm TODO: lower error union payload pointer", .{}),3133 .eu_payload => |eu_ptr| try cg.lowerPtr(
3134 eu_ptr,
3135 offset + codegen.errUnionPayloadOffset(
3136 Value.fromInterned(eu_ptr).typeOf(zcu).childType(zcu),
3137 zcu,
3138 ),
3139 ),
3134 .opt_payload => |opt_ptr| return cg.lowerPtr(opt_ptr, offset),3140 .opt_payload => |opt_ptr| return cg.lowerPtr(opt_ptr, offset),
3135 .field => |field| {3141 .field => |field| {
3136 const base_ptr = Value.fromInterned(field.base);3142 const base_ptr = Value.fromInterned(field.base);
...@@ -4179,52 +4185,62 @@ fn airIsErr(cg: *CodeGen, inst: Air.Inst.Index, opcode: std.wasm.Opcode) InnerEr...@@ -4179,52 +4185,62 @@ fn airIsErr(cg: *CodeGen, inst: Air.Inst.Index, opcode: std.wasm.Opcode) InnerEr
4179 return cg.finishAir(inst, result, &.{un_op});4185 return cg.finishAir(inst, result, &.{un_op});
4180}4186}
41814187
4188/// E!T -> T op_is_ptr == false
4189/// *(E!T) -> *T op_is_prt == true
4182fn airUnwrapErrUnionPayload(cg: *CodeGen, inst: Air.Inst.Index, op_is_ptr: bool) InnerError!void {4190fn airUnwrapErrUnionPayload(cg: *CodeGen, inst: Air.Inst.Index, op_is_ptr: bool) InnerError!void {
4183 const zcu = cg.pt.zcu;4191 const zcu = cg.pt.zcu;
4184 const ty_op = cg.air.instructions.items(.data)[@intFromEnum(inst)].ty_op;4192 const ty_op = cg.air.instructions.items(.data)[@intFromEnum(inst)].ty_op;
41854193
4186 const operand = try cg.resolveInst(ty_op.operand);4194 const operand = try cg.resolveInst(ty_op.operand);
4187 const op_ty = cg.typeOf(ty_op.operand);4195 const op_ty = cg.typeOf(ty_op.operand);
4188 const err_ty = if (op_is_ptr) op_ty.childType(zcu) else op_ty;4196 const eu_ty = if (op_is_ptr) op_ty.childType(zcu) else op_ty;
4189 const payload_ty = err_ty.errorUnionPayload(zcu);4197 const payload_ty = eu_ty.errorUnionPayload(zcu);
41904198
4191 const result: WValue = result: {4199 const result: WValue = result: {
4192 if (!payload_ty.hasRuntimeBitsIgnoreComptime(zcu)) {4200 if (!payload_ty.hasRuntimeBitsIgnoreComptime(zcu)) {
4193 if (op_is_ptr) {4201 if (op_is_ptr) {
4194 break :result cg.reuseOperand(ty_op.operand, operand);4202 break :result cg.reuseOperand(ty_op.operand, operand);
4203 } else {
4204 break :result .none;
4195 }4205 }
4196 break :result .none;
4197 }4206 }
41984207
4199 const pl_offset = @as(u32, @intCast(errUnionPayloadOffset(payload_ty, zcu)));4208 const pl_offset: u32 = @intCast(errUnionPayloadOffset(payload_ty, zcu));
4200 if (op_is_ptr or isByRef(payload_ty, zcu, cg.target)) {4209 if (op_is_ptr or isByRef(payload_ty, zcu, cg.target)) {
4201 break :result try cg.buildPointerOffset(operand, pl_offset, .new);4210 break :result try cg.buildPointerOffset(operand, pl_offset, .new);
4211 } else {
4212 assert(isByRef(eu_ty, zcu, cg.target));
4213 break :result try cg.load(operand, payload_ty, pl_offset);
4202 }4214 }
42034215
4204 break :result try cg.load(operand, payload_ty, pl_offset);
4205 };4216 };
4206 return cg.finishAir(inst, result, &.{ty_op.operand});4217 return cg.finishAir(inst, result, &.{ty_op.operand});
4207}4218}
42084219
4220/// E!T -> E op_is_ptr == false
4221/// *(E!T) -> E op_is_prt == true
4222/// NOTE: op_is_ptr will not change return type
4209fn airUnwrapErrUnionError(cg: *CodeGen, inst: Air.Inst.Index, op_is_ptr: bool) InnerError!void {4223fn airUnwrapErrUnionError(cg: *CodeGen, inst: Air.Inst.Index, op_is_ptr: bool) InnerError!void {
4210 const zcu = cg.pt.zcu;4224 const zcu = cg.pt.zcu;
4211 const ty_op = cg.air.instructions.items(.data)[@intFromEnum(inst)].ty_op;4225 const ty_op = cg.air.instructions.items(.data)[@intFromEnum(inst)].ty_op;
42124226
4213 const operand = try cg.resolveInst(ty_op.operand);4227 const operand = try cg.resolveInst(ty_op.operand);
4214 const op_ty = cg.typeOf(ty_op.operand);4228 const op_ty = cg.typeOf(ty_op.operand);
4215 const err_ty = if (op_is_ptr) op_ty.childType(zcu) else op_ty;4229 const eu_ty = if (op_is_ptr) op_ty.childType(zcu) else op_ty;
4216 const payload_ty = err_ty.errorUnionPayload(zcu);4230 const payload_ty = eu_ty.errorUnionPayload(zcu);
42174231
4218 const result: WValue = result: {4232 const result: WValue = result: {
4219 if (err_ty.errorUnionSet(zcu).errorSetIsEmpty(zcu)) {4233 if (eu_ty.errorUnionSet(zcu).errorSetIsEmpty(zcu)) {
4220 break :result .{ .imm32 = 0 };4234 break :result .{ .imm32 = 0 };
4221 }4235 }
42224236
4223 if (op_is_ptr or !payload_ty.hasRuntimeBitsIgnoreComptime(zcu)) {4237 const err_offset: u32 = @intCast(errUnionErrorOffset(payload_ty, zcu));
4238 if (op_is_ptr or isByRef(eu_ty, zcu, cg.target)) {
4239 break :result try cg.load(operand, Type.anyerror, err_offset);
4240 } else {
4241 assert(!payload_ty.hasRuntimeBitsIgnoreComptime(zcu));
4224 break :result cg.reuseOperand(ty_op.operand, operand);4242 break :result cg.reuseOperand(ty_op.operand, operand);
4225 }4243 }
4226
4227 break :result try cg.load(operand, Type.anyerror, @intCast(errUnionErrorOffset(payload_ty, zcu)));
4228 };4244 };
4229 return cg.finishAir(inst, result, &.{ty_op.operand});4245 return cg.finishAir(inst, result, &.{ty_op.operand});
4230}4246}
test/behavior/switch_on_captured_error.zig-3
...@@ -7,7 +7,6 @@ const builtin = @import("builtin");...@@ -7,7 +7,6 @@ const builtin = @import("builtin");
77
8test "switch on error union catch capture" {8test "switch on error union catch capture" {
9 if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest;9 if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest;
10 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest;
11 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;10 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
1211
13 const S = struct {12 const S = struct {
...@@ -302,7 +301,6 @@ test "switch on error union catch capture" {...@@ -302,7 +301,6 @@ test "switch on error union catch capture" {
302301
303test "switch on error union if else capture" {302test "switch on error union if else capture" {
304 if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest;303 if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest;
305 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest;
306 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;304 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
307305
308 const S = struct {306 const S = struct {
...@@ -794,7 +792,6 @@ test "switch on error union if else capture" {...@@ -794,7 +792,6 @@ test "switch on error union if else capture" {
794 }792 }
795793
796 fn testAddressOf() !void {794 fn testAddressOf() !void {
797 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest;
798 {795 {
799 const a: anyerror!usize = 0;796 const a: anyerror!usize = 0;
800 const ptr = &(if (a) |*v| v.* else |e| switch (e) {797 const ptr = &(if (a) |*v| v.* else |e| switch (e) {