2018-06-13 03:25:04 -07:00
|
|
|
const builtin = @import("builtin");
|
2019-03-02 13:46:04 -08:00
|
|
|
const compiler_rt = @import("../compiler_rt.zig");
|
2018-06-13 03:25:04 -07:00
|
|
|
|
2020-01-06 12:34:50 -08:00
|
|
|
pub fn __muloti4(a: i128, b: i128, overflow: *c_int) callconv(.C) i128 {
|
2018-06-13 03:25:04 -07:00
|
|
|
@setRuntimeSafety(builtin.is_test);
|
|
|
|
|
2019-11-06 20:25:57 -08:00
|
|
|
const min = @bitCast(i128, @as(u128, 1 << (i128.bit_count - 1)));
|
2018-06-13 03:25:04 -07:00
|
|
|
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) {
|
2019-04-10 13:29:10 -07:00
|
|
|
if (abs_a > @divTrunc(max, abs_b)) {
|
2018-06-13 03:25:04 -07:00
|
|
|
overflow.* = 1;
|
|
|
|
}
|
|
|
|
} else {
|
2019-04-10 13:29:10 -07:00
|
|
|
if (abs_a > @divTrunc(min, -abs_b)) {
|
2018-06-13 03:25:04 -07:00
|
|
|
overflow.* = 1;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return r;
|
|
|
|
}
|
2018-06-14 02:18:36 -07:00
|
|
|
|
|
|
|
test "import muloti4" {
|
|
|
|
_ = @import("muloti4_test.zig");
|
|
|
|
}
|