From 00dedabc41322bc2b4978ddc39ee17b72193f194 Mon Sep 17 00:00:00 2001 From: Luuk de Gram Date: Sun, 21 May 2023 15:16:48 +0200 Subject: [PATCH 01/11] wasm: `memcpy` support elem abi-size > 1 Previously it was incorrectly assumed that all memcopy's generated by the `memcpy` AIR instruction had an element size of 1 byte. However, this would result in miscompilations for pointer's to arrays where the element size of the array was larger than 1 byte. We now corectly calculate this size. --- src/arch/wasm/CodeGen.zig | 16 ++++++++++++++-- 1 file changed, 14 insertions(+), 2 deletions(-) diff --git a/src/arch/wasm/CodeGen.zig b/src/arch/wasm/CodeGen.zig index bdbe9640c2..7872d89e9b 100644 --- a/src/arch/wasm/CodeGen.zig +++ b/src/arch/wasm/CodeGen.zig @@ -5295,11 +5295,23 @@ fn airMemcpy(func: *CodeGen, inst: Air.Inst.Index) InnerError!void { const bin_op = func.air.instructions.items(.data)[inst].bin_op; const dst = try func.resolveInst(bin_op.lhs); const dst_ty = func.air.typeOf(bin_op.lhs); + const ptr_elem_ty = dst_ty.childType(); const src = try func.resolveInst(bin_op.rhs); const src_ty = func.air.typeOf(bin_op.rhs); const len = switch (dst_ty.ptrSize()) { - .Slice => try func.sliceLen(dst), - .One => @as(WValue, .{ .imm32 = @intCast(u32, dst_ty.childType().arrayLen()) }), + .Slice => blk: { + const slice_len = try func.sliceLen(dst); + if (ptr_elem_ty.abiSize(func.target) != 1) { + try func.emitWValue(slice_len); + try func.emitWValue(.{ .imm32 = @intCast(u32, ptr_elem_ty.abiSize(func.target)) }); + try func.addTag(.i32_mul); + try func.addLabel(.local_set, slice_len.local.value); + } + break :blk slice_len; + }, + .One => @as(WValue, .{ + .imm32 = @intCast(u32, ptr_elem_ty.arrayLen() * ptr_elem_ty.childType().abiSize(func.target)), + }), .C, .Many => unreachable, }; const dst_ptr = try func.sliceOrArrayPtr(dst, dst_ty); From 49fddbf4c11d4ea493c1e5b6176052aeacc1ad10 Mon Sep 17 00:00:00 2001 From: Luuk de Gram Date: Mon, 22 May 2023 19:06:38 +0200 Subject: [PATCH 02/11] wasm: `union_init` correctly store the tag Previously we would only store the payload, but not the actual tag that was set. This meant miscompilations where it would incorrectly return the tag value. This also adds a tiny optimization for payloads which are not `byRef` by directly storing them based on offset, rather than first calculating a pointer to an offset. --- src/arch/wasm/CodeGen.zig | 40 ++++++++++++++++++++++++++++++++------- 1 file changed, 33 insertions(+), 7 deletions(-) diff --git a/src/arch/wasm/CodeGen.zig b/src/arch/wasm/CodeGen.zig index 7872d89e9b..ff09919492 100644 --- a/src/arch/wasm/CodeGen.zig +++ b/src/arch/wasm/CodeGen.zig @@ -4982,26 +4982,52 @@ fn airUnionInit(func: *CodeGen, inst: Air.Inst.Index) InnerError!void { const result = result: { const union_ty = func.air.typeOfIndex(inst); const layout = union_ty.unionGetLayout(func.target); + const union_obj = union_ty.cast(Type.Payload.Union).?.data; + const field = union_obj.fields.values()[extra.field_index]; + const field_name = union_obj.fields.keys()[extra.field_index]; + + const tag_int = blk: { + const tag_ty = union_ty.unionTagTypeHypothetical(); + const enum_field_index = tag_ty.enumFieldIndex(field_name).?; + var tag_val_payload: Value.Payload.U32 = .{ + .base = .{ .tag = .enum_field_index }, + .data = @intCast(u32, enum_field_index), + }; + const tag_val = Value.initPayload(&tag_val_payload.base); + break :blk try func.lowerConstant(tag_val, tag_ty); + }; if (layout.payload_size == 0) { if (layout.tag_size == 0) { break :result WValue{ .none = {} }; } assert(!isByRef(union_ty, func.target)); - break :result WValue{ .imm32 = extra.field_index }; + break :result tag_int; } assert(isByRef(union_ty, func.target)); const result_ptr = try func.allocStack(union_ty); const payload = try func.resolveInst(extra.init); - const union_obj = union_ty.cast(Type.Payload.Union).?.data; - assert(union_obj.haveFieldTypes()); - const field = union_obj.fields.values()[extra.field_index]; - if (layout.tag_align >= layout.payload_align) { - const payload_ptr = try func.buildPointerOffset(result_ptr, layout.tag_size, .new); - try func.store(payload_ptr, payload, field.ty, 0); + if (isByRef(field.ty, func.target)) { + const payload_ptr = try func.buildPointerOffset(result_ptr, layout.tag_size, .new); + try func.store(payload_ptr, payload, field.ty, 0); + } else { + try func.store(result_ptr, payload, field.ty, @intCast(u32, layout.tag_size)); + } + + if (layout.tag_size > 0) { + try func.store(result_ptr, tag_int, union_obj.tag_ty, 0); + } } else { try func.store(result_ptr, payload, field.ty, 0); + if (layout.tag_size > 0) { + try func.store( + result_ptr, + tag_int, + union_obj.tag_ty, + @intCast(u32, layout.payload_size), + ); + } } break :result result_ptr; }; From 7cfc44d86ff56fd760eaf0781cc3ba0650267af9 Mon Sep 17 00:00:00 2001 From: Luuk de Gram Date: Tue, 23 May 2023 19:55:33 +0200 Subject: [PATCH 03/11] wasm: implement `struct_field_val` for packed unions We currently have `isRef` return true for any type of union, including packed unions. This means we can simply load it from the data section to the exact type we want. In the future we can optimize it so it works similarly to packed structs below 64 bits which do not get stored in the data section and are not passed by ref. --- src/arch/wasm/CodeGen.zig | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/src/arch/wasm/CodeGen.zig b/src/arch/wasm/CodeGen.zig index ff09919492..4514311160 100644 --- a/src/arch/wasm/CodeGen.zig +++ b/src/arch/wasm/CodeGen.zig @@ -3617,7 +3617,6 @@ fn airStructFieldVal(func: *CodeGen, inst: Air.Inst.Index) InnerError!void { .Packed => switch (struct_ty.zigTypeTag()) { .Struct => result: { const struct_obj = struct_ty.castTag(.@"struct").?.data; - assert(struct_obj.layout == .Packed); const offset = struct_obj.packedFieldBitOffset(func.target, field_index); const backing_ty = struct_obj.backing_int_ty; const wasm_bits = toWasmBits(backing_ty.intInfo(func.target).bits) orelse { @@ -3661,7 +3660,10 @@ fn airStructFieldVal(func: *CodeGen, inst: Air.Inst.Index) InnerError!void { const truncated = try func.trunc(shifted_value, field_ty, backing_ty); break :result try truncated.toLocal(func, field_ty); }, - .Union => return func.fail("TODO: airStructFieldVal for packed unions", .{}), + .Union => result: { + const val = try func.load(operand, field_ty, 0); + break :result try val.toLocal(func, field_ty); + }, else => unreachable, }, else => result: { @@ -5032,7 +5034,7 @@ fn airUnionInit(func: *CodeGen, inst: Air.Inst.Index) InnerError!void { break :result result_ptr; }; - func.finishAir(inst, result, &.{extra.init}); + return func.finishAir(inst, result, &.{extra.init}); } fn airPrefetch(func: *CodeGen, inst: Air.Inst.Index) InnerError!void { From 3c72b4d25eb14bbdc03503c368a750b1ca1b7c28 Mon Sep 17 00:00:00 2001 From: Luuk de Gram Date: Thu, 25 May 2023 17:52:39 +0200 Subject: [PATCH 04/11] wasm: support and optimize for all packed unions For packed unions where its abi size is less than or equal to 8 bytes we store it directly and don't pass it by reference. This means that when retrieving the field, we will perform shifts and bitcasts to ensure the correct type is returned. For larger packed unions, we either allocate a new stack value based on the field type when the field type is also passed by reference, or load it directly into a local if it's not. --- src/arch/wasm/CodeGen.zig | 55 ++++++++++++++++++++++++++++++++++++--- 1 file changed, 52 insertions(+), 3 deletions(-) diff --git a/src/arch/wasm/CodeGen.zig b/src/arch/wasm/CodeGen.zig index 4514311160..74eb075eab 100644 --- a/src/arch/wasm/CodeGen.zig +++ b/src/arch/wasm/CodeGen.zig @@ -1716,7 +1716,14 @@ fn isByRef(ty: Type, target: std.Target) bool { .Array, .Frame, .Union, - => return ty.hasRuntimeBitsIgnoreComptime(), + => { + if (ty.castTag(.@"union")) |union_ty| { + if (union_ty.data.layout == .Packed) { + return ty.abiSize(target) > 8; + } + } + return ty.hasRuntimeBitsIgnoreComptime(); + }, .Struct => { if (ty.castTag(.@"struct")) |struct_ty| { const struct_obj = struct_ty.data; @@ -3131,6 +3138,14 @@ fn lowerConstant(func: *CodeGen, arg_val: Value, ty: Type) InnerError!WValue { val.writeToMemory(ty, func.bin_file.base.options.module.?, &buf) catch unreachable; return func.storeSimdImmd(buf); }, + .Union => { + // in this case we have a packed union which will not be passed by reference. + const union_ty = ty.cast(Type.Payload.Union).?.data; + const union_obj = val.castTag(.@"union").?.data; + const field_index = ty.unionTagFieldIndex(union_obj.tag, func.bin_file.base.options.module.?).?; + const field_ty = union_ty.fields.values()[field_index].ty; + return func.lowerConstant(union_obj.val, field_ty); + }, else => |zig_type| return func.fail("Wasm TODO: LowerConstant for zigTypeTag {}", .{zig_type}), } } @@ -3661,8 +3676,42 @@ fn airStructFieldVal(func: *CodeGen, inst: Air.Inst.Index) InnerError!void { break :result try truncated.toLocal(func, field_ty); }, .Union => result: { - const val = try func.load(operand, field_ty, 0); - break :result try val.toLocal(func, field_ty); + if (isByRef(struct_ty, func.target)) { + if (!isByRef(field_ty, func.target)) { + const val = try func.load(operand, field_ty, 0); + break :result try val.toLocal(func, field_ty); + } else { + const new_stack_val = try func.allocStack(field_ty); + try func.store(new_stack_val, operand, field_ty, 0); + break :result new_stack_val; + } + } + + var payload: Type.Payload.Bits = .{ + .base = .{ .tag = .int_unsigned }, + .data = @intCast(u16, struct_ty.bitSize(func.target)), + }; + const union_int_type = Type.initPayload(&payload.base); + if (field_ty.zigTypeTag() == .Float) { + var int_payload: Type.Payload.Bits = .{ + .base = .{ .tag = .int_unsigned }, + .data = @intCast(u16, field_ty.bitSize(func.target)), + }; + const int_type = Type.initPayload(&int_payload.base); + const truncated = try func.trunc(operand, int_type, union_int_type); + const bitcasted = try func.bitcast(field_ty, int_type, truncated); + break :result try bitcasted.toLocal(func, field_ty); + } else if (field_ty.isPtrAtRuntime()) { + var int_payload: Type.Payload.Bits = .{ + .base = .{ .tag = .int_unsigned }, + .data = @intCast(u16, field_ty.bitSize(func.target)), + }; + const int_type = Type.initPayload(&int_payload.base); + const truncated = try func.trunc(operand, int_type, union_int_type); + break :result try truncated.toLocal(func, field_ty); + } + const truncated = try func.trunc(operand, field_ty, union_int_type); + break :result try truncated.toLocal(func, field_ty); }, else => unreachable, }, From ffa89d3b8370377b56be594650c0ea73f225c926 Mon Sep 17 00:00:00 2001 From: Luuk de Gram Date: Fri, 26 May 2023 17:30:51 +0200 Subject: [PATCH 05/11] wasm: `UnwrapErrUnionPayloadPtr` ensure ptr ret When the paylaod is zero-sized we must ensure a valid pointer is still returned for the ptr variation of the instruction. This, because it's valid to have a pointer to a zero-sized value. In such a case, we simply return the operand. --- src/arch/wasm/CodeGen.zig | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/src/arch/wasm/CodeGen.zig b/src/arch/wasm/CodeGen.zig index 74eb075eab..1cd282f5f7 100644 --- a/src/arch/wasm/CodeGen.zig +++ b/src/arch/wasm/CodeGen.zig @@ -3161,7 +3161,7 @@ fn storeSimdImmd(func: *CodeGen, value: [16]u8) !WValue { fn emitUndefined(func: *CodeGen, ty: Type) InnerError!WValue { switch (ty.zigTypeTag()) { .Bool, .ErrorSet => return WValue{ .imm32 = 0xaaaaaaaa }, - .Int => switch (ty.intInfo(func.target).bits) { + .Int, .Enum => switch (ty.intInfo(func.target).bits) { 0...32 => return WValue{ .imm32 = 0xaaaaaaaa }, 33...64 => return WValue{ .imm64 = 0xaaaaaaaaaaaaaaaa }, else => unreachable, @@ -3958,7 +3958,12 @@ fn airUnwrapErrUnionPayload(func: *CodeGen, inst: Air.Inst.Index, op_is_ptr: boo const payload_ty = err_ty.errorUnionPayload(); const result = result: { - if (!payload_ty.hasRuntimeBitsIgnoreComptime()) break :result WValue{ .none = {} }; + if (!payload_ty.hasRuntimeBitsIgnoreComptime()) { + if (op_is_ptr) { + break :result WValue{ .imm32 = 0 }; + } + break :result WValue{ .none = {} }; + } const pl_offset = @intCast(u32, errUnionPayloadOffset(payload_ty, func.target)); if (op_is_ptr or isByRef(payload_ty, func.target)) { From 969f9211622b3f2d296a6f51449605d65b66bb31 Mon Sep 17 00:00:00 2001 From: Luuk de Gram Date: Sat, 27 May 2023 15:11:53 +0200 Subject: [PATCH 06/11] wasm: `ptr_elem_val` use pointer type for local When storing the address after calculating the element's address, ensure it's stored in a local with the correct type. Previously it would incorrectly use the element's type, which could be a float for example and therefore generate invalid WebAssembly code. This change also introduces a more robust `store` function. --- src/arch/wasm/CodeGen.zig | 32 +++++++++++++++++++------------- 1 file changed, 19 insertions(+), 13 deletions(-) diff --git a/src/arch/wasm/CodeGen.zig b/src/arch/wasm/CodeGen.zig index 1cd282f5f7..2a8e1668e8 100644 --- a/src/arch/wasm/CodeGen.zig +++ b/src/arch/wasm/CodeGen.zig @@ -2318,6 +2318,7 @@ fn airStore(func: *CodeGen, inst: Air.Inst.Index, safety: bool) InnerError!void fn store(func: *CodeGen, lhs: WValue, rhs: WValue, ty: Type, offset: u32) InnerError!void { assert(!(lhs != .stack and rhs == .stack)); + const abi_size = ty.abiSize(func.target); switch (ty.zigTypeTag()) { .ErrorUnion => { const pl_ty = ty.errorUnionPayload(); @@ -2325,7 +2326,7 @@ fn store(func: *CodeGen, lhs: WValue, rhs: WValue, ty: Type, offset: u32) InnerE return func.store(lhs, rhs, Type.anyerror, 0); } - const len = @intCast(u32, ty.abiSize(func.target)); + const len = @intCast(u32, abi_size); return func.memcpy(lhs, rhs, .{ .imm32 = len }); }, .Optional => { @@ -2341,16 +2342,16 @@ fn store(func: *CodeGen, lhs: WValue, rhs: WValue, ty: Type, offset: u32) InnerE return func.store(lhs, rhs, Type.anyerror, 0); } - const len = @intCast(u32, ty.abiSize(func.target)); + const len = @intCast(u32, abi_size); return func.memcpy(lhs, rhs, .{ .imm32 = len }); }, .Struct, .Array, .Union => if (isByRef(ty, func.target)) { - const len = @intCast(u32, ty.abiSize(func.target)); + const len = @intCast(u32, abi_size); return func.memcpy(lhs, rhs, .{ .imm32 = len }); }, .Vector => switch (determineSimdStoreStrategy(ty, func.target)) { .unrolled => { - const len = @intCast(u32, ty.abiSize(func.target)); + const len = @intCast(u32, abi_size); return func.memcpy(lhs, rhs, .{ .imm32 = len }); }, .direct => { @@ -2382,7 +2383,7 @@ fn store(func: *CodeGen, lhs: WValue, rhs: WValue, ty: Type, offset: u32) InnerE return; } }, - .Int => if (ty.intInfo(func.target).bits > 64) { + .Int, .Float => if (abi_size > 8 and abi_size <= 16) { try func.emitWValue(lhs); const lsb = try func.load(rhs, Type.u64, 0); try func.store(.{ .stack = {} }, lsb, Type.u64, 0 + lhs.offset()); @@ -2391,8 +2392,15 @@ fn store(func: *CodeGen, lhs: WValue, rhs: WValue, ty: Type, offset: u32) InnerE const msb = try func.load(rhs, Type.u64, 8); try func.store(.{ .stack = {} }, msb, Type.u64, 8 + lhs.offset()); return; + } else if (abi_size > 16) { + try func.memcpy(lhs, rhs, .{ .imm32 = @intCast(u32, ty.abiSize(func.target)) }); + }, + else => if (abi_size > 8) { + return func.fail("TODO: `store` for type `{}` with abisize `{d}`", .{ + ty.fmt(func.bin_file.base.options.module.?), + abi_size, + }); }, - else => {}, } try func.emitWValue(lhs); // In this case we're actually interested in storing the stack position @@ -2400,11 +2408,9 @@ fn store(func: *CodeGen, lhs: WValue, rhs: WValue, ty: Type, offset: u32) InnerE try func.lowerToStack(rhs); const valtype = typeToValtype(ty, func.target); - const abi_size = @intCast(u8, ty.abiSize(func.target)); - const opcode = buildOpcode(.{ .valtype1 = valtype, - .width = abi_size * 8, + .width = @intCast(u8, abi_size * 8), .op = .store, }); @@ -3960,7 +3966,7 @@ fn airUnwrapErrUnionPayload(func: *CodeGen, inst: Air.Inst.Index, op_is_ptr: boo const result = result: { if (!payload_ty.hasRuntimeBitsIgnoreComptime()) { if (op_is_ptr) { - break :result WValue{ .imm32 = 0 }; + break :result func.reuseOperand(ty_op.operand, operand); } break :result WValue{ .none = {} }; } @@ -4453,7 +4459,7 @@ fn airPtrElemVal(func: *CodeGen, inst: Air.Inst.Index) InnerError!void { try func.addTag(.i32_add); const elem_result = val: { - var result = try func.allocLocal(elem_ty); + var result = try func.allocLocal(Type.usize); try func.addLabel(.local_set, result.local.value); if (isByRef(elem_ty, func.target)) { break :val result; @@ -5155,8 +5161,8 @@ fn cmpOptionals(func: *CodeGen, lhs: WValue, rhs: WValue, operand_ty: Type, op: fn cmpBigInt(func: *CodeGen, lhs: WValue, rhs: WValue, operand_ty: Type, op: std.math.CompareOperator) InnerError!WValue { assert(operand_ty.abiSize(func.target) >= 16); assert(!(lhs != .stack and rhs == .stack)); - if (operand_ty.intInfo(func.target).bits > 128) { - return func.fail("TODO: Support cmpBigInt for integer bitsize: '{d}'", .{operand_ty.intInfo(func.target).bits}); + if (operand_ty.bitSize(func.target) > 128) { + return func.fail("TODO: Support cmpBigInt for integer bitsize: '{d}'", .{operand_ty.bitSize(func.target)}); } var lhs_high_bit = try (try func.load(lhs, Type.u64, 0)).toLocal(func, Type.u64); From 128814f9bf89460232569ae3e47c52f90cdf4ffd Mon Sep 17 00:00:00 2001 From: Luuk de Gram Date: Sat, 27 May 2023 15:14:18 +0200 Subject: [PATCH 07/11] wasm: `aggregate_init` store sentinel for arrays --- src/arch/wasm/CodeGen.zig | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/src/arch/wasm/CodeGen.zig b/src/arch/wasm/CodeGen.zig index 2a8e1668e8..57f6beb035 100644 --- a/src/arch/wasm/CodeGen.zig +++ b/src/arch/wasm/CodeGen.zig @@ -4926,6 +4926,9 @@ fn airAggregateInit(func: *CodeGen, inst: Air.Inst.Index) InnerError!void { const result = try func.allocStack(result_ty); const elem_ty = result_ty.childType(); const elem_size = @intCast(u32, elem_ty.abiSize(func.target)); + const sentinel = if (result_ty.sentinel()) |sent| blk: { + break :blk try func.lowerConstant(sent, elem_ty); + } else null; // When the element type is by reference, we must copy the entire // value. It is therefore safer to move the offset pointer and store @@ -4938,10 +4941,13 @@ fn airAggregateInit(func: *CodeGen, inst: Air.Inst.Index) InnerError!void { const elem_val = try func.resolveInst(elem); try func.store(offset, elem_val, elem_ty, 0); - if (elem_index < elements.len - 1) { + if (elem_index < elements.len - 1 and sentinel == null) { _ = try func.buildPointerOffset(offset, elem_size, .modify); } } + if (sentinel) |sent| { + try func.store(offset, sent, elem_ty, 0); + } } else { var offset: u32 = 0; for (elements) |elem| { @@ -4949,6 +4955,9 @@ fn airAggregateInit(func: *CodeGen, inst: Air.Inst.Index) InnerError!void { try func.store(result, elem_val, elem_ty, offset); offset += elem_size; } + if (sentinel) |sent| { + try func.store(result, sent, elem_ty, offset); + } } break :result_value result; }, From e36cc0ce8f4c0ec7c1398149c5fa30f15d8dae9f Mon Sep 17 00:00:00 2001 From: Luuk de Gram Date: Mon, 29 May 2023 12:33:24 +0200 Subject: [PATCH 08/11] wasm: `union_init` support packed unions --- src/arch/wasm/CodeGen.zig | 81 +++++++++++++++++++++++++++++---------- 1 file changed, 60 insertions(+), 21 deletions(-) diff --git a/src/arch/wasm/CodeGen.zig b/src/arch/wasm/CodeGen.zig index 57f6beb035..34a3c68102 100644 --- a/src/arch/wasm/CodeGen.zig +++ b/src/arch/wasm/CodeGen.zig @@ -1014,6 +1014,17 @@ fn typeToValtype(ty: Type, target: std.Target) wasm.Valtype { .direct => wasm.Valtype.v128, .unrolled => wasm.Valtype.i32, }, + .Union => switch (ty.containerLayout()) { + .Packed => { + var int_ty_payload: Type.Payload.Bits = .{ + .base = .{ .tag = .int_unsigned }, + .data = @intCast(u16, ty.bitSize(target)), + }; + const int_ty = Type.initPayload(&int_ty_payload.base); + return typeToValtype(int_ty, target); + }, + else => wasm.Valtype.i32, + }, else => wasm.Valtype.i32, // all represented as reference/immediate }; } @@ -5074,33 +5085,61 @@ fn airUnionInit(func: *CodeGen, inst: Air.Inst.Index) InnerError!void { assert(!isByRef(union_ty, func.target)); break :result tag_int; } - assert(isByRef(union_ty, func.target)); - const result_ptr = try func.allocStack(union_ty); - const payload = try func.resolveInst(extra.init); - if (layout.tag_align >= layout.payload_align) { - if (isByRef(field.ty, func.target)) { - const payload_ptr = try func.buildPointerOffset(result_ptr, layout.tag_size, .new); - try func.store(payload_ptr, payload, field.ty, 0); + if (isByRef(union_ty, func.target)) { + const result_ptr = try func.allocStack(union_ty); + const payload = try func.resolveInst(extra.init); + if (layout.tag_align >= layout.payload_align) { + if (isByRef(field.ty, func.target)) { + const payload_ptr = try func.buildPointerOffset(result_ptr, layout.tag_size, .new); + try func.store(payload_ptr, payload, field.ty, 0); + } else { + try func.store(result_ptr, payload, field.ty, @intCast(u32, layout.tag_size)); + } + + if (layout.tag_size > 0) { + try func.store(result_ptr, tag_int, union_obj.tag_ty, 0); + } } else { - try func.store(result_ptr, payload, field.ty, @intCast(u32, layout.tag_size)); - } - - if (layout.tag_size > 0) { - try func.store(result_ptr, tag_int, union_obj.tag_ty, 0); + try func.store(result_ptr, payload, field.ty, 0); + if (layout.tag_size > 0) { + try func.store( + result_ptr, + tag_int, + union_obj.tag_ty, + @intCast(u32, layout.payload_size), + ); + } } + break :result result_ptr; } else { - try func.store(result_ptr, payload, field.ty, 0); - if (layout.tag_size > 0) { - try func.store( - result_ptr, - tag_int, - union_obj.tag_ty, - @intCast(u32, layout.payload_size), - ); + const operand = try func.resolveInst(extra.init); + var payload: Type.Payload.Bits = .{ + .base = .{ .tag = .int_unsigned }, + .data = @intCast(u16, union_ty.bitSize(func.target)), + }; + const union_int_type = Type.initPayload(&payload.base); + if (field.ty.zigTypeTag() == .Float) { + var int_payload: Type.Payload.Bits = .{ + .base = .{ .tag = .int_unsigned }, + .data = @intCast(u16, field.ty.bitSize(func.target)), + }; + const int_type = Type.initPayload(&int_payload.base); + const bitcasted = try func.bitcast(field.ty, int_type, operand); + const casted = try func.trunc(bitcasted, int_type, union_int_type); + break :result try casted.toLocal(func, field.ty); + } else if (field.ty.isPtrAtRuntime()) { + var int_payload: Type.Payload.Bits = .{ + .base = .{ .tag = .int_unsigned }, + .data = @intCast(u16, field.ty.bitSize(func.target)), + }; + const int_type = Type.initPayload(&int_payload.base); + const casted = try func.intcast(operand, int_type, union_int_type); + break :result try casted.toLocal(func, field.ty); } + const casted = try func.intcast(operand, field.ty, union_int_type); + break :result try casted.toLocal(func, field.ty); } - break :result result_ptr; }; return func.finishAir(inst, result, &.{extra.init}); From 7e10cf4fbe2a8a379564941be9953ce157d483cc Mon Sep 17 00:00:00 2001 From: Luuk de Gram Date: Mon, 29 May 2023 14:23:51 +0200 Subject: [PATCH 09/11] wasm: `shl_with_overflow` ensure rhs is coerced Both operands must have the same Wasm type before we are allowed to perform any binary operation on the values. --- src/arch/wasm/CodeGen.zig | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-) diff --git a/src/arch/wasm/CodeGen.zig b/src/arch/wasm/CodeGen.zig index 34a3c68102..2072ff1506 100644 --- a/src/arch/wasm/CodeGen.zig +++ b/src/arch/wasm/CodeGen.zig @@ -5707,6 +5707,7 @@ fn airShlWithOverflow(func: *CodeGen, inst: Air.Inst.Index) InnerError!void { const lhs = try func.resolveInst(extra.lhs); const rhs = try func.resolveInst(extra.rhs); const lhs_ty = func.air.typeOf(extra.lhs); + const rhs_ty = func.air.typeOf(extra.rhs); if (lhs_ty.zigTypeTag() == .Vector) { return func.fail("TODO: Implement overflow arithmetic for vectors", .{}); @@ -5718,7 +5719,15 @@ fn airShlWithOverflow(func: *CodeGen, inst: Air.Inst.Index) InnerError!void { return func.fail("TODO: Implement shl_with_overflow for integer bitsize: {d}", .{int_info.bits}); }; - var shl = try (try func.binOp(lhs, rhs, lhs_ty, .shl)).toLocal(func, lhs_ty); + // Ensure rhs is coerced to lhs as they must have the same WebAssembly types + // before we can perform any binary operation. + const rhs_wasm_bits = toWasmBits(rhs_ty.intInfo(func.target).bits).?; + const rhs_final = if (wasm_bits != rhs_wasm_bits) blk: { + const rhs_casted = try func.intcast(rhs, rhs_ty, lhs_ty); + break :blk try rhs_casted.toLocal(func, lhs_ty); + } else rhs; + + var shl = try (try func.binOp(lhs, rhs_final, lhs_ty, .shl)).toLocal(func, lhs_ty); defer shl.free(func); var result = if (wasm_bits != int_info.bits) blk: { break :blk try (try func.wrapOperand(shl, lhs_ty)).toLocal(func, lhs_ty); @@ -5729,11 +5738,11 @@ fn airShlWithOverflow(func: *CodeGen, inst: Air.Inst.Index) InnerError!void { // emit lhs to stack to we can keep 'wrapped' on the stack also try func.emitWValue(lhs); const abs = try func.signAbsValue(shl, lhs_ty); - const wrapped = try func.wrapBinOp(abs, rhs, lhs_ty, .shr); + const wrapped = try func.wrapBinOp(abs, rhs_final, lhs_ty, .shr); break :blk try func.cmp(.{ .stack = {} }, wrapped, lhs_ty, .neq); } else blk: { try func.emitWValue(lhs); - const shr = try func.binOp(result, rhs, lhs_ty, .shr); + const shr = try func.binOp(result, rhs_final, lhs_ty, .shr); break :blk try func.cmp(.{ .stack = {} }, shr, lhs_ty, .neq); }; var overflow_local = try overflow_bit.toLocal(func, Type.initTag(.u1)); From ebfd3450d9a3338726e1ed8b08a5751b06604cd5 Mon Sep 17 00:00:00 2001 From: Luuk de Gram Date: Tue, 30 May 2023 21:55:44 +0200 Subject: [PATCH 10/11] codegen: Write padding bytes for unions Previously we did not write any missing padding bytes after the smallest field (either tag or payload, depending on alignment). This resulted in writing too few bytes and not matching the full abisize of the union. --- src/arch/wasm/CodeGen.zig | 4 ++-- src/codegen.zig | 4 ++++ 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/src/arch/wasm/CodeGen.zig b/src/arch/wasm/CodeGen.zig index 2072ff1506..d4be9bf139 100644 --- a/src/arch/wasm/CodeGen.zig +++ b/src/arch/wasm/CodeGen.zig @@ -1726,8 +1726,8 @@ fn isByRef(ty: Type, target: std.Target) bool { .Array, .Frame, - .Union, - => { + => return ty.hasRuntimeBitsIgnoreComptime(), + .Union => { if (ty.castTag(.@"union")) |union_ty| { if (union_ty.data.layout == .Packed) { return ty.abiSize(target) > 8; diff --git a/src/codegen.zig b/src/codegen.zig index 692c55e380..adce183833 100644 --- a/src/codegen.zig +++ b/src/codegen.zig @@ -611,6 +611,10 @@ pub fn generateSymbol( } } + if (layout.padding > 0) { + try code.writer().writeByteNTimes(0, layout.padding); + } + return Result.ok; }, .Optional => { From 1042deb86fd57278f3a16fd064b370bf72f28160 Mon Sep 17 00:00:00 2001 From: Luuk de Gram Date: Wed, 31 May 2023 18:03:49 +0200 Subject: [PATCH 11/11] enable passing behavior tests --- test/behavior/align.zig | 1 - test/behavior/atomics.zig | 1 - test/behavior/basic.zig | 3 --- test/behavior/bugs/12142.zig | 1 - test/behavior/bugs/13113.zig | 1 - test/behavior/bugs/13128.zig | 1 - test/behavior/bugs/13664.zig | 1 - test/behavior/bugs/1381.zig | 1 - test/behavior/cast_int.zig | 1 - test/behavior/empty_union.zig | 5 ----- test/behavior/enum.zig | 2 -- test/behavior/error.zig | 5 ----- test/behavior/eval.zig | 5 ----- test/behavior/optional.zig | 1 - test/behavior/ptrcast.zig | 2 -- test/behavior/return_address.zig | 1 - test/behavior/type.zig | 2 -- test/behavior/union.zig | 11 ----------- test/behavior/union_with_members.zig | 1 - 19 files changed, 46 deletions(-) diff --git a/test/behavior/align.zig b/test/behavior/align.zig index dd0ea31711..ce407422bf 100644 --- a/test/behavior/align.zig +++ b/test/behavior/align.zig @@ -16,7 +16,6 @@ test "global variable alignment" { } test "slicing array of length 1 can not assume runtime index is always zero" { - if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest; diff --git a/test/behavior/atomics.zig b/test/behavior/atomics.zig index 99f08a6cae..41794461ad 100644 --- a/test/behavior/atomics.zig +++ b/test/behavior/atomics.zig @@ -383,7 +383,6 @@ fn testAtomicRmwInt128(comptime signedness: std.builtin.Signedness) !void { } test "atomics with different types" { - if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO diff --git a/test/behavior/basic.zig b/test/behavior/basic.zig index 3024ad58c0..bdbcfdbfc0 100644 --- a/test/behavior/basic.zig +++ b/test/behavior/basic.zig @@ -413,7 +413,6 @@ test "array 2D const double ptr with offset" { if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; - if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest; const rect_2d_vertexes = [_][2]f32{ @@ -427,7 +426,6 @@ test "array 3D const double ptr with offset" { if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; - if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest; const rect_3d_vertexes = [_][2][2]f32{ @@ -1052,7 +1050,6 @@ test "inline call of function with a switch inside the return statement" { } test "namespace lookup ignores decl causing the lookup" { - if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest; diff --git a/test/behavior/bugs/12142.zig b/test/behavior/bugs/12142.zig index e5c022bf18..4b9a4d9fa1 100644 --- a/test/behavior/bugs/12142.zig +++ b/test/behavior/bugs/12142.zig @@ -19,7 +19,6 @@ fn letter(e: Letter) u8 { } test { - if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_x86) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO diff --git a/test/behavior/bugs/13113.zig b/test/behavior/bugs/13113.zig index 72ab0f9f5e..fd3a14f8f6 100644 --- a/test/behavior/bugs/13113.zig +++ b/test/behavior/bugs/13113.zig @@ -7,7 +7,6 @@ const Foo = extern struct { }; test { - if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_x86) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO diff --git a/test/behavior/bugs/13128.zig b/test/behavior/bugs/13128.zig index 944fa52c8a..b87513d510 100644 --- a/test/behavior/bugs/13128.zig +++ b/test/behavior/bugs/13128.zig @@ -14,7 +14,6 @@ fn foo(val: U) !void { test "runtime union init, most-aligned field != largest" { if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO - if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest; diff --git a/test/behavior/bugs/13664.zig b/test/behavior/bugs/13664.zig index 7171a89f29..34f6e9110b 100644 --- a/test/behavior/bugs/13664.zig +++ b/test/behavior/bugs/13664.zig @@ -13,7 +13,6 @@ fn value() i64 { return 1341; } test { - if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO diff --git a/test/behavior/bugs/1381.zig b/test/behavior/bugs/1381.zig index aa349b4d13..90941de341 100644 --- a/test/behavior/bugs/1381.zig +++ b/test/behavior/bugs/1381.zig @@ -15,7 +15,6 @@ test "union that needs padding bytes inside an array" { if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; - if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest; diff --git a/test/behavior/cast_int.zig b/test/behavior/cast_int.zig index c04c300d45..041ee193e8 100644 --- a/test/behavior/cast_int.zig +++ b/test/behavior/cast_int.zig @@ -4,7 +4,6 @@ const expect = std.testing.expect; const maxInt = std.math.maxInt; test "@intCast i32 to u7" { - if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO diff --git a/test/behavior/empty_union.zig b/test/behavior/empty_union.zig index 54ad52df63..1bdbf8e54b 100644 --- a/test/behavior/empty_union.zig +++ b/test/behavior/empty_union.zig @@ -3,15 +3,12 @@ const std = @import("std"); const expect = std.testing.expect; test "switch on empty enum" { - if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO - const E = enum {}; var e: E = undefined; switch (e) {} } test "switch on empty enum with a specified tag type" { - if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest; const E = enum(u8) {}; @@ -21,7 +18,6 @@ test "switch on empty enum with a specified tag type" { test "switch on empty auto numbered tagged union" { if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO - if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest; const U = union(enum(u8)) {}; @@ -31,7 +27,6 @@ test "switch on empty auto numbered tagged union" { test "switch on empty tagged union" { if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO - if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO const E = enum {}; const U = union(E) {}; diff --git a/test/behavior/enum.zig b/test/behavior/enum.zig index f652d7fe5b..42131df80e 100644 --- a/test/behavior/enum.zig +++ b/test/behavior/enum.zig @@ -1079,7 +1079,6 @@ const bit_field_1 = BitFieldOfEnums{ }; test "bit field access with enum fields" { - if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO @@ -1120,7 +1119,6 @@ test "enum literal in array literal" { } test "tag name functions are unique" { - if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO diff --git a/test/behavior/error.zig b/test/behavior/error.zig index 618af87e10..b8f68ec663 100644 --- a/test/behavior/error.zig +++ b/test/behavior/error.zig @@ -720,7 +720,6 @@ test "ret_ptr doesn't cause own inferred error set to be resolved" { } test "simple else prong allowed even when all errors handled" { - if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest; @@ -749,7 +748,6 @@ test "simple else prong allowed even when all errors handled" { test "pointer to error union payload" { if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO - if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest; @@ -783,7 +781,6 @@ const NoReturn = struct { test "error union of noreturn used with if" { if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO - if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest; @@ -798,7 +795,6 @@ test "error union of noreturn used with if" { test "error union of noreturn used with try" { if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO - if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest; @@ -810,7 +806,6 @@ test "error union of noreturn used with try" { test "error union of noreturn used with catch" { if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO - if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest; diff --git a/test/behavior/eval.zig b/test/behavior/eval.zig index 68d43ef0b6..39eac020c5 100644 --- a/test/behavior/eval.zig +++ b/test/behavior/eval.zig @@ -470,7 +470,6 @@ test "binary math operator in partially inlined function" { } test "comptime shl" { - if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO @@ -501,7 +500,6 @@ test "comptime bitwise operators" { test "comptime shlWithOverflow" { if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO - if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest; const ct_shifted = @shlWithOverflow(~@as(u64, 0), 16)[0]; @@ -812,7 +810,6 @@ test "array concatenation peer resolves element types - pointer" { } test "array concatenation sets the sentinel - value" { - if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO @@ -850,7 +847,6 @@ test "array concatenation sets the sentinel - pointer" { } test "array multiplication sets the sentinel - value" { - if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO @@ -1550,7 +1546,6 @@ test "x or true is comptime-known true" { test "non-optional and optional array elements concatenated" { if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO - if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest; diff --git a/test/behavior/optional.zig b/test/behavior/optional.zig index 4a043c6a6e..8a38f95366 100644 --- a/test/behavior/optional.zig +++ b/test/behavior/optional.zig @@ -365,7 +365,6 @@ test "optional pointer to zero bit optional payload" { test "optional pointer to zero bit error union payload" { if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO - if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest; diff --git a/test/behavior/ptrcast.zig b/test/behavior/ptrcast.zig index 8e25a52505..5051dc0ecb 100644 --- a/test/behavior/ptrcast.zig +++ b/test/behavior/ptrcast.zig @@ -129,7 +129,6 @@ fn testReinterpretOverAlignedExternStructAsExternStruct() !void { test "lower reinterpreted comptime field ptr (with under-aligned fields)" { if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO - if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest; @@ -153,7 +152,6 @@ test "lower reinterpreted comptime field ptr (with under-aligned fields)" { test "lower reinterpreted comptime field ptr" { if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO - if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest; diff --git a/test/behavior/return_address.zig b/test/behavior/return_address.zig index 6d92e11793..3e8c18c04a 100644 --- a/test/behavior/return_address.zig +++ b/test/behavior/return_address.zig @@ -6,7 +6,6 @@ fn retAddr() usize { } test "return address" { - if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO diff --git a/test/behavior/type.zig b/test/behavior/type.zig index 2fff4b05af..94a6b460e4 100644 --- a/test/behavior/type.zig +++ b/test/behavior/type.zig @@ -258,7 +258,6 @@ test "Type.ErrorSet" { } test "Type.Struct" { - if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO @@ -488,7 +487,6 @@ test "Type.Union from regular enum" { } test "Type.Fn" { - if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO diff --git a/test/behavior/union.zig b/test/behavior/union.zig index 2520241aff..f1bfaa063b 100644 --- a/test/behavior/union.zig +++ b/test/behavior/union.zig @@ -452,7 +452,6 @@ var glbl: Foo1 = undefined; test "global union with single field is correctly initialized" { if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; - if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest; @@ -500,7 +499,6 @@ test "update the tag value for zero-sized unions" { test "union initializer generates padding only if needed" { if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; - if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest; @@ -788,7 +786,6 @@ fn Setter(comptime attr: Attribute) type { test "return union init with void payload" { if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; - if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest; @@ -814,7 +811,6 @@ test "return union init with void payload" { test "@unionInit stored to a const" { if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO - if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest; @@ -985,7 +981,6 @@ test "function call result coerces from tagged union to the tag" { test "cast from anonymous struct to union" { if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO - if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest; @@ -1018,7 +1013,6 @@ test "cast from anonymous struct to union" { test "cast from pointer to anonymous struct to pointer to union" { if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO - if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest; @@ -1108,7 +1102,6 @@ test "containers with single-field enums" { test "@unionInit on union with tag but no fields" { if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO - if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest; @@ -1382,7 +1375,6 @@ test "union and enum field order doesn't match" { test "@unionInit uses tag value instead of field index" { if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO - if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest; @@ -1440,7 +1432,6 @@ test "union field ptr - zero sized field" { test "packed union in packed struct" { if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO - if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest; @@ -1528,7 +1519,6 @@ test "union reassignment can use previous value" { test "packed union with zero-bit field" { if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO - if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest; @@ -1549,7 +1539,6 @@ test "packed union with zero-bit field" { test "reinterpreting enum value inside packed union" { if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO - if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest; const U = packed union { diff --git a/test/behavior/union_with_members.zig b/test/behavior/union_with_members.zig index 1155d14924..186a30ad63 100644 --- a/test/behavior/union_with_members.zig +++ b/test/behavior/union_with_members.zig @@ -17,7 +17,6 @@ const ET = union(enum) { }; test "enum with members" { - if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO