diff options
Diffstat (limited to 'lib/std/special/compiler_rt/muloti4.zig')
| -rw-r--r-- | lib/std/special/compiler_rt/muloti4.zig | 49 |
1 files changed, 49 insertions, 0 deletions
diff --git a/lib/std/special/compiler_rt/muloti4.zig b/lib/std/special/compiler_rt/muloti4.zig new file mode 100644 index 0000000000..ccde8e3e6c --- /dev/null +++ b/lib/std/special/compiler_rt/muloti4.zig @@ -0,0 +1,49 @@ +const builtin = @import("builtin"); +const compiler_rt = @import("../compiler_rt.zig"); + +pub extern fn __muloti4(a: i128, b: i128, overflow: *c_int) i128 { + @setRuntimeSafety(builtin.is_test); + + const min = @bitCast(i128, u128(1 << (i128.bit_count - 1))); + const max = ~min; + overflow.* = 0; + + const r = a *% b; + if (a == min) { + if (b != 0 and b != 1) { + overflow.* = 1; + } + return r; + } + if (b == min) { + if (a != 0 and a != 1) { + overflow.* = 1; + } + return r; + } + + const sa = a >> (i128.bit_count - 1); + const abs_a = (a ^ sa) -% sa; + const sb = b >> (i128.bit_count - 1); + const abs_b = (b ^ sb) -% sb; + + if (abs_a < 2 or abs_b < 2) { + return r; + } + + if (sa == sb) { + if (abs_a > @divTrunc(max, abs_b)) { + overflow.* = 1; + } + } else { + if (abs_a > @divTrunc(min, -abs_b)) { + overflow.* = 1; + } + } + + return r; +} + +test "import muloti4" { + _ = @import("muloti4_test.zig"); +} |
