diff --git a/CMakeLists.txt b/CMakeLists.txt index 6bab57bd1f..7090f88527 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -211,10 +211,10 @@ set(ZIG_STAGE2_SOURCES lib/compiler_rt/absvti2.zig lib/compiler_rt/adddf3.zig lib/compiler_rt/addf3.zig - lib/compiler_rt/addo.zig lib/compiler_rt/addsf3.zig lib/compiler_rt/addtf3.zig lib/compiler_rt/addvsi3.zig + lib/compiler_rt/addvdi3.zig lib/compiler_rt/addxf3.zig lib/compiler_rt/arm.zig lib/compiler_rt/atomics.zig @@ -354,7 +354,6 @@ set(ZIG_STAGE2_SOURCES lib/compiler_rt/sqrt.zig lib/compiler_rt/stack_probe.zig lib/compiler_rt/subdf3.zig - lib/compiler_rt/subo.zig lib/compiler_rt/subsf3.zig lib/compiler_rt/subtf3.zig lib/compiler_rt/subvdi3.zig diff --git a/lib/compiler_rt.zig b/lib/compiler_rt.zig index aac81bf414..040d2c6c41 100644 --- a/lib/compiler_rt.zig +++ b/lib/compiler_rt.zig @@ -28,12 +28,13 @@ comptime { _ = @import("compiler_rt/negv.zig"); _ = @import("compiler_rt/addvsi3.zig"); + _ = @import("compiler_rt/addvdi3.zig"); + _ = @import("compiler_rt/subvsi3.zig"); _ = @import("compiler_rt/subvdi3.zig"); + _ = @import("compiler_rt/mulvsi3.zig"); - _ = @import("compiler_rt/addo.zig"); - _ = @import("compiler_rt/subo.zig"); _ = @import("compiler_rt/mulo.zig"); // Float routines diff --git a/lib/compiler_rt/addo.zig b/lib/compiler_rt/addo.zig deleted file mode 100644 index 610d620690..0000000000 --- a/lib/compiler_rt/addo.zig +++ /dev/null @@ -1,46 +0,0 @@ -const std = @import("std"); -const common = @import("./common.zig"); -pub const panic = @import("common.zig").panic; - -comptime { - @export(&__addosi4, .{ .name = "__addosi4", .linkage = common.linkage, .visibility = common.visibility }); - @export(&__addodi4, .{ .name = "__addodi4", .linkage = common.linkage, .visibility = common.visibility }); - @export(&__addoti4, .{ .name = "__addoti4", .linkage = common.linkage, .visibility = common.visibility }); -} - -// addo - add overflow -// * return a+%b. -// * return if a+b overflows => 1 else => 0 -// - addoXi4_generic as default - -inline fn addoXi4_generic(comptime ST: type, a: ST, b: ST, overflow: *c_int) ST { - @setRuntimeSafety(common.test_safety); - overflow.* = 0; - const sum: ST = a +% b; - // Hackers Delight: section Overflow Detection, subsection Signed Add/Subtract - // Let sum = a +% b == a + b + carry == wraparound addition. - // Overflow in a+b+carry occurs, iff a and b have opposite signs - // and the sign of a+b+carry is the same as a (or equivalently b). - // Slower routine: res = ~(a ^ b) & ((sum ^ a) - // Faster routine: res = (sum ^ a) & (sum ^ b) - // Overflow occurred, iff (res < 0) - if (((sum ^ a) & (sum ^ b)) < 0) - overflow.* = 1; - return sum; -} - -pub fn __addosi4(a: i32, b: i32, overflow: *c_int) callconv(.c) i32 { - return addoXi4_generic(i32, a, b, overflow); -} -pub fn __addodi4(a: i64, b: i64, overflow: *c_int) callconv(.c) i64 { - return addoXi4_generic(i64, a, b, overflow); -} -pub fn __addoti4(a: i128, b: i128, overflow: *c_int) callconv(.c) i128 { - return addoXi4_generic(i128, a, b, overflow); -} - -test { - _ = @import("addosi4_test.zig"); - _ = @import("addodi4_test.zig"); - _ = @import("addoti4_test.zig"); -} diff --git a/lib/compiler_rt/addodi4_test.zig b/lib/compiler_rt/addodi4_test.zig deleted file mode 100644 index 92f8e9c1f2..0000000000 --- a/lib/compiler_rt/addodi4_test.zig +++ /dev/null @@ -1,77 +0,0 @@ -const addv = @import("addo.zig"); -const std = @import("std"); -const testing = std.testing; -const math = std.math; - -fn test__addodi4(a: i64, b: i64) !void { - var result_ov: c_int = undefined; - var expected_ov: c_int = undefined; - const result = addv.__addodi4(a, b, &result_ov); - const expected: i64 = simple_addodi4(a, b, &expected_ov); - try testing.expectEqual(expected, result); - try testing.expectEqual(expected_ov, result_ov); -} - -fn simple_addodi4(a: i64, b: i64, overflow: *c_int) i64 { - overflow.* = 0; - const min: i64 = math.minInt(i64); - const max: i64 = math.maxInt(i64); - if (((a > 0) and (b > max - a)) or - ((a < 0) and (b < min - a))) - overflow.* = 1; - return a +% b; -} - -test "addodi4" { - const min: i64 = math.minInt(i64); - const max: i64 = math.maxInt(i64); - var i: i64 = 1; - while (i < max) : (i *|= 2) { - try test__addodi4(i, i); - try test__addodi4(-i, -i); - try test__addodi4(i, -i); - try test__addodi4(-i, i); - } - - // edge cases - // 0 + 0 = 0 - // MIN + MIN overflow - // MAX + MAX overflow - // 0 + MIN MIN - // 0 + MAX MAX - // MIN + 0 MIN - // MAX + 0 MAX - // MIN + MAX -1 - // MAX + MIN -1 - try test__addodi4(0, 0); - try test__addodi4(min, min); - try test__addodi4(max, max); - try test__addodi4(0, min); - try test__addodi4(0, max); - try test__addodi4(min, 0); - try test__addodi4(max, 0); - try test__addodi4(min, max); - try test__addodi4(max, min); - - // derived edge cases - // MIN+1 + MIN overflow - // MAX-1 + MAX overflow - // 1 + MIN = MIN+1 - // -1 + MIN overflow - // -1 + MAX = MAX-1 - // +1 + MAX overflow - // MIN + 1 = MIN+1 - // MIN + -1 overflow - // MAX + 1 overflow - // MAX + -1 = MAX-1 - try test__addodi4(min + 1, min); - try test__addodi4(max - 1, max); - try test__addodi4(1, min); - try test__addodi4(-1, min); - try test__addodi4(-1, max); - try test__addodi4(1, max); - try test__addodi4(min, 1); - try test__addodi4(min, -1); - try test__addodi4(max, -1); - try test__addodi4(max, 1); -} diff --git a/lib/compiler_rt/addosi4_test.zig b/lib/compiler_rt/addosi4_test.zig deleted file mode 100644 index 3494909f50..0000000000 --- a/lib/compiler_rt/addosi4_test.zig +++ /dev/null @@ -1,78 +0,0 @@ -const addv = @import("addo.zig"); -const testing = @import("std").testing; - -fn test__addosi4(a: i32, b: i32) !void { - var result_ov: c_int = undefined; - var expected_ov: c_int = undefined; - const result = addv.__addosi4(a, b, &result_ov); - const expected: i32 = simple_addosi4(a, b, &expected_ov); - try testing.expectEqual(expected, result); - try testing.expectEqual(expected_ov, result_ov); -} - -fn simple_addosi4(a: i32, b: i32, overflow: *c_int) i32 { - overflow.* = 0; - const min: i32 = -2147483648; - const max: i32 = 2147483647; - if (((a > 0) and (b > max - a)) or - ((a < 0) and (b < min - a))) - overflow.* = 1; - return a +% b; -} - -test "addosi4" { - // -2^31 <= i32 <= 2^31-1 - // 2^31 = 2147483648 - // 2^31-1 = 2147483647 - const min: i32 = -2147483648; - const max: i32 = 2147483647; - var i: i32 = 1; - while (i < max) : (i *|= 2) { - try test__addosi4(i, i); - try test__addosi4(-i, -i); - try test__addosi4(i, -i); - try test__addosi4(-i, i); - } - - // edge cases - // 0 + 0 = 0 - // MIN + MIN overflow - // MAX + MAX overflow - // 0 + MIN MIN - // 0 + MAX MAX - // MIN + 0 MIN - // MAX + 0 MAX - // MIN + MAX -1 - // MAX + MIN -1 - try test__addosi4(0, 0); - try test__addosi4(min, min); - try test__addosi4(max, max); - try test__addosi4(0, min); - try test__addosi4(0, max); - try test__addosi4(min, 0); - try test__addosi4(max, 0); - try test__addosi4(min, max); - try test__addosi4(max, min); - - // derived edge cases - // MIN+1 + MIN overflow - // MAX-1 + MAX overflow - // 1 + MIN = MIN+1 - // -1 + MIN overflow - // -1 + MAX = MAX-1 - // +1 + MAX overflow - // MIN + 1 = MIN+1 - // MIN + -1 overflow - // MAX + 1 overflow - // MAX + -1 = MAX-1 - try test__addosi4(min + 1, min); - try test__addosi4(max - 1, max); - try test__addosi4(1, min); - try test__addosi4(-1, min); - try test__addosi4(-1, max); - try test__addosi4(1, max); - try test__addosi4(min, 1); - try test__addosi4(min, -1); - try test__addosi4(max, -1); - try test__addosi4(max, 1); -} diff --git a/lib/compiler_rt/addoti4_test.zig b/lib/compiler_rt/addoti4_test.zig deleted file mode 100644 index d031d1d428..0000000000 --- a/lib/compiler_rt/addoti4_test.zig +++ /dev/null @@ -1,80 +0,0 @@ -const addv = @import("addo.zig"); -const builtin = @import("builtin"); -const std = @import("std"); -const testing = std.testing; -const math = std.math; - -fn test__addoti4(a: i128, b: i128) !void { - var result_ov: c_int = undefined; - var expected_ov: c_int = undefined; - const result = addv.__addoti4(a, b, &result_ov); - const expected: i128 = simple_addoti4(a, b, &expected_ov); - try testing.expectEqual(expected, result); - try testing.expectEqual(expected_ov, result_ov); -} - -fn simple_addoti4(a: i128, b: i128, overflow: *c_int) i128 { - overflow.* = 0; - const min: i128 = math.minInt(i128); - const max: i128 = math.maxInt(i128); - if (((a > 0) and (b > max - a)) or - ((a < 0) and (b < min - a))) - overflow.* = 1; - return a +% b; -} - -test "addoti4" { - if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; - - const min: i128 = math.minInt(i128); - const max: i128 = math.maxInt(i128); - var i: i128 = 1; - while (i < max) : (i *|= 2) { - try test__addoti4(i, i); - try test__addoti4(-i, -i); - try test__addoti4(i, -i); - try test__addoti4(-i, i); - } - - // edge cases - // 0 + 0 = 0 - // MIN + MIN overflow - // MAX + MAX overflow - // 0 + MIN MIN - // 0 + MAX MAX - // MIN + 0 MIN - // MAX + 0 MAX - // MIN + MAX -1 - // MAX + MIN -1 - try test__addoti4(0, 0); - try test__addoti4(min, min); - try test__addoti4(max, max); - try test__addoti4(0, min); - try test__addoti4(0, max); - try test__addoti4(min, 0); - try test__addoti4(max, 0); - try test__addoti4(min, max); - try test__addoti4(max, min); - - // derived edge cases - // MIN+1 + MIN overflow - // MAX-1 + MAX overflow - // 1 + MIN = MIN+1 - // -1 + MIN overflow - // -1 + MAX = MAX-1 - // +1 + MAX overflow - // MIN + 1 = MIN+1 - // MIN + -1 overflow - // MAX + 1 overflow - // MAX + -1 = MAX-1 - try test__addoti4(min + 1, min); - try test__addoti4(max - 1, max); - try test__addoti4(1, min); - try test__addoti4(-1, min); - try test__addoti4(-1, max); - try test__addoti4(1, max); - try test__addoti4(min, 1); - try test__addoti4(min, -1); - try test__addoti4(max, -1); - try test__addoti4(max, 1); -} diff --git a/lib/compiler_rt/addvdi3.zig b/lib/compiler_rt/addvdi3.zig new file mode 100644 index 0000000000..03aa9b91c7 --- /dev/null +++ b/lib/compiler_rt/addvdi3.zig @@ -0,0 +1,26 @@ +const common = @import("./common.zig"); +const testing = @import("std").testing; + +pub const panic = common.panic; + +comptime { + @export(&__addvdi3, .{ .name = "__addvdi3", .linkage = common.linkage, .visibility = common.visibility }); +} + +pub fn __addvdi3(a: i64, b: i64) callconv(.c) i64 { + const sum = a +% b; + // Overflow occurred iff both operands have the same sign, and the sign of the sum does + // not match it. In other words, iff the sum sign is not the sign of either operand. + if (((sum ^ a) & (sum ^ b)) < 0) @panic("compiler-rt: integer overflow"); + return sum; +} + +test "addvdi3" { + // const min: i64 = -9223372036854775808 + // const max: i64 = 9223372036854775807 + // TODO write panic handler for testing panics + // try test__addvdi3(-9223372036854775808, -1, -1); // panic + // try test__addvdi3(9223372036854775807, 1, 1); // panic + try testing.expectEqual(-9223372036854775808, __addvdi3(-9223372036854775807, -1)); + try testing.expectEqual(9223372036854775807, __addvdi3(9223372036854775806, 1)); +} diff --git a/lib/compiler_rt/addvsi3.zig b/lib/compiler_rt/addvsi3.zig index 04c19881bc..e688fdba58 100644 --- a/lib/compiler_rt/addvsi3.zig +++ b/lib/compiler_rt/addvsi3.zig @@ -1,4 +1,3 @@ -const addv = @import("addo.zig"); const common = @import("./common.zig"); const testing = @import("std").testing; @@ -9,9 +8,10 @@ comptime { } pub fn __addvsi3(a: i32, b: i32) callconv(.c) i32 { - var overflow: c_int = 0; - const sum = addv.__addosi4(a, b, &overflow); - if (overflow != 0) @panic("compiler-rt: integer overflow"); + const sum = a +% b; + // Overflow occurred iff both operands have the same sign, and the sign of the sum does + // not match it. In other words, iff the sum sign is not the sign of either operand. + if (((sum ^ a) & (sum ^ b)) < 0) @panic("compiler-rt: integer overflow"); return sum; } diff --git a/lib/compiler_rt/subo.zig b/lib/compiler_rt/subo.zig deleted file mode 100644 index b4fb8f7710..0000000000 --- a/lib/compiler_rt/subo.zig +++ /dev/null @@ -1,47 +0,0 @@ -//! subo - subtract overflow -//! * return a-%b. -//! * return if a-b overflows => 1 else => 0 -//! - suboXi4_generic as default - -const std = @import("std"); -const builtin = @import("builtin"); -const common = @import("common.zig"); - -pub const panic = common.panic; - -comptime { - @export(&__subosi4, .{ .name = "__subosi4", .linkage = common.linkage, .visibility = common.visibility }); - @export(&__subodi4, .{ .name = "__subodi4", .linkage = common.linkage, .visibility = common.visibility }); - @export(&__suboti4, .{ .name = "__suboti4", .linkage = common.linkage, .visibility = common.visibility }); -} - -pub fn __subosi4(a: i32, b: i32, overflow: *c_int) callconv(.c) i32 { - return suboXi4_generic(i32, a, b, overflow); -} -pub fn __subodi4(a: i64, b: i64, overflow: *c_int) callconv(.c) i64 { - return suboXi4_generic(i64, a, b, overflow); -} -pub fn __suboti4(a: i128, b: i128, overflow: *c_int) callconv(.c) i128 { - return suboXi4_generic(i128, a, b, overflow); -} - -inline fn suboXi4_generic(comptime ST: type, a: ST, b: ST, overflow: *c_int) ST { - overflow.* = 0; - const sum: ST = a -% b; - // Hackers Delight: section Overflow Detection, subsection Signed Add/Subtract - // Let sum = a -% b == a - b - carry == wraparound subtraction. - // Overflow in a-b-carry occurs, iff a and b have opposite signs - // and the sign of a-b-carry is opposite of a (or equivalently same as b). - // Faster routine: res = (a ^ b) & (sum ^ a) - // Slower routine: res = (sum^a) & ~(sum^b) - // Overflow occurred, iff (res < 0) - if (((a ^ b) & (sum ^ a)) < 0) - overflow.* = 1; - return sum; -} - -test { - _ = @import("subosi4_test.zig"); - _ = @import("subodi4_test.zig"); - _ = @import("suboti4_test.zig"); -} diff --git a/lib/compiler_rt/subodi4_test.zig b/lib/compiler_rt/subodi4_test.zig deleted file mode 100644 index 2dd717e14b..0000000000 --- a/lib/compiler_rt/subodi4_test.zig +++ /dev/null @@ -1,81 +0,0 @@ -const subo = @import("subo.zig"); -const std = @import("std"); -const testing = std.testing; -const math = std.math; - -fn test__subodi4(a: i64, b: i64) !void { - var result_ov: c_int = undefined; - var expected_ov: c_int = undefined; - const result = subo.__subodi4(a, b, &result_ov); - const expected: i64 = simple_subodi4(a, b, &expected_ov); - try testing.expectEqual(expected, result); - try testing.expectEqual(expected_ov, result_ov); -} - -// 2 cases on evaluating `a-b`: -// 1. `a-b` may underflow, iff b>0 && a<0 and a-b < min <=> a0 and a-b > max <=> a>max+b -// `-b` evaluation may overflow, iff b==min, but this is handled by the hardware -pub fn simple_subodi4(a: i64, b: i64, overflow: *c_int) i64 { - overflow.* = 0; - const min: i64 = math.minInt(i64); - const max: i64 = math.maxInt(i64); - if (((b > 0) and (a < min + b)) or - ((b < 0) and (a > max + b))) - overflow.* = 1; - return a -% b; -} - -test "subodi3" { - const min: i64 = math.minInt(i64); - const max: i64 = math.maxInt(i64); - var i: i64 = 1; - while (i < max) : (i *|= 2) { - try test__subodi4(i, i); - try test__subodi4(-i, -i); - try test__subodi4(i, -i); - try test__subodi4(-i, i); - } - - // edge cases - // 0 - 0 = 0 - // MIN - MIN = 0 - // MAX - MAX = 0 - // 0 - MIN overflow - // 0 - MAX = MIN+1 - // MIN - 0 = MIN - // MAX - 0 = MAX - // MIN - MAX overflow - // MAX - MIN overflow - try test__subodi4(0, 0); - try test__subodi4(min, min); - try test__subodi4(max, max); - try test__subodi4(0, min); - try test__subodi4(0, max); - try test__subodi4(min, 0); - try test__subodi4(max, 0); - try test__subodi4(min, max); - try test__subodi4(max, min); - - // derived edge cases - // MIN+1 - MIN = 1 - // MAX-1 - MAX = -1 - // 1 - MIN overflow - // -1 - MIN = MAX - // -1 - MAX = MIN - // +1 - MAX = MIN+2 - // MIN - 1 overflow - // MIN - -1 = MIN+1 - // MAX - 1 = MAX-1 - // MAX - -1 overflow - try test__subodi4(min + 1, min); - try test__subodi4(max - 1, max); - try test__subodi4(1, min); - try test__subodi4(-1, min); - try test__subodi4(-1, max); - try test__subodi4(1, max); - try test__subodi4(min, 1); - try test__subodi4(min, -1); - try test__subodi4(max, -1); - try test__subodi4(max, 1); -} diff --git a/lib/compiler_rt/subosi4_test.zig b/lib/compiler_rt/subosi4_test.zig deleted file mode 100644 index 8644e8100e..0000000000 --- a/lib/compiler_rt/subosi4_test.zig +++ /dev/null @@ -1,82 +0,0 @@ -const subo = @import("subo.zig"); -const testing = @import("std").testing; - -fn test__subosi4(a: i32, b: i32) !void { - var result_ov: c_int = undefined; - var expected_ov: c_int = undefined; - const result = subo.__subosi4(a, b, &result_ov); - const expected: i32 = simple_subosi4(a, b, &expected_ov); - try testing.expectEqual(expected, result); - try testing.expectEqual(expected_ov, result_ov); -} - -// 2 cases on evaluating `a-b`: -// 1. `a-b` may underflow, iff b>0 && a<0 and a-b < min <=> a0 and a-b > max <=> a>max+b -// `-b` evaluation may overflow, iff b==min, but this is handled by the hardware -pub fn simple_subosi4(a: i32, b: i32, overflow: *c_int) i32 { - overflow.* = 0; - const min: i32 = -2147483648; - const max: i32 = 2147483647; - if (((b > 0) and (a < min + b)) or - ((b < 0) and (a > max + b))) - overflow.* = 1; - return a -% b; -} - -test "subosi3" { - // -2^31 <= i32 <= 2^31-1 - // 2^31 = 2147483648 - // 2^31-1 = 2147483647 - const min: i32 = -2147483648; - const max: i32 = 2147483647; - var i: i32 = 1; - while (i < max) : (i *|= 2) { - try test__subosi4(i, i); - try test__subosi4(-i, -i); - try test__subosi4(i, -i); - try test__subosi4(-i, i); - } - - // edge cases - // 0 - 0 = 0 - // MIN - MIN = 0 - // MAX - MAX = 0 - // 0 - MIN overflow - // 0 - MAX = MIN+1 - // MIN - 0 = MIN - // MAX - 0 = MAX - // MIN - MAX overflow - // MAX - MIN overflow - try test__subosi4(0, 0); - try test__subosi4(min, min); - try test__subosi4(max, max); - try test__subosi4(0, min); - try test__subosi4(0, max); - try test__subosi4(min, 0); - try test__subosi4(max, 0); - try test__subosi4(min, max); - try test__subosi4(max, min); - - // derived edge cases - // MIN+1 - MIN = 1 - // MAX-1 - MAX = -1 - // 1 - MIN overflow - // -1 - MIN = MAX - // -1 - MAX = MIN - // +1 - MAX = MIN+2 - // MIN - 1 overflow - // MIN - -1 = MIN+1 - // MAX - 1 = MAX-1 - // MAX - -1 overflow - try test__subosi4(min + 1, min); - try test__subosi4(max - 1, max); - try test__subosi4(1, min); - try test__subosi4(-1, min); - try test__subosi4(-1, max); - try test__subosi4(1, max); - try test__subosi4(min, 1); - try test__subosi4(min, -1); - try test__subosi4(max, -1); - try test__subosi4(max, 1); -} diff --git a/lib/compiler_rt/suboti4_test.zig b/lib/compiler_rt/suboti4_test.zig deleted file mode 100644 index 65018bc966..0000000000 --- a/lib/compiler_rt/suboti4_test.zig +++ /dev/null @@ -1,84 +0,0 @@ -const subo = @import("subo.zig"); -const builtin = @import("builtin"); -const std = @import("std"); -const testing = std.testing; -const math = std.math; - -fn test__suboti4(a: i128, b: i128) !void { - var result_ov: c_int = undefined; - var expected_ov: c_int = undefined; - const result = subo.__suboti4(a, b, &result_ov); - const expected: i128 = simple_suboti4(a, b, &expected_ov); - try testing.expectEqual(expected, result); - try testing.expectEqual(expected_ov, result_ov); -} - -// 2 cases on evaluating `a-b`: -// 1. `a-b` may underflow, iff b>0 && a<0 and a-b < min <=> a0 and a-b > max <=> a>max+b -// `-b` evaluation may overflow, iff b==min, but this is handled by the hardware -pub fn simple_suboti4(a: i128, b: i128, overflow: *c_int) i128 { - overflow.* = 0; - const min: i128 = math.minInt(i128); - const max: i128 = math.maxInt(i128); - if (((b > 0) and (a < min + b)) or - ((b < 0) and (a > max + b))) - overflow.* = 1; - return a -% b; -} - -test "suboti3" { - if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; - - const min: i128 = math.minInt(i128); - const max: i128 = math.maxInt(i128); - var i: i128 = 1; - while (i < max) : (i *|= 2) { - try test__suboti4(i, i); - try test__suboti4(-i, -i); - try test__suboti4(i, -i); - try test__suboti4(-i, i); - } - - // edge cases - // 0 - 0 = 0 - // MIN - MIN = 0 - // MAX - MAX = 0 - // 0 - MIN overflow - // 0 - MAX = MIN+1 - // MIN - 0 = MIN - // MAX - 0 = MAX - // MIN - MAX overflow - // MAX - MIN overflow - try test__suboti4(0, 0); - try test__suboti4(min, min); - try test__suboti4(max, max); - try test__suboti4(0, min); - try test__suboti4(0, max); - try test__suboti4(min, 0); - try test__suboti4(max, 0); - try test__suboti4(min, max); - try test__suboti4(max, min); - - // derived edge cases - // MIN+1 - MIN = 1 - // MAX-1 - MAX = -1 - // 1 - MIN overflow - // -1 - MIN = MAX - // -1 - MAX = MIN - // +1 - MAX = MIN+2 - // MIN - 1 overflow - // MIN - -1 = MIN+1 - // MAX - 1 = MAX-1 - // MAX - -1 overflow - try test__suboti4(min + 1, min); - try test__suboti4(max - 1, max); - try test__suboti4(1, min); - try test__suboti4(-1, min); - try test__suboti4(-1, max); - try test__suboti4(1, max); - try test__suboti4(min, 1); - try test__suboti4(min, -1); - try test__suboti4(max, -1); - try test__suboti4(max, 1); -} diff --git a/lib/compiler_rt/subvdi3.zig b/lib/compiler_rt/subvdi3.zig index 8248e93022..a34deb2da1 100644 --- a/lib/compiler_rt/subvdi3.zig +++ b/lib/compiler_rt/subvdi3.zig @@ -1,4 +1,3 @@ -const subv = @import("subo.zig"); const common = @import("./common.zig"); const testing = @import("std").testing; @@ -9,9 +8,10 @@ comptime { } pub fn __subvdi3(a: i64, b: i64) callconv(.c) i64 { - var overflow: c_int = 0; - const sum = subv.__subodi4(a, b, &overflow); - if (overflow != 0) @panic("compiler-rt: integer overflow"); + const sum = a -% b; + // Overflow occurred iff the operands have opposite signs, and the sign of the + // sum is the opposite of the lhs sign. + if (((a ^ b) & (sum ^ a)) < 0) @panic("compiler-rt: integer overflow"); return sum; } diff --git a/lib/compiler_rt/subvsi3.zig b/lib/compiler_rt/subvsi3.zig index 8a2ea6c6a6..c524a3a634 100644 --- a/lib/compiler_rt/subvsi3.zig +++ b/lib/compiler_rt/subvsi3.zig @@ -1,4 +1,3 @@ -const subv = @import("subo.zig"); const common = @import("./common.zig"); const testing = @import("std").testing; @@ -9,9 +8,10 @@ comptime { } pub fn __subvsi3(a: i32, b: i32) callconv(.c) i32 { - var overflow: c_int = 0; - const sum = subv.__subosi4(a, b, &overflow); - if (overflow != 0) @panic("compiler-rt: integer overflow"); + const sum = a -% b; + // Overflow occurred iff the operands have opposite signs, and the sign of the + // sum is the opposite of the lhs sign. + if (((a ^ b) & (sum ^ a)) < 0) @panic("compiler-rt: integer overflow"); return sum; }