Commit 4b89a4c7cb

Pavel Verigo <paul.verigo@gmail.com>
2024-10-08 16:44:19
stage2-wasm: airRem + airMod for floats
1 parent b00cbec
Changed files (2)
src
arch
test
behavior
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 {
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