Commit d976b4e4a5

matu3ba <matu3ba@users.noreply.github.com>
2023-02-11 13:41:08
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.
1 parent ba680aa
Changed files (3)
lib
compiler_rt
tools
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" {
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  | ..                             |
tools/gen_stubs.zig
@@ -666,6 +666,7 @@ const blacklisted_symbols = [_][]const u8{
     "__divkf3",
     "__divmoddi4",
     "__divmodsi4",
+    "__divmodti4",
     "__divsf3",
     "__divsi3",
     "__divtf3",