diff --git a/src/arch/wasm/CodeGen.zig b/src/arch/wasm/CodeGen.zig index 287ec831a2..c78fc1584f 100644 --- a/src/arch/wasm/CodeGen.zig +++ b/src/arch/wasm/CodeGen.zig @@ -2783,6 +2783,7 @@ const FloatOp = enum { .sqrt => .sqrt, .sub => .sub, .trunc => .trunc, + .rem => .fmod, else => unreachable, }; } @@ -6808,30 +6809,37 @@ fn airMod(func: *CodeGen, inst: Air.Inst.Index) InnerError!void { const lhs = try func.resolveInst(bin_op.lhs); const rhs = try func.resolveInst(bin_op.rhs); - if (ty.isUnsignedInt(zcu)) { - _ = try func.binOp(lhs, rhs, ty, .rem); - } else if (ty.isSignedInt(zcu)) { - // The wasm rem instruction gives the remainder after truncating division (rounding towards - // 0), equivalent to @rem. - // We make use of the fact that: - // @mod(a, b) = @rem(@rem(a, b) + b, b) - const int_bits = ty.intInfo(zcu).bits; - const wasm_bits = toWasmBits(int_bits) orelse { - return func.fail("TODO: `@mod` for signed integers larger than 64 bits ({d} bits requested)", .{int_bits}); - }; - - if (wasm_bits > 64) { - return func.fail("TODO: `@mod` for signed integers larger than 64 bits ({d} bits requested)", .{int_bits}); + const result = result: { + if (ty.isUnsignedInt(zcu)) { + break :result try func.binOp(lhs, rhs, ty, .rem); } + if (ty.isSignedInt(zcu)) { + // The wasm rem instruction gives the remainder after truncating division (rounding towards + // 0), equivalent to @rem. + // We make use of the fact that: + // @mod(a, b) = @rem(@rem(a, b) + b, b) + const int_bits = ty.intInfo(zcu).bits; + const wasm_bits = toWasmBits(int_bits) orelse { + return func.fail("TODO: `@mod` for signed integers larger than 64 bits ({d} bits requested)", .{int_bits}); + }; - _ = try func.binOp(lhs, rhs, ty, .rem); - _ = try func.binOp(.stack, rhs, ty, .add); - _ = try func.binOp(.stack, rhs, ty, .rem); - } else { - return func.fail("TODO: implement `@mod` on floating point types for {}", .{func.target.cpu.arch}); - } + if (wasm_bits > 64) { + return func.fail("TODO: `@mod` for signed integers larger than 64 bits ({d} bits requested)", .{int_bits}); + } - return func.finishAir(inst, .stack, &.{ bin_op.lhs, bin_op.rhs }); + _ = try func.binOp(lhs, rhs, ty, .rem); + _ = try func.binOp(.stack, rhs, ty, .add); + break :result try func.binOp(.stack, rhs, ty, .rem); + } + if (ty.isAnyFloat()) { + const rem = try func.binOp(lhs, rhs, ty, .rem); + const add = try func.binOp(rem, rhs, ty, .add); + break :result try func.binOp(add, rhs, ty, .rem); + } + return func.fail("TODO: @mod for {}", .{ty.fmt(pt)}); + }; + + return func.finishAir(inst, result, &.{ bin_op.lhs, bin_op.rhs }); } fn airSatMul(func: *CodeGen, inst: Air.Inst.Index) InnerError!void { diff --git a/test/behavior/math.zig b/test/behavior/math.zig index bbf87fc834..1cd7583abc 100644 --- a/test/behavior/math.zig +++ b/test/behavior/math.zig @@ -167,7 +167,6 @@ fn testOneCtz(comptime T: type, x: T) u32 { } test "@ctz 128-bit integers" { - if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_x86_64 and builtin.target.ofmt != .elf and builtin.target.ofmt != .macho) return error.SkipZigTest; if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO @@ -776,7 +775,6 @@ fn should_not_be_zero(x: f128) !void { } test "128-bit multiplication" { - 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 @@ -1204,7 +1202,6 @@ test "allow signed integer division/remainder when values are comptime-known and } test "quad hex float literal parsing accurate" { - 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 @@ -1363,7 +1360,6 @@ test "comptime float rem int" { } test "remainder 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_aarch64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO @@ -1403,7 +1399,6 @@ fn remdivOne(comptime T: type, a: T, b: T, c: T) !void { } test "float remainder division using @rem" { - 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 @@ -1447,7 +1442,6 @@ fn fremOne(comptime T: type, a: T, b: T, c: T, epsilon: T) !void { } test "float modulo division using @mod" { - 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