From 07e3e50fd28d98edaf893b9d58d97e7d2b895d38 Mon Sep 17 00:00:00 2001 From: Pavel Verigo Date: Wed, 8 Apr 2026 04:26:02 +0200 Subject: [PATCH] stage2-wasm: enabling bigint blocked tests + final fixes --- src/codegen/wasm/CodeGen.zig | 64 ++++++++++++++++++--------------- test/behavior/bit_shifting.zig | 1 - test/behavior/bitcast.zig | 4 --- test/behavior/byteswap.zig | 1 - test/behavior/eval.zig | 1 - test/behavior/math.zig | 1 + test/behavior/packed-struct.zig | 2 -- test/behavior/struct.zig | 1 - test/behavior/switch.zig | 2 -- test/behavior/switch_loop.zig | 2 -- 10 files changed, 36 insertions(+), 43 deletions(-) diff --git a/src/codegen/wasm/CodeGen.zig b/src/codegen/wasm/CodeGen.zig index 402daa074d007feb2746decc4ea79c8773d14359..82b4c21e0b72df3b3d879694e20685227192ac13 100644 --- a/src/codegen/wasm/CodeGen.zig +++ b/src/codegen/wasm/CodeGen.zig @@ -3,6 +3,7 @@ const builtin = @import("builtin"); const Allocator = std.mem.Allocator; const assert = std.debug.assert; const testing = std.testing; +const math = std.math; const mem = std.mem; const log = std.log.scoped(.codegen); @@ -3258,32 +3259,35 @@ fn intByteSwap(cg: *CodeGen, ty: IntType, operand: WValue) InnerError!WValue { return cg.intShr(ty, intrin_ret, .{ .imm32 = 64 - ty.bits }); }, 65...128 => { - const tmp = try cg.allocStack(Type.u128); + const result = try cg.allocStack(Type.u128); + + try cg.emitWValue(result); const low = try cg.load(operand, Type.u64, 0); - const high = try cg.load(operand, Type.u64, 8); - const swap_low = try cg.callIntrinsic( .__bswapdi2, &.{.u64_type}, Type.u64, &.{low}, ); + try cg.store(.stack, swap_low, Type.u64, result.offset() + 8); + + try cg.emitWValue(result); + + const high = try cg.load(operand, Type.u64, 8); const swap_high = try cg.callIntrinsic( .__bswapdi2, &.{.u64_type}, Type.u64, &.{high}, ); - - try cg.store(tmp, swap_low, Type.u64, tmp.offset() + 8); - try cg.store(tmp, swap_high, Type.u64, tmp.offset()); + try cg.store(.stack, swap_high, Type.u64, result.offset()); if (ty.bits < 128) { const shift_ty: IntType = .{ .is_signed = ty.is_signed, .bits = 128 }; - return cg.intShr(shift_ty, tmp, .{ .imm32 = 128 - ty.bits }); + return cg.intShr(shift_ty, result, .{ .imm32 = 128 - ty.bits }); } else { - return tmp; + return result; } }, else => { @@ -3360,14 +3364,14 @@ fn intWrap(cg: *CodeGen, ty: IntType, operand: WValue) InnerError!WValue { const result = try cg.allocInt(ty); - const copy_len = (ty.bits / 64) * 8; - try cg.memcpy(result, operand, .{ .imm32 = copy_len }); + const used_len = (math.divCeil(u16, ty.bits, 64) catch unreachable) * 8; if (ty.bits % 64 != 0) { + try cg.memcpy(result, operand, .{ .imm32 = used_len - 8 }); const pad = 64 - ty.bits % 64; try cg.emitWValue(result); - _ = try cg.load(operand, Type.u64, copy_len); + _ = try cg.load(operand, Type.u64, used_len - 8); if (ty.is_signed) { try cg.addImm64(pad); try cg.addTag(.i64_shl); @@ -3377,20 +3381,22 @@ fn intWrap(cg: *CodeGen, ty: IntType, operand: WValue) InnerError!WValue { try cg.addImm64(~@as(u64, 0) >> @intCast(pad)); try cg.addTag(.i64_and); } - try cg.store(.stack, .stack, Type.u64, result.offset() + copy_len); + try cg.store(.stack, .stack, Type.u64, result.offset() + used_len - 8); + } else { + try cg.memcpy(result, operand, .{ .imm32 = used_len }); } const full_len = @divExact(bits, 8); - if (copy_len + 16 == full_len) { // last limb needs sign extended + if (used_len + 8 == full_len) { // last limb needs sign extended try cg.emitWValue(result); if (ty.is_signed) { - _ = try cg.load(result, Type.u64, copy_len); + _ = try cg.load(result, Type.u64, used_len - 8); try cg.addImm64(63); try cg.addTag(.i64_shr_s); } else { try cg.addImm64(0); } - try cg.store(.stack, .stack, Type.u64, result.offset() + copy_len + 8); + try cg.store(.stack, .stack, Type.u64, result.offset() + used_len); } return result; @@ -3424,17 +3430,17 @@ fn intMaxValue(cg: *CodeGen, int_ty: IntType) InnerError!WValue { } else { const result = try cg.allocInt(int_ty); const full_len = @divExact(cg.intBackingBits(int_ty.bits), 8); - const normal_len = (int_ty.bits / 64) * 8; + const used_len = (math.divCeil(u16, int_ty.bits, 64) catch unreachable) * 8; - try cg.memset(Type.u8, result, .{ .imm32 = normal_len }, .{ .imm32 = 0xFF }); + try cg.memset(Type.u8, result, .{ .imm32 = used_len - 8 }, .{ .imm32 = 0xFF }); if (int_ty.is_signed) { - try cg.store(result, .{ .imm64 = (~@as(u64, 0) >> @intCast((normal_len + 8) * 8 - int_ty.bits)) >> 1 }, Type.u64, normal_len); + try cg.store(result, .{ .imm64 = (~@as(u64, 0) >> @intCast(used_len * 8 - int_ty.bits)) >> 1 }, Type.u64, used_len - 8); } else { - try cg.store(result, .{ .imm64 = ~@as(u64, 0) >> @intCast((normal_len + 8) * 8 - int_ty.bits) }, Type.u64, normal_len); + try cg.store(result, .{ .imm64 = ~@as(u64, 0) >> @intCast(used_len * 8 - int_ty.bits) }, Type.u64, used_len - 8); } - if (normal_len + 16 == full_len) { + if (used_len + 8 == full_len) { try cg.store(result, .{ .imm64 = 0 }, Type.u64, full_len - 8); } @@ -3458,12 +3464,12 @@ fn intMinValue(cg: *CodeGen, int_ty: IntType) InnerError!WValue { } else { const result = try cg.allocInt(int_ty); const full_len = @divExact(cg.intBackingBits(int_ty.bits), 8); - const normal_len = (int_ty.bits / 64) * 8; + const used_len = (math.divCeil(u16, int_ty.bits, 64) catch unreachable) * 8; - try cg.memset(Type.u8, result, .{ .imm32 = normal_len }, .{ .imm32 = 0 }); - try cg.store(result, .{ .imm64 = ~@as(u64, 0) << @intCast(int_ty.bits - normal_len * 8 - 1) }, Type.u64, normal_len); + try cg.memset(Type.u8, result, .{ .imm32 = used_len - 8 }, .{ .imm32 = 0 }); + try cg.store(result, .{ .imm64 = ~@as(u64, 0) << @intCast(int_ty.bits - (used_len - 8) * 8 - 1) }, Type.u64, used_len - 8); - if (normal_len + 16 == full_len) { + if (used_len + 8 == full_len) { try cg.store(result, .{ .imm64 = ~@as(u64, 0) }, Type.u64, full_len - 8); } @@ -4505,7 +4511,7 @@ fn floatFromInt(cg: *CodeGen, dest_ty: FloatType, src_ty: IntType, operand: WVal }, else => { const intrinsic: Mir.Intrinsic = if (src_ty.is_signed) .__floateihf else .__floatuneihf; - return cg.callIntrinsic(intrinsic, &.{ .usize_type, .usize_type }, Type.f16, &.{ operand, .{ .imm32 = src_ty.bits }}); + return cg.callIntrinsic(intrinsic, &.{ .usize_type, .usize_type }, Type.f16, &.{ operand, .{ .imm32 = src_ty.bits } }); }, }, .f32 => switch (src_ty.bits) { @@ -4526,7 +4532,7 @@ fn floatFromInt(cg: *CodeGen, dest_ty: FloatType, src_ty: IntType, operand: WVal }, else => { const intrinsic: Mir.Intrinsic = if (src_ty.is_signed) .__floateisf else .__floatuneisf; - return cg.callIntrinsic(intrinsic, &.{ .usize_type, .usize_type }, Type.f32, &.{ operand, .{ .imm32 = src_ty.bits }}); + return cg.callIntrinsic(intrinsic, &.{ .usize_type, .usize_type }, Type.f32, &.{ operand, .{ .imm32 = src_ty.bits } }); }, }, .f64 => switch (src_ty.bits) { @@ -4547,7 +4553,7 @@ fn floatFromInt(cg: *CodeGen, dest_ty: FloatType, src_ty: IntType, operand: WVal }, else => { const intrinsic: Mir.Intrinsic = if (src_ty.is_signed) .__floateidf else .__floatuneidf; - return cg.callIntrinsic(intrinsic, &.{ .usize_type, .usize_type }, Type.f64, &.{ operand, .{ .imm32 = src_ty.bits }}); + return cg.callIntrinsic(intrinsic, &.{ .usize_type, .usize_type }, Type.f64, &.{ operand, .{ .imm32 = src_ty.bits } }); }, }, .f80 => switch (src_ty.bits) { @@ -4566,7 +4572,7 @@ fn floatFromInt(cg: *CodeGen, dest_ty: FloatType, src_ty: IntType, operand: WVal }, else => { const intrinsic: Mir.Intrinsic = if (src_ty.is_signed) .__floateixf else .__floatuneixf; - return cg.callIntrinsic(intrinsic, &.{ .usize_type, .usize_type }, Type.f80, &.{ operand, .{ .imm32 = src_ty.bits }}); + return cg.callIntrinsic(intrinsic, &.{ .usize_type, .usize_type }, Type.f80, &.{ operand, .{ .imm32 = src_ty.bits } }); }, }, .f128 => switch (src_ty.bits) { @@ -4585,7 +4591,7 @@ fn floatFromInt(cg: *CodeGen, dest_ty: FloatType, src_ty: IntType, operand: WVal }, else => { const intrinsic: Mir.Intrinsic = if (src_ty.is_signed) .__floateitf else .__floatuneitf; - return cg.callIntrinsic(intrinsic, &.{ .usize_type, .usize_type }, Type.f128, &.{ operand, .{ .imm32 = src_ty.bits }}); + return cg.callIntrinsic(intrinsic, &.{ .usize_type, .usize_type }, Type.f128, &.{ operand, .{ .imm32 = src_ty.bits } }); }, }, } diff --git a/test/behavior/bit_shifting.zig b/test/behavior/bit_shifting.zig index 74bd8690b4228cc631726c4eb707c38a4da1bf7f..9fed23895b90f67ae734be965eb715a0e180a8bd 100644 --- a/test/behavior/bit_shifting.zig +++ b/test/behavior/bit_shifting.zig @@ -151,7 +151,6 @@ test "Saturating Shift Left" { if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; - if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; const S = struct { fn shlSat(x: anytype, y: std.math.Log2Int(@TypeOf(x))) @TypeOf(x) { diff --git a/test/behavior/bitcast.zig b/test/behavior/bitcast.zig index a8f8bcb0221cfb34be16a326329c18dba3a03a41..51573e21fc9b9f6355b36b1f2785bbbad5902047 100644 --- a/test/behavior/bitcast.zig +++ b/test/behavior/bitcast.zig @@ -35,7 +35,6 @@ test "@bitCast iX -> uX (8, 16, 128)" { test "@bitCast iX -> uX exotic integers" { if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; - if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; @@ -80,7 +79,6 @@ fn conv_uN(comptime N: usize, x: std.meta.Int(.unsigned, N)) std.meta.Int(.signe test "bitcast uX to bytes" { if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; - if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; @@ -296,7 +294,6 @@ test "triple level result location with bitcast sandwich passed as tuple element test "@bitCast packed struct of floats" { if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; - if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO @@ -334,7 +331,6 @@ test "@bitCast packed struct of floats" { test "comptime @bitCast packed struct to int and back" { if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; - if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO diff --git a/test/behavior/byteswap.zig b/test/behavior/byteswap.zig index 3cf7b7e015a657221ae8c3d01a34eeb2f684778c..c73e4a5ea97663d840a8107a63439161e7ee903e 100644 --- a/test/behavior/byteswap.zig +++ b/test/behavior/byteswap.zig @@ -42,7 +42,6 @@ test "@byteSwap exotic integers" { if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; - if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; const ByteSwapIntTest = struct { fn run() !void { diff --git a/test/behavior/eval.zig b/test/behavior/eval.zig index 03550fef70d73da7b334842a25ed383d8867cc8b..57ef1d864b8e8259f20d49578e72f58a891c438b 100644 --- a/test/behavior/eval.zig +++ b/test/behavior/eval.zig @@ -511,7 +511,6 @@ var foo_contents = Foo{ .name = "a" }; const foo_ref = &foo_contents; test "runtime 128 bit integer division" { - 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_sparc64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; diff --git a/test/behavior/math.zig b/test/behavior/math.zig index e62f7be41ffd91994861f87c84d88c354801ce7a..77a6a3650dde73cb5142e909e7567f9e98b955c8 100644 --- a/test/behavior/math.zig +++ b/test/behavior/math.zig @@ -1768,6 +1768,7 @@ fn testMod(comptime T: type, numerator: T, denominator: T, expected: T) !void { test "@mod > 128 bits" { if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; + if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; try testMod(u140, 0, maxInt(u140), 0); try testMod(u140, maxInt(u140), maxInt(u140), 0); diff --git a/test/behavior/packed-struct.zig b/test/behavior/packed-struct.zig index d5b01f7c12f71ac5e88976a4d50587ffc460a857..21538ba36923e765ec08c6f5960a0eda9b6bd383 100644 --- a/test/behavior/packed-struct.zig +++ b/test/behavior/packed-struct.zig @@ -582,7 +582,6 @@ test "packed struct fields modification" { test "nested packed struct field access test" { if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO - if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO packed structs larger than 64 bits if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; @@ -736,7 +735,6 @@ test "nested packed struct at non-zero offset 2" { if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; - if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO packed structs larger than 64 bits if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; diff --git a/test/behavior/struct.zig b/test/behavior/struct.zig index b88597ad969def43ea7de26efdeaa869b5aa261b..1e0907d8f6a6148a7aa93405edda27d2cd58d044 100644 --- a/test/behavior/struct.zig +++ b/test/behavior/struct.zig @@ -540,7 +540,6 @@ test "zero-bit field in packed struct" { test "packed struct with non-ABI-aligned field" { if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO - if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; diff --git a/test/behavior/switch.zig b/test/behavior/switch.zig index 95fd81e58fa6a26244f6cbcc9a01f4b6aa38e370..c2a98de5283b3bf117cdc1db22fce9e534eaf5c2 100644 --- a/test/behavior/switch.zig +++ b/test/behavior/switch.zig @@ -1457,8 +1457,6 @@ test "switch on nested packed containers" { } test "switch on large types" { - if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; - const S = struct { fn doTheTest(a: u128, b: i500) !void { switch (a) { diff --git a/test/behavior/switch_loop.zig b/test/behavior/switch_loop.zig index 14794d2d120852838b94b3ba7d8e956fbd827441..4b8cdc71b5e0e458b878577d673390eb60739057 100644 --- a/test/behavior/switch_loop.zig +++ b/test/behavior/switch_loop.zig @@ -566,8 +566,6 @@ test "switch loop with packed unions with OPV" { } test "switch loop on large types" { - if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; - const S = struct { fn doTheTest(a: u128, b: i500) !void { label: switch (a) { -- 2.54.0