authorgravatar for paul.verigo@gmail.comPavel Verigo <paul.verigo@gmail.com> 2026-04-07 00:25:49+02:00
committergravatar for paul.verigo@gmail.comPavel Verigo <paul.verigo@gmail.com> 2026-04-09 00:14:09+02:00
logdf79ea941bc3c355dfcb51c1de3d2d4fd186dd46
tree4007406a7cd5ed31fecdc12a54736c4255946a97
parent0ebd270d907a3fb7e2e600891fe2f455b7b2d4ad

stage2-wasm: bigint abs + test min/max


4 files changed, 140 insertions(+), 1 deletions(-)

lib/compiler_rt/limb64.zig+50
...@@ -977,3 +977,53 @@ test __mulo_limb64 {...@@ -977,3 +977,53 @@ test __mulo_limb64 {
977 try test__mulo_limb64(i200, maxInt(i200), maxInt(i200), .{ 1, true });977 try test__mulo_limb64(i200, maxInt(i200), maxInt(i200), .{ 1, true });
978 try test__mulo_limb64(i200, minInt(i200), minInt(i200), .{ 0, true });978 try test__mulo_limb64(i200, minInt(i200), minInt(i200), .{ 0, true });
979}979}
980
981comptime {
982 symbol(&__abs_limb64, "__abs_limb64");
983}
984
985fn __abs_limb64(out_ptr: [*]u64, a_ptr: [*]const u64, bits: u16) callconv(.c) void {
986 const limb_cnt = limbCount(bits);
987 const out = out_ptr[0..limb_cnt];
988 const a = a_ptr[0..limb_cnt];
989
990 const ms = limbGet(a, limb_cnt - 1);
991 if ((ms >> 63) == 0) {
992 @memcpy(out, a);
993 return;
994 }
995
996 var carry: u1 = 1;
997 var i: usize = 0;
998 while (i < limb_cnt) : (i += 1) {
999 const s = @addWithOverflow(~limbGet(a, i), carry);
1000 limbSet(out, i, s[0]);
1001 carry = s[1];
1002 }
1003}
1004
1005fn test__abs_limb64(comptime T: type, a: T, expected: @Int(.unsigned, @typeInfo(T).int.bits)) !void {
1006 const int_info = @typeInfo(T).int;
1007 comptime assert(int_info.signedness == .signed);
1008
1009 var a_limbs = asLimbs(a);
1010 var out: Limbs(@TypeOf(expected)) = undefined;
1011 __abs_limb64(&out, &a_limbs, int_info.bits);
1012
1013 const expected_limbs = asLimbs(expected);
1014 try testing.expectEqual(expected_limbs, out);
1015}
1016
1017test __abs_limb64 {
1018 try test__abs_limb64(i64, 0, 0);
1019 try test__abs_limb64(i64, -1, 1);
1020 try test__abs_limb64(i64, minInt(i64), 1 << 63);
1021 try test__abs_limb64(i65, -1, 1);
1022 try test__abs_limb64(i65, minInt(i65), 1 << 64);
1023 try test__abs_limb64(i65, maxInt(i65), maxInt(i65));
1024 try test__abs_limb64(i128, -1 << 80, 1 << 80);
1025 try test__abs_limb64(i128, 1 << 64, 1 << 64);
1026 try test__abs_limb64(i200, -1 << 198, 1 << 198);
1027 try test__abs_limb64(i255, -5, 5);
1028 try test__abs_limb64(i255, minInt(i255), 1 << 254);
1029}
src/codegen/wasm/CodeGen.zig+10-1
...@@ -2941,7 +2941,16 @@ fn intAbs(cg: *CodeGen, ty: IntType, operand: WValue) InnerError!WValue {...@@ -2941,7 +2941,16 @@ fn intAbs(cg: *CodeGen, ty: IntType, operand: WValue) InnerError!WValue {
2941 const b = try cg.intSub(u128_ty, a, mask);2941 const b = try cg.intSub(u128_ty, a, mask);
2942 return b;2942 return b;
2943 },2943 },
2944 else => return cg.fail("TODO: Support intAbs for integer bitsize: {d}", .{ty.bits}),2944 else => {
2945 const result = try cg.allocInt(ty);
2946
2947 try cg.lowerToStack(result);
2948 try cg.lowerToStack(operand);
2949 try cg.addImm32(ty.bits);
2950 try cg.addCallIntrinsic(.__abs_limb64);
2951
2952 return result;
2953 },
2945 }2954 }
2946}2955}
29472956
src/codegen/wasm/Mir.zig+1
...@@ -1019,4 +1019,5 @@ pub const Intrinsic = enum(u32) {...@@ -1019,4 +1019,5 @@ pub const Intrinsic = enum(u32) {
1019 __bitreverse_limb64,1019 __bitreverse_limb64,
1020 __byteswap_limb64,1020 __byteswap_limb64,
1021 __mulo_limb64,1021 __mulo_limb64,
1022 __abs_limb64,
1022};1023};
test/behavior/math.zig+79
...@@ -1657,6 +1657,85 @@ test "@byteSwap > 128 bits" {...@@ -1657,6 +1657,85 @@ test "@byteSwap > 128 bits" {
1657 try testByteSwap(i256, 1 << 120, 1 << 128);1657 try testByteSwap(i256, 1 << 120, 1 << 128);
1658}1658}
16591659
1660fn testMax(comptime T: type, a: T, b: T, expected: T) !void {
1661 try expect(@max(a, b) == expected);
1662}
1663
1664test "@max > 128 bits" {
1665 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
1666
1667 try testMax(u140, 0, maxInt(u140), maxInt(u140));
1668 try testMax(u140, 1 << 139, 1 << 138, 1 << 139);
1669 try testMax(u140, (1 << 100) + 7, (1 << 100) + 3, (1 << 100) + 7);
1670 try testMax(u140, maxInt(u140) - 1, maxInt(u140), maxInt(u140));
1671
1672 try testMax(u200, 1 << 199, 1 << 198, 1 << 199);
1673 try testMax(u200, (1 << 150) + (1 << 17), (1 << 150) + (1 << 18), (1 << 150) + (1 << 18));
1674 try testMax(u200, 0, 1 << 123, 1 << 123);
1675 try testMax(u200, maxInt(u200), maxInt(u200) - 1, maxInt(u200));
1676
1677 try testMax(i140, -1, 0, 0);
1678 try testMax(i140, minInt(i140), maxInt(i140), maxInt(i140));
1679 try testMax(i140, -1 << 70, -1 << 69, -1 << 69);
1680 try testMax(i140, (1 << 100) - 1, 1 << 100, 1 << 100);
1681
1682 try testMax(i200, -1, minInt(i200), -1);
1683 try testMax(i200, -1 << 150, -1 << 149, -1 << 149);
1684 try testMax(i200, 1 << 198, (1 << 198) - 1, 1 << 198);
1685 try testMax(i200, maxInt(i200), 0, maxInt(i200));
1686}
1687
1688fn testMin(comptime T: type, a: T, b: T, expected: T) !void {
1689 try expect(@min(a, b) == expected);
1690}
1691
1692test "@min > 128 bits" {
1693 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
1694
1695 try testMin(u140, 0, maxInt(u140), 0);
1696 try testMin(u140, 1 << 139, 1 << 138, 1 << 138);
1697 try testMin(u140, (1 << 100) + 7, (1 << 100) + 3, (1 << 100) + 3);
1698 try testMin(u140, maxInt(u140) - 1, maxInt(u140), maxInt(u140) - 1);
1699
1700 try testMin(u200, 1 << 199, 1 << 198, 1 << 198);
1701 try testMin(u200, (1 << 150) + (1 << 17), (1 << 150) + (1 << 18), (1 << 150) + (1 << 17));
1702 try testMin(u200, 0, 1 << 123, 0);
1703 try testMin(u200, maxInt(u200), maxInt(u200) - 1, maxInt(u200) - 1);
1704
1705 try testMin(i140, -1, 0, -1);
1706 try testMin(i140, minInt(i140), maxInt(i140), minInt(i140));
1707 try testMin(i140, -1 << 70, -1 << 69, -1 << 70);
1708 try testMin(i140, (1 << 100) - 1, 1 << 100, (1 << 100) - 1);
1709
1710 try testMin(i200, -1, minInt(i200), minInt(i200));
1711 try testMin(i200, -1 << 150, -1 << 149, -1 << 150);
1712 try testMin(i200, 1 << 198, (1 << 198) - 1, (1 << 198) - 1);
1713 try testMin(i200, maxInt(i200), 0, 0);
1714}
1715
1716fn testAbs(comptime T: type, a: T, expected: anytype) !void {
1717 try expect(@abs(a) == expected);
1718}
1719
1720test "@abs > 128 bits" {
1721 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
1722
1723 try testAbs(u140, 0, 0);
1724 try testAbs(u140, 1 << 139, 1 << 139);
1725 try testAbs(u200, 123456789, 123456789);
1726 try testAbs(u200, maxInt(u200), maxInt(u200));
1727
1728 try testAbs(i140, 0, 0);
1729 try testAbs(i140, 1, 1);
1730 try testAbs(i140, -1, 1);
1731 try testAbs(i140, minInt(i140), 1 << 139);
1732
1733 try testAbs(i200, 1 << 198, 1 << 198);
1734 try testAbs(i200, -1 << 198, 1 << 198);
1735 try testAbs(i200, maxInt(i200), maxInt(i200));
1736 try testAbs(i200, minInt(i200), 1 << 199);
1737}
1738
1660test "overflow arithmetic with u0 values" {1739test "overflow arithmetic with u0 values" {
1661 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;1740 if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
16621741