diff options
| author | Andrew Kelley <andrew@ziglang.org> | 2019-04-29 18:54:21 -0400 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2019-04-29 18:54:21 -0400 |
| commit | d2328ac71a927df3ce9b7cec09c90dbb04ec3018 (patch) | |
| tree | c9a70c664767e2d797f6a56e475aeb5e0940eeef /std | |
| parent | 75d42ace31e8965a6bce04965dfc4a9a7b322b4f (diff) | |
| parent | 4e241263ff0081a756d4d331f1e78e571342bea4 (diff) | |
| download | zig-d2328ac71a927df3ce9b7cec09c90dbb04ec3018.tar.gz zig-d2328ac71a927df3ce9b7cec09c90dbb04ec3018.zip | |
Merge pull request #2372 from LemonBoy/aeabi_idiv
compiler-rt: Add __divsi3, __aeabi_idiv
Diffstat (limited to 'std')
| -rw-r--r-- | std/special/compiler_rt.zig | 82 |
1 files changed, 81 insertions, 1 deletions
diff --git a/std/special/compiler_rt.zig b/std/special/compiler_rt.zig index 6a0f832047..d6af9535d7 100644 --- a/std/special/compiler_rt.zig +++ b/std/special/compiler_rt.zig @@ -102,9 +102,11 @@ comptime { @export("__udivmoddi4", @import("compiler_rt/udivmoddi4.zig").__udivmoddi4, linkage); @export("__popcountdi2", @import("compiler_rt/popcountdi2.zig").__popcountdi2, linkage); + @export("__divsi3", __divsi3, linkage); @export("__udivsi3", __udivsi3, linkage); @export("__udivdi3", __udivdi3, linkage); @export("__umoddi3", __umoddi3, linkage); + @export("__divmodsi4", __divmodsi4, linkage); @export("__udivmodsi4", __udivmodsi4, linkage); @export("__negsf2", @import("compiler_rt/negXf2.zig").__negsf2, linkage); @@ -112,8 +114,11 @@ comptime { if (is_arm_arch and !is_arm_64) { @export("__aeabi_uldivmod", __aeabi_uldivmod, linkage); - @export("__aeabi_uidivmod", __aeabi_uidivmod, linkage); + + @export("__aeabi_idiv", __divsi3, linkage); + @export("__aeabi_idivmod", __divmodsi4, linkage); @export("__aeabi_uidiv", __udivsi3, linkage); + @export("__aeabi_uidivmod", __aeabi_uidivmod, linkage); @export("__aeabi_memcpy", __aeabi_memcpy, linkage); @export("__aeabi_memcpy4", __aeabi_memcpy, linkage); @@ -558,6 +563,14 @@ nakedcc fn ___chkstk_ms() align(4) void { ); } +extern fn __divmodsi4(a: i32, b: i32, rem: *i32) i32 { + @setRuntimeSafety(is_test); + + const d = __divsi3(a, b); + rem.* = a -% (d * b); + return d; +} + extern fn __udivmodsi4(a: u32, b: u32, rem: *u32) u32 { @setRuntimeSafety(is_test); @@ -566,6 +579,20 @@ extern fn __udivmodsi4(a: u32, b: u32, rem: *u32) u32 { return d; } +extern fn __divsi3(n: i32, d: i32) i32 { + @setRuntimeSafety(is_test); + + // Set aside the sign of the quotient. + const sign = @bitCast(u32, (n ^ d) >> 31); + // Take absolute value of a and b via abs(x) = (x^(x >> 31)) - (x >> 31). + const abs_n = (n ^ (n >> 31)) -% (n >> 31); + const abs_d = (d ^ (d >> 31)) -% (d >> 31); + // abs(a) / abs(b) + const res = @bitCast(u32, abs_n) / @bitCast(u32, abs_d); + // Apply sign of quotient to result and return. + return @bitCast(i32, (res ^ sign) -% sign); +} + extern fn __udivsi3(n: u32, d: u32) u32 { @setRuntimeSafety(is_test); @@ -1293,3 +1320,56 @@ fn test_one_udivsi3(a: u32, b: u32, expected_q: u32) void { const q: u32 = __udivsi3(a, b); testing.expect(q == expected_q); } + +test "test_divsi3" { + const cases = [][3]i32{ + []i32{ 0, 1, 0}, + []i32{ 0, -1, 0}, + []i32{ 2, 1, 2}, + []i32{ 2, -1, -2}, + []i32{-2, 1, -2}, + []i32{-2, -1, 2}, + + []i32{@bitCast(i32, u32(0x80000000)), 1, @bitCast(i32, u32(0x80000000))}, + []i32{@bitCast(i32, u32(0x80000000)), -1, @bitCast(i32, u32(0x80000000))}, + []i32{@bitCast(i32, u32(0x80000000)), -2, 0x40000000}, + []i32{@bitCast(i32, u32(0x80000000)), 2, @bitCast(i32, u32(0xC0000000))}, + }; + + for (cases) |case| { + test_one_divsi3(case[0], case[1], case[2]); + } +} + +fn test_one_divsi3(a: i32, b: i32, expected_q: i32) void { + const q: i32 = __divsi3(a, b); + testing.expect(q == expected_q); +} + +test "test_divmodsi4" { + const cases = [][4]i32{ + []i32{ 0, 1, 0, 0}, + []i32{ 0, -1, 0, 0}, + []i32{ 2, 1, 2, 0}, + []i32{ 2, -1, -2, 0}, + []i32{-2, 1, -2, 0}, + []i32{-2, -1, 2, 0}, + []i32{ 7, 5, 1, 2}, + []i32{-7, 5, -1, -2}, + []i32{19, 5, 3, 4}, + []i32{19, -5, -3, 4}, + + []i32{@bitCast(i32, u32(0x80000000)), 8, @bitCast(i32, u32(0xf0000000)), 0}, + []i32{@bitCast(i32, u32(0x80000007)), 8, @bitCast(i32, u32(0xf0000001)), -1}, + }; + + for (cases) |case| { + test_one_divmodsi4(case[0], case[1], case[2], case[3]); + } +} + +fn test_one_divmodsi4(a: i32, b: i32, expected_q: i32, expected_r: i32) void { + var r: i32 = undefined; + const q: i32 = __divmodsi4(a, b, &r); + testing.expect(q == expected_q and r == expected_r); +} |
