From d976b4e4a56e4ac6b45a3d9ae9766e57bf04f82b Mon Sep 17 00:00:00 2001 From: matu3ba Date: Sat, 11 Feb 2023 13:41:08 +0100 Subject: [PATCH] compiler_rt: __divmodti4 for libgcc symbol compatibility - Copy and adjust __divmodsi4 tests for __divmoddi4 and __divmodti4. - Assuming d = a/b does not overflow (MIN/-1) or uses div by 0, then tmp = (d * b) = (a/b * b) = a does not overflow. => Remove wraparound for remainder in applicable routines. --- lib/compiler_rt/README.md | 2 +- lib/compiler_rt/int.zig | 68 +++++++++++++++++++++++++++++++++++++-- tools/gen_stubs.zig | 1 + 3 files changed, 67 insertions(+), 4 deletions(-) diff --git a/lib/compiler_rt/README.md b/lib/compiler_rt/README.md index 87a8acb756..8d9cf4a135 100644 --- a/lib/compiler_rt/README.md +++ b/lib/compiler_rt/README.md @@ -114,7 +114,7 @@ Integer and Float Operations | ✓ | __udivmodti4 | u128 | u128 | u128 | .. | | ✓ | __divmodsi4 | i32 | i32 | i32 | `a / b, rem.* = a % b` | | ✓ | __divmoddi4 | i64 | i64 | i64 | .. | -| ✗ | __divmodti4 | i128 | i128 | i128 | .. [^libgcc_compat] | +| ✓ | __divmodti4 | i128 | i128 | i128 | .. [^libgcc_compat] | | | | | | | **Integer Arithmetic with Trapping Overflow**| | ✓ | __absvsi2 | i32 | i32 | i32 | abs(a) | | ✓ | __absvdi2 | i64 | i64 | i64 | .. | diff --git a/lib/compiler_rt/int.zig b/lib/compiler_rt/int.zig index b844af1859..6a761807dd 100644 --- a/lib/compiler_rt/int.zig +++ b/lib/compiler_rt/int.zig @@ -9,10 +9,12 @@ const arch = builtin.cpu.arch; const is_test = builtin.is_test; const common = @import("common.zig"); const udivmod = @import("udivmod.zig").udivmod; +const __divti3 = @import("divti3.zig").__divti3; pub const panic = common.panic; comptime { + @export(__divmodti4, .{ .name = "__divmodti4", .linkage = common.linkage, .visibility = common.visibility }); @export(__udivmoddi4, .{ .name = "__udivmoddi4", .linkage = common.linkage, .visibility = common.visibility }); @export(__mulsi3, .{ .name = "__mulsi3", .linkage = common.linkage, .visibility = common.visibility }); @export(__divmoddi4, .{ .name = "__divmoddi4", .linkage = common.linkage, .visibility = common.visibility }); @@ -33,12 +35,72 @@ comptime { @export(__udivmodsi4, .{ .name = "__udivmodsi4", .linkage = common.linkage, .visibility = common.visibility }); } +pub fn __divmodti4(a: i128, b: i128, rem: *i128) callconv(.C) i128 { + const d = __divti3(a, b); + rem.* = a -% (d * b); + return d; +} + +test "test_divmodti4" { + const cases = [_][4]i128{ + [_]i128{ 0, 1, 0, 0 }, + [_]i128{ 0, -1, 0, 0 }, + [_]i128{ 2, 1, 2, 0 }, + [_]i128{ 2, -1, -2, 0 }, + [_]i128{ -2, 1, -2, 0 }, + [_]i128{ -2, -1, 2, 0 }, + [_]i128{ 7, 5, 1, 2 }, + [_]i128{ -7, 5, -1, -2 }, + [_]i128{ 19, 5, 3, 4 }, + [_]i128{ 19, -5, -3, 4 }, + [_]i128{ @bitCast(i128, @as(u128, 0x80000000000000000000000000000000)), 8, @bitCast(i128, @as(u128, 0xf0000000000000000000000000000000)), 0 }, + [_]i128{ @bitCast(i128, @as(u128, 0x80000000000000000000000000000007)), 8, @bitCast(i128, @as(u128, 0xf0000000000000000000000000000001)), -1 }, + }; + + for (cases) |case| { + try test_one_divmodti4(case[0], case[1], case[2], case[3]); + } +} + +fn test_one_divmodti4(a: i128, b: i128, expected_q: i128, expected_r: i128) !void { + var r: i128 = undefined; + const q: i128 = __divmodti4(a, b, &r); + try testing.expect(q == expected_q and r == expected_r); +} + pub fn __divmoddi4(a: i64, b: i64, rem: *i64) callconv(.C) i64 { const d = __divdi3(a, b); - rem.* = a -% (d *% b); + rem.* = a -% (d * b); return d; } +test "test_divmoddi4" { + const cases = [_][4]i64{ + [_]i64{ 0, 1, 0, 0 }, + [_]i64{ 0, -1, 0, 0 }, + [_]i64{ 2, 1, 2, 0 }, + [_]i64{ 2, -1, -2, 0 }, + [_]i64{ -2, 1, -2, 0 }, + [_]i64{ -2, -1, 2, 0 }, + [_]i64{ 7, 5, 1, 2 }, + [_]i64{ -7, 5, -1, -2 }, + [_]i64{ 19, 5, 3, 4 }, + [_]i64{ 19, -5, -3, 4 }, + [_]i64{ @bitCast(i64, @as(u64, 0x8000000000000000)), 8, @bitCast(i64, @as(u64, 0xf000000000000000)), 0 }, + [_]i64{ @bitCast(i64, @as(u64, 0x8000000000000007)), 8, @bitCast(i64, @as(u64, 0xf000000000000001)), -1 }, + }; + + for (cases) |case| { + try test_one_divmoddi4(case[0], case[1], case[2], case[3]); + } +} + +fn test_one_divmoddi4(a: i64, b: i64, expected_q: i64, expected_r: i64) !void { + var r: i64 = undefined; + const q: i64 = __divmoddi4(a, b, &r); + try testing.expect(q == expected_q and r == expected_r); +} + pub fn __udivmoddi4(a: u64, b: u64, maybe_rem: ?*u64) callconv(.C) u64 { return udivmod(u64, a, b, maybe_rem); } @@ -424,7 +486,7 @@ fn test_one_udivsi3(a: u32, b: u32, expected_q: u32) !void { } pub fn __modsi3(n: i32, d: i32) callconv(.C) i32 { - return n -% __divsi3(n, d) *% d; + return n -% __divsi3(n, d) * d; } test "test_modsi3" { @@ -453,7 +515,7 @@ fn test_one_modsi3(a: i32, b: i32, expected_r: i32) !void { } pub fn __umodsi3(n: u32, d: u32) callconv(.C) u32 { - return n -% __udivsi3(n, d) *% d; + return n -% __udivsi3(n, d) * d; } test "test_umodsi3" { diff --git a/tools/gen_stubs.zig b/tools/gen_stubs.zig index 3e9a92086b..b1783b96ba 100644 --- a/tools/gen_stubs.zig +++ b/tools/gen_stubs.zig @@ -666,6 +666,7 @@ const blacklisted_symbols = [_][]const u8{ "__divkf3", "__divmoddi4", "__divmodsi4", + "__divmodti4", "__divsf3", "__divsi3", "__divtf3",