| author | |
| committer | |
| log | 20bd5e801826121ffa72ee54e3788bdb371b0fbc |
| tree | feafaa7e61a82983cb97f037e8e6f3cc8104a37c |
| parent | c091e27aac9d51cb3af06904c3039a8c316e5b89 |
| signature |
`__addosi4`, `__addodi4`, `__addoti4`, `__subosi4`, `__subodi4`, and
`__suboti4` were all functions which we invented for no apparent reason.
Neither LLVM, nor GCC, nor the Zig compiler use these functions. It
appears the functions were created in a kind of misunderstanding of an
old language proposal; see https://github.com/ziglang/zig/pull/10824.
There is no benefit to these functions existing; if a Zig compiler
backend needs this operation, it is trivial to implement, and *far*
simpler than calling a compiler-rt routine. Therefore, this commit
deletes them. A small amount of that code was used by other parts of
compiler-rt; the logic is trivial so has just been inlined where needed.
I also chose to quickly implement `__addvdi3` (a standard function)
because it is trivial and we already implement the `sub` parallel.14 files changed, 42 insertions(+), 591 deletions(-)
CMakeLists.txt+1-2| ... | @@ -211,10 +211,10 @@ set(ZIG_STAGE2_SOURCES | ... | @@ -211,10 +211,10 @@ set(ZIG_STAGE2_SOURCES |
| 211 | lib/compiler_rt/absvti2.zig | 211 | lib/compiler_rt/absvti2.zig |
| 212 | lib/compiler_rt/adddf3.zig | 212 | lib/compiler_rt/adddf3.zig |
| 213 | lib/compiler_rt/addf3.zig | 213 | lib/compiler_rt/addf3.zig |
| 214 | lib/compiler_rt/addo.zig | ||
| 215 | lib/compiler_rt/addsf3.zig | 214 | lib/compiler_rt/addsf3.zig |
| 216 | lib/compiler_rt/addtf3.zig | 215 | lib/compiler_rt/addtf3.zig |
| 217 | lib/compiler_rt/addvsi3.zig | 216 | lib/compiler_rt/addvsi3.zig |
| 217 | lib/compiler_rt/addvdi3.zig | ||
| 218 | lib/compiler_rt/addxf3.zig | 218 | lib/compiler_rt/addxf3.zig |
| 219 | lib/compiler_rt/arm.zig | 219 | lib/compiler_rt/arm.zig |
| 220 | lib/compiler_rt/atomics.zig | 220 | lib/compiler_rt/atomics.zig |
| ... | @@ -354,7 +354,6 @@ set(ZIG_STAGE2_SOURCES | ... | @@ -354,7 +354,6 @@ set(ZIG_STAGE2_SOURCES |
| 354 | lib/compiler_rt/sqrt.zig | 354 | lib/compiler_rt/sqrt.zig |
| 355 | lib/compiler_rt/stack_probe.zig | 355 | lib/compiler_rt/stack_probe.zig |
| 356 | lib/compiler_rt/subdf3.zig | 356 | lib/compiler_rt/subdf3.zig |
| 357 | lib/compiler_rt/subo.zig | ||
| 358 | lib/compiler_rt/subsf3.zig | 357 | lib/compiler_rt/subsf3.zig |
| 359 | lib/compiler_rt/subtf3.zig | 358 | lib/compiler_rt/subtf3.zig |
| 360 | lib/compiler_rt/subvdi3.zig | 359 | lib/compiler_rt/subvdi3.zig |
lib/compiler_rt.zig+3-2| ... | @@ -28,12 +28,13 @@ comptime { | ... | @@ -28,12 +28,13 @@ comptime { |
| 28 | _ = @import("compiler_rt/negv.zig"); | 28 | _ = @import("compiler_rt/negv.zig"); |
| 29 | 29 | ||
| 30 | _ = @import("compiler_rt/addvsi3.zig"); | 30 | _ = @import("compiler_rt/addvsi3.zig"); |
| 31 | _ = @import("compiler_rt/addvdi3.zig"); | ||
| 32 | |||
| 31 | _ = @import("compiler_rt/subvsi3.zig"); | 33 | _ = @import("compiler_rt/subvsi3.zig"); |
| 32 | _ = @import("compiler_rt/subvdi3.zig"); | 34 | _ = @import("compiler_rt/subvdi3.zig"); |
| 35 | |||
| 33 | _ = @import("compiler_rt/mulvsi3.zig"); | 36 | _ = @import("compiler_rt/mulvsi3.zig"); |
| 34 | 37 | ||
| 35 | _ = @import("compiler_rt/addo.zig"); | ||
| 36 | _ = @import("compiler_rt/subo.zig"); | ||
| 37 | _ = @import("compiler_rt/mulo.zig"); | 38 | _ = @import("compiler_rt/mulo.zig"); |
| 38 | 39 | ||
| 39 | // Float routines | 40 | // Float routines |
lib/compiler_rt/addo.zig deleted-46| ... | @@ -1,46 +0,0 @@ | ||
| 1 | const std = @import("std"); | ||
| 2 | const common = @import("./common.zig"); | ||
| 3 | pub const panic = @import("common.zig").panic; | ||
| 4 | |||
| 5 | comptime { | ||
| 6 | @export(&__addosi4, .{ .name = "__addosi4", .linkage = common.linkage, .visibility = common.visibility }); | ||
| 7 | @export(&__addodi4, .{ .name = "__addodi4", .linkage = common.linkage, .visibility = common.visibility }); | ||
| 8 | @export(&__addoti4, .{ .name = "__addoti4", .linkage = common.linkage, .visibility = common.visibility }); | ||
| 9 | } | ||
| 10 | |||
| 11 | // addo - add overflow | ||
| 12 | // * return a+%b. | ||
| 13 | // * return if a+b overflows => 1 else => 0 | ||
| 14 | // - addoXi4_generic as default | ||
| 15 | |||
| 16 | inline fn addoXi4_generic(comptime ST: type, a: ST, b: ST, overflow: *c_int) ST { | ||
| 17 | @setRuntimeSafety(common.test_safety); | ||
| 18 | overflow.* = 0; | ||
| 19 | const sum: ST = a +% b; | ||
| 20 | // Hackers Delight: section Overflow Detection, subsection Signed Add/Subtract | ||
| 21 | // Let sum = a +% b == a + b + carry == wraparound addition. | ||
| 22 | // Overflow in a+b+carry occurs, iff a and b have opposite signs | ||
| 23 | // and the sign of a+b+carry is the same as a (or equivalently b). | ||
| 24 | // Slower routine: res = ~(a ^ b) & ((sum ^ a) | ||
| 25 | // Faster routine: res = (sum ^ a) & (sum ^ b) | ||
| 26 | // Overflow occurred, iff (res < 0) | ||
| 27 | if (((sum ^ a) & (sum ^ b)) < 0) | ||
| 28 | overflow.* = 1; | ||
| 29 | return sum; | ||
| 30 | } | ||
| 31 | |||
| 32 | pub fn __addosi4(a: i32, b: i32, overflow: *c_int) callconv(.c) i32 { | ||
| 33 | return addoXi4_generic(i32, a, b, overflow); | ||
| 34 | } | ||
| 35 | pub fn __addodi4(a: i64, b: i64, overflow: *c_int) callconv(.c) i64 { | ||
| 36 | return addoXi4_generic(i64, a, b, overflow); | ||
| 37 | } | ||
| 38 | pub fn __addoti4(a: i128, b: i128, overflow: *c_int) callconv(.c) i128 { | ||
| 39 | return addoXi4_generic(i128, a, b, overflow); | ||
| 40 | } | ||
| 41 | |||
| 42 | test { | ||
| 43 | _ = @import("addosi4_test.zig"); | ||
| 44 | _ = @import("addodi4_test.zig"); | ||
| 45 | _ = @import("addoti4_test.zig"); | ||
| 46 | } | ||
lib/compiler_rt/addodi4_test.zig deleted-77| ... | @@ -1,77 +0,0 @@ | ||
| 1 | const addv = @import("addo.zig"); | ||
| 2 | const std = @import("std"); | ||
| 3 | const testing = std.testing; | ||
| 4 | const math = std.math; | ||
| 5 | |||
| 6 | fn test__addodi4(a: i64, b: i64) !void { | ||
| 7 | var result_ov: c_int = undefined; | ||
| 8 | var expected_ov: c_int = undefined; | ||
| 9 | const result = addv.__addodi4(a, b, &result_ov); | ||
| 10 | const expected: i64 = simple_addodi4(a, b, &expected_ov); | ||
| 11 | try testing.expectEqual(expected, result); | ||
| 12 | try testing.expectEqual(expected_ov, result_ov); | ||
| 13 | } | ||
| 14 | |||
| 15 | fn simple_addodi4(a: i64, b: i64, overflow: *c_int) i64 { | ||
| 16 | overflow.* = 0; | ||
| 17 | const min: i64 = math.minInt(i64); | ||
| 18 | const max: i64 = math.maxInt(i64); | ||
| 19 | if (((a > 0) and (b > max - a)) or | ||
| 20 | ((a < 0) and (b < min - a))) | ||
| 21 | overflow.* = 1; | ||
| 22 | return a +% b; | ||
| 23 | } | ||
| 24 | |||
| 25 | test "addodi4" { | ||
| 26 | const min: i64 = math.minInt(i64); | ||
| 27 | const max: i64 = math.maxInt(i64); | ||
| 28 | var i: i64 = 1; | ||
| 29 | while (i < max) : (i *|= 2) { | ||
| 30 | try test__addodi4(i, i); | ||
| 31 | try test__addodi4(-i, -i); | ||
| 32 | try test__addodi4(i, -i); | ||
| 33 | try test__addodi4(-i, i); | ||
| 34 | } | ||
| 35 | |||
| 36 | // edge cases | ||
| 37 | // 0 + 0 = 0 | ||
| 38 | // MIN + MIN overflow | ||
| 39 | // MAX + MAX overflow | ||
| 40 | // 0 + MIN MIN | ||
| 41 | // 0 + MAX MAX | ||
| 42 | // MIN + 0 MIN | ||
| 43 | // MAX + 0 MAX | ||
| 44 | // MIN + MAX -1 | ||
| 45 | // MAX + MIN -1 | ||
| 46 | try test__addodi4(0, 0); | ||
| 47 | try test__addodi4(min, min); | ||
| 48 | try test__addodi4(max, max); | ||
| 49 | try test__addodi4(0, min); | ||
| 50 | try test__addodi4(0, max); | ||
| 51 | try test__addodi4(min, 0); | ||
| 52 | try test__addodi4(max, 0); | ||
| 53 | try test__addodi4(min, max); | ||
| 54 | try test__addodi4(max, min); | ||
| 55 | |||
| 56 | // derived edge cases | ||
| 57 | // MIN+1 + MIN overflow | ||
| 58 | // MAX-1 + MAX overflow | ||
| 59 | // 1 + MIN = MIN+1 | ||
| 60 | // -1 + MIN overflow | ||
| 61 | // -1 + MAX = MAX-1 | ||
| 62 | // +1 + MAX overflow | ||
| 63 | // MIN + 1 = MIN+1 | ||
| 64 | // MIN + -1 overflow | ||
| 65 | // MAX + 1 overflow | ||
| 66 | // MAX + -1 = MAX-1 | ||
| 67 | try test__addodi4(min + 1, min); | ||
| 68 | try test__addodi4(max - 1, max); | ||
| 69 | try test__addodi4(1, min); | ||
| 70 | try test__addodi4(-1, min); | ||
| 71 | try test__addodi4(-1, max); | ||
| 72 | try test__addodi4(1, max); | ||
| 73 | try test__addodi4(min, 1); | ||
| 74 | try test__addodi4(min, -1); | ||
| 75 | try test__addodi4(max, -1); | ||
| 76 | try test__addodi4(max, 1); | ||
| 77 | } | ||
lib/compiler_rt/addosi4_test.zig deleted-78| ... | @@ -1,78 +0,0 @@ | ||
| 1 | const addv = @import("addo.zig"); | ||
| 2 | const testing = @import("std").testing; | ||
| 3 | |||
| 4 | fn test__addosi4(a: i32, b: i32) !void { | ||
| 5 | var result_ov: c_int = undefined; | ||
| 6 | var expected_ov: c_int = undefined; | ||
| 7 | const result = addv.__addosi4(a, b, &result_ov); | ||
| 8 | const expected: i32 = simple_addosi4(a, b, &expected_ov); | ||
| 9 | try testing.expectEqual(expected, result); | ||
| 10 | try testing.expectEqual(expected_ov, result_ov); | ||
| 11 | } | ||
| 12 | |||
| 13 | fn simple_addosi4(a: i32, b: i32, overflow: *c_int) i32 { | ||
| 14 | overflow.* = 0; | ||
| 15 | const min: i32 = -2147483648; | ||
| 16 | const max: i32 = 2147483647; | ||
| 17 | if (((a > 0) and (b > max - a)) or | ||
| 18 | ((a < 0) and (b < min - a))) | ||
| 19 | overflow.* = 1; | ||
| 20 | return a +% b; | ||
| 21 | } | ||
| 22 | |||
| 23 | test "addosi4" { | ||
| 24 | // -2^31 <= i32 <= 2^31-1 | ||
| 25 | // 2^31 = 2147483648 | ||
| 26 | // 2^31-1 = 2147483647 | ||
| 27 | const min: i32 = -2147483648; | ||
| 28 | const max: i32 = 2147483647; | ||
| 29 | var i: i32 = 1; | ||
| 30 | while (i < max) : (i *|= 2) { | ||
| 31 | try test__addosi4(i, i); | ||
| 32 | try test__addosi4(-i, -i); | ||
| 33 | try test__addosi4(i, -i); | ||
| 34 | try test__addosi4(-i, i); | ||
| 35 | } | ||
| 36 | |||
| 37 | // edge cases | ||
| 38 | // 0 + 0 = 0 | ||
| 39 | // MIN + MIN overflow | ||
| 40 | // MAX + MAX overflow | ||
| 41 | // 0 + MIN MIN | ||
| 42 | // 0 + MAX MAX | ||
| 43 | // MIN + 0 MIN | ||
| 44 | // MAX + 0 MAX | ||
| 45 | // MIN + MAX -1 | ||
| 46 | // MAX + MIN -1 | ||
| 47 | try test__addosi4(0, 0); | ||
| 48 | try test__addosi4(min, min); | ||
| 49 | try test__addosi4(max, max); | ||
| 50 | try test__addosi4(0, min); | ||
| 51 | try test__addosi4(0, max); | ||
| 52 | try test__addosi4(min, 0); | ||
| 53 | try test__addosi4(max, 0); | ||
| 54 | try test__addosi4(min, max); | ||
| 55 | try test__addosi4(max, min); | ||
| 56 | |||
| 57 | // derived edge cases | ||
| 58 | // MIN+1 + MIN overflow | ||
| 59 | // MAX-1 + MAX overflow | ||
| 60 | // 1 + MIN = MIN+1 | ||
| 61 | // -1 + MIN overflow | ||
| 62 | // -1 + MAX = MAX-1 | ||
| 63 | // +1 + MAX overflow | ||
| 64 | // MIN + 1 = MIN+1 | ||
| 65 | // MIN + -1 overflow | ||
| 66 | // MAX + 1 overflow | ||
| 67 | // MAX + -1 = MAX-1 | ||
| 68 | try test__addosi4(min + 1, min); | ||
| 69 | try test__addosi4(max - 1, max); | ||
| 70 | try test__addosi4(1, min); | ||
| 71 | try test__addosi4(-1, min); | ||
| 72 | try test__addosi4(-1, max); | ||
| 73 | try test__addosi4(1, max); | ||
| 74 | try test__addosi4(min, 1); | ||
| 75 | try test__addosi4(min, -1); | ||
| 76 | try test__addosi4(max, -1); | ||
| 77 | try test__addosi4(max, 1); | ||
| 78 | } | ||
lib/compiler_rt/addoti4_test.zig deleted-80| ... | @@ -1,80 +0,0 @@ | ||
| 1 | const addv = @import("addo.zig"); | ||
| 2 | const builtin = @import("builtin"); | ||
| 3 | const std = @import("std"); | ||
| 4 | const testing = std.testing; | ||
| 5 | const math = std.math; | ||
| 6 | |||
| 7 | fn test__addoti4(a: i128, b: i128) !void { | ||
| 8 | var result_ov: c_int = undefined; | ||
| 9 | var expected_ov: c_int = undefined; | ||
| 10 | const result = addv.__addoti4(a, b, &result_ov); | ||
| 11 | const expected: i128 = simple_addoti4(a, b, &expected_ov); | ||
| 12 | try testing.expectEqual(expected, result); | ||
| 13 | try testing.expectEqual(expected_ov, result_ov); | ||
| 14 | } | ||
| 15 | |||
| 16 | fn simple_addoti4(a: i128, b: i128, overflow: *c_int) i128 { | ||
| 17 | overflow.* = 0; | ||
| 18 | const min: i128 = math.minInt(i128); | ||
| 19 | const max: i128 = math.maxInt(i128); | ||
| 20 | if (((a > 0) and (b > max - a)) or | ||
| 21 | ((a < 0) and (b < min - a))) | ||
| 22 | overflow.* = 1; | ||
| 23 | return a +% b; | ||
| 24 | } | ||
| 25 | |||
| 26 | test "addoti4" { | ||
| 27 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | ||
| 28 | |||
| 29 | const min: i128 = math.minInt(i128); | ||
| 30 | const max: i128 = math.maxInt(i128); | ||
| 31 | var i: i128 = 1; | ||
| 32 | while (i < max) : (i *|= 2) { | ||
| 33 | try test__addoti4(i, i); | ||
| 34 | try test__addoti4(-i, -i); | ||
| 35 | try test__addoti4(i, -i); | ||
| 36 | try test__addoti4(-i, i); | ||
| 37 | } | ||
| 38 | |||
| 39 | // edge cases | ||
| 40 | // 0 + 0 = 0 | ||
| 41 | // MIN + MIN overflow | ||
| 42 | // MAX + MAX overflow | ||
| 43 | // 0 + MIN MIN | ||
| 44 | // 0 + MAX MAX | ||
| 45 | // MIN + 0 MIN | ||
| 46 | // MAX + 0 MAX | ||
| 47 | // MIN + MAX -1 | ||
| 48 | // MAX + MIN -1 | ||
| 49 | try test__addoti4(0, 0); | ||
| 50 | try test__addoti4(min, min); | ||
| 51 | try test__addoti4(max, max); | ||
| 52 | try test__addoti4(0, min); | ||
| 53 | try test__addoti4(0, max); | ||
| 54 | try test__addoti4(min, 0); | ||
| 55 | try test__addoti4(max, 0); | ||
| 56 | try test__addoti4(min, max); | ||
| 57 | try test__addoti4(max, min); | ||
| 58 | |||
| 59 | // derived edge cases | ||
| 60 | // MIN+1 + MIN overflow | ||
| 61 | // MAX-1 + MAX overflow | ||
| 62 | // 1 + MIN = MIN+1 | ||
| 63 | // -1 + MIN overflow | ||
| 64 | // -1 + MAX = MAX-1 | ||
| 65 | // +1 + MAX overflow | ||
| 66 | // MIN + 1 = MIN+1 | ||
| 67 | // MIN + -1 overflow | ||
| 68 | // MAX + 1 overflow | ||
| 69 | // MAX + -1 = MAX-1 | ||
| 70 | try test__addoti4(min + 1, min); | ||
| 71 | try test__addoti4(max - 1, max); | ||
| 72 | try test__addoti4(1, min); | ||
| 73 | try test__addoti4(-1, min); | ||
| 74 | try test__addoti4(-1, max); | ||
| 75 | try test__addoti4(1, max); | ||
| 76 | try test__addoti4(min, 1); | ||
| 77 | try test__addoti4(min, -1); | ||
| 78 | try test__addoti4(max, -1); | ||
| 79 | try test__addoti4(max, 1); | ||
| 80 | } | ||
lib/compiler_rt/addvdi3.zig created+26| ... | @@ -0,0 +1,26 @@ | ||
| 1 | const common = @import("./common.zig"); | ||
| 2 | const testing = @import("std").testing; | ||
| 3 | |||
| 4 | pub const panic = common.panic; | ||
| 5 | |||
| 6 | comptime { | ||
| 7 | @export(&__addvdi3, .{ .name = "__addvdi3", .linkage = common.linkage, .visibility = common.visibility }); | ||
| 8 | } | ||
| 9 | |||
| 10 | pub fn __addvdi3(a: i64, b: i64) callconv(.c) i64 { | ||
| 11 | const sum = a +% b; | ||
| 12 | // Overflow occurred iff both operands have the same sign, and the sign of the sum does | ||
| 13 | // not match it. In other words, iff the sum sign is not the sign of either operand. | ||
| 14 | if (((sum ^ a) & (sum ^ b)) < 0) @panic("compiler-rt: integer overflow"); | ||
| 15 | return sum; | ||
| 16 | } | ||
| 17 | |||
| 18 | test "addvdi3" { | ||
| 19 | // const min: i64 = -9223372036854775808 | ||
| 20 | // const max: i64 = 9223372036854775807 | ||
| 21 | // TODO write panic handler for testing panics | ||
| 22 | // try test__addvdi3(-9223372036854775808, -1, -1); // panic | ||
| 23 | // try test__addvdi3(9223372036854775807, 1, 1); // panic | ||
| 24 | try testing.expectEqual(-9223372036854775808, __addvdi3(-9223372036854775807, -1)); | ||
| 25 | try testing.expectEqual(9223372036854775807, __addvdi3(9223372036854775806, 1)); | ||
| 26 | } | ||
lib/compiler_rt/addvsi3.zig+4-4| ... | @@ -1,4 +1,3 @@ | ... | @@ -1,4 +1,3 @@ |
| 1 | const addv = @import("addo.zig"); | ||
| 2 | const common = @import("./common.zig"); | 1 | const common = @import("./common.zig"); |
| 3 | const testing = @import("std").testing; | 2 | const testing = @import("std").testing; |
| 4 | 3 | ||
| ... | @@ -9,9 +8,10 @@ comptime { | ... | @@ -9,9 +8,10 @@ comptime { |
| 9 | } | 8 | } |
| 10 | 9 | ||
| 11 | pub fn __addvsi3(a: i32, b: i32) callconv(.c) i32 { | 10 | pub fn __addvsi3(a: i32, b: i32) callconv(.c) i32 { |
| 12 | var overflow: c_int = 0; | 11 | const sum = a +% b; |
| 13 | const sum = addv.__addosi4(a, b, &overflow); | 12 | // Overflow occurred iff both operands have the same sign, and the sign of the sum does |
| 14 | if (overflow != 0) @panic("compiler-rt: integer overflow"); | 13 | // not match it. In other words, iff the sum sign is not the sign of either operand. |
| 14 | if (((sum ^ a) & (sum ^ b)) < 0) @panic("compiler-rt: integer overflow"); | ||
| 15 | return sum; | 15 | return sum; |
| 16 | } | 16 | } |
| 17 | 17 |
lib/compiler_rt/subo.zig deleted-47| ... | @@ -1,47 +0,0 @@ | ||
| 1 | //! subo - subtract overflow | ||
| 2 | //! * return a-%b. | ||
| 3 | //! * return if a-b overflows => 1 else => 0 | ||
| 4 | //! - suboXi4_generic as default | ||
| 5 | |||
| 6 | const std = @import("std"); | ||
| 7 | const builtin = @import("builtin"); | ||
| 8 | const common = @import("common.zig"); | ||
| 9 | |||
| 10 | pub const panic = common.panic; | ||
| 11 | |||
| 12 | comptime { | ||
| 13 | @export(&__subosi4, .{ .name = "__subosi4", .linkage = common.linkage, .visibility = common.visibility }); | ||
| 14 | @export(&__subodi4, .{ .name = "__subodi4", .linkage = common.linkage, .visibility = common.visibility }); | ||
| 15 | @export(&__suboti4, .{ .name = "__suboti4", .linkage = common.linkage, .visibility = common.visibility }); | ||
| 16 | } | ||
| 17 | |||
| 18 | pub fn __subosi4(a: i32, b: i32, overflow: *c_int) callconv(.c) i32 { | ||
| 19 | return suboXi4_generic(i32, a, b, overflow); | ||
| 20 | } | ||
| 21 | pub fn __subodi4(a: i64, b: i64, overflow: *c_int) callconv(.c) i64 { | ||
| 22 | return suboXi4_generic(i64, a, b, overflow); | ||
| 23 | } | ||
| 24 | pub fn __suboti4(a: i128, b: i128, overflow: *c_int) callconv(.c) i128 { | ||
| 25 | return suboXi4_generic(i128, a, b, overflow); | ||
| 26 | } | ||
| 27 | |||
| 28 | inline fn suboXi4_generic(comptime ST: type, a: ST, b: ST, overflow: *c_int) ST { | ||
| 29 | overflow.* = 0; | ||
| 30 | const sum: ST = a -% b; | ||
| 31 | // Hackers Delight: section Overflow Detection, subsection Signed Add/Subtract | ||
| 32 | // Let sum = a -% b == a - b - carry == wraparound subtraction. | ||
| 33 | // Overflow in a-b-carry occurs, iff a and b have opposite signs | ||
| 34 | // and the sign of a-b-carry is opposite of a (or equivalently same as b). | ||
| 35 | // Faster routine: res = (a ^ b) & (sum ^ a) | ||
| 36 | // Slower routine: res = (sum^a) & ~(sum^b) | ||
| 37 | // Overflow occurred, iff (res < 0) | ||
| 38 | if (((a ^ b) & (sum ^ a)) < 0) | ||
| 39 | overflow.* = 1; | ||
| 40 | return sum; | ||
| 41 | } | ||
| 42 | |||
| 43 | test { | ||
| 44 | _ = @import("subosi4_test.zig"); | ||
| 45 | _ = @import("subodi4_test.zig"); | ||
| 46 | _ = @import("suboti4_test.zig"); | ||
| 47 | } | ||
lib/compiler_rt/subodi4_test.zig deleted-81| ... | @@ -1,81 +0,0 @@ | ||
| 1 | const subo = @import("subo.zig"); | ||
| 2 | const std = @import("std"); | ||
| 3 | const testing = std.testing; | ||
| 4 | const math = std.math; | ||
| 5 | |||
| 6 | fn test__subodi4(a: i64, b: i64) !void { | ||
| 7 | var result_ov: c_int = undefined; | ||
| 8 | var expected_ov: c_int = undefined; | ||
| 9 | const result = subo.__subodi4(a, b, &result_ov); | ||
| 10 | const expected: i64 = simple_subodi4(a, b, &expected_ov); | ||
| 11 | try testing.expectEqual(expected, result); | ||
| 12 | try testing.expectEqual(expected_ov, result_ov); | ||
| 13 | } | ||
| 14 | |||
| 15 | // 2 cases on evaluating `a-b`: | ||
| 16 | // 1. `a-b` may underflow, iff b>0 && a<0 and a-b < min <=> a<min+b | ||
| 17 | // 2. `a-b` may overflow, iff b<0 && a>0 and a-b > max <=> a>max+b | ||
| 18 | // `-b` evaluation may overflow, iff b==min, but this is handled by the hardware | ||
| 19 | pub fn simple_subodi4(a: i64, b: i64, overflow: *c_int) i64 { | ||
| 20 | overflow.* = 0; | ||
| 21 | const min: i64 = math.minInt(i64); | ||
| 22 | const max: i64 = math.maxInt(i64); | ||
| 23 | if (((b > 0) and (a < min + b)) or | ||
| 24 | ((b < 0) and (a > max + b))) | ||
| 25 | overflow.* = 1; | ||
| 26 | return a -% b; | ||
| 27 | } | ||
| 28 | |||
| 29 | test "subodi3" { | ||
| 30 | const min: i64 = math.minInt(i64); | ||
| 31 | const max: i64 = math.maxInt(i64); | ||
| 32 | var i: i64 = 1; | ||
| 33 | while (i < max) : (i *|= 2) { | ||
| 34 | try test__subodi4(i, i); | ||
| 35 | try test__subodi4(-i, -i); | ||
| 36 | try test__subodi4(i, -i); | ||
| 37 | try test__subodi4(-i, i); | ||
| 38 | } | ||
| 39 | |||
| 40 | // edge cases | ||
| 41 | // 0 - 0 = 0 | ||
| 42 | // MIN - MIN = 0 | ||
| 43 | // MAX - MAX = 0 | ||
| 44 | // 0 - MIN overflow | ||
| 45 | // 0 - MAX = MIN+1 | ||
| 46 | // MIN - 0 = MIN | ||
| 47 | // MAX - 0 = MAX | ||
| 48 | // MIN - MAX overflow | ||
| 49 | // MAX - MIN overflow | ||
| 50 | try test__subodi4(0, 0); | ||
| 51 | try test__subodi4(min, min); | ||
| 52 | try test__subodi4(max, max); | ||
| 53 | try test__subodi4(0, min); | ||
| 54 | try test__subodi4(0, max); | ||
| 55 | try test__subodi4(min, 0); | ||
| 56 | try test__subodi4(max, 0); | ||
| 57 | try test__subodi4(min, max); | ||
| 58 | try test__subodi4(max, min); | ||
| 59 | |||
| 60 | // derived edge cases | ||
| 61 | // MIN+1 - MIN = 1 | ||
| 62 | // MAX-1 - MAX = -1 | ||
| 63 | // 1 - MIN overflow | ||
| 64 | // -1 - MIN = MAX | ||
| 65 | // -1 - MAX = MIN | ||
| 66 | // +1 - MAX = MIN+2 | ||
| 67 | // MIN - 1 overflow | ||
| 68 | // MIN - -1 = MIN+1 | ||
| 69 | // MAX - 1 = MAX-1 | ||
| 70 | // MAX - -1 overflow | ||
| 71 | try test__subodi4(min + 1, min); | ||
| 72 | try test__subodi4(max - 1, max); | ||
| 73 | try test__subodi4(1, min); | ||
| 74 | try test__subodi4(-1, min); | ||
| 75 | try test__subodi4(-1, max); | ||
| 76 | try test__subodi4(1, max); | ||
| 77 | try test__subodi4(min, 1); | ||
| 78 | try test__subodi4(min, -1); | ||
| 79 | try test__subodi4(max, -1); | ||
| 80 | try test__subodi4(max, 1); | ||
| 81 | } | ||
lib/compiler_rt/subosi4_test.zig deleted-82| ... | @@ -1,82 +0,0 @@ | ||
| 1 | const subo = @import("subo.zig"); | ||
| 2 | const testing = @import("std").testing; | ||
| 3 | |||
| 4 | fn test__subosi4(a: i32, b: i32) !void { | ||
| 5 | var result_ov: c_int = undefined; | ||
| 6 | var expected_ov: c_int = undefined; | ||
| 7 | const result = subo.__subosi4(a, b, &result_ov); | ||
| 8 | const expected: i32 = simple_subosi4(a, b, &expected_ov); | ||
| 9 | try testing.expectEqual(expected, result); | ||
| 10 | try testing.expectEqual(expected_ov, result_ov); | ||
| 11 | } | ||
| 12 | |||
| 13 | // 2 cases on evaluating `a-b`: | ||
| 14 | // 1. `a-b` may underflow, iff b>0 && a<0 and a-b < min <=> a<min+b | ||
| 15 | // 2. `a-b` may overflow, iff b<0 && a>0 and a-b > max <=> a>max+b | ||
| 16 | // `-b` evaluation may overflow, iff b==min, but this is handled by the hardware | ||
| 17 | pub fn simple_subosi4(a: i32, b: i32, overflow: *c_int) i32 { | ||
| 18 | overflow.* = 0; | ||
| 19 | const min: i32 = -2147483648; | ||
| 20 | const max: i32 = 2147483647; | ||
| 21 | if (((b > 0) and (a < min + b)) or | ||
| 22 | ((b < 0) and (a > max + b))) | ||
| 23 | overflow.* = 1; | ||
| 24 | return a -% b; | ||
| 25 | } | ||
| 26 | |||
| 27 | test "subosi3" { | ||
| 28 | // -2^31 <= i32 <= 2^31-1 | ||
| 29 | // 2^31 = 2147483648 | ||
| 30 | // 2^31-1 = 2147483647 | ||
| 31 | const min: i32 = -2147483648; | ||
| 32 | const max: i32 = 2147483647; | ||
| 33 | var i: i32 = 1; | ||
| 34 | while (i < max) : (i *|= 2) { | ||
| 35 | try test__subosi4(i, i); | ||
| 36 | try test__subosi4(-i, -i); | ||
| 37 | try test__subosi4(i, -i); | ||
| 38 | try test__subosi4(-i, i); | ||
| 39 | } | ||
| 40 | |||
| 41 | // edge cases | ||
| 42 | // 0 - 0 = 0 | ||
| 43 | // MIN - MIN = 0 | ||
| 44 | // MAX - MAX = 0 | ||
| 45 | // 0 - MIN overflow | ||
| 46 | // 0 - MAX = MIN+1 | ||
| 47 | // MIN - 0 = MIN | ||
| 48 | // MAX - 0 = MAX | ||
| 49 | // MIN - MAX overflow | ||
| 50 | // MAX - MIN overflow | ||
| 51 | try test__subosi4(0, 0); | ||
| 52 | try test__subosi4(min, min); | ||
| 53 | try test__subosi4(max, max); | ||
| 54 | try test__subosi4(0, min); | ||
| 55 | try test__subosi4(0, max); | ||
| 56 | try test__subosi4(min, 0); | ||
| 57 | try test__subosi4(max, 0); | ||
| 58 | try test__subosi4(min, max); | ||
| 59 | try test__subosi4(max, min); | ||
| 60 | |||
| 61 | // derived edge cases | ||
| 62 | // MIN+1 - MIN = 1 | ||
| 63 | // MAX-1 - MAX = -1 | ||
| 64 | // 1 - MIN overflow | ||
| 65 | // -1 - MIN = MAX | ||
| 66 | // -1 - MAX = MIN | ||
| 67 | // +1 - MAX = MIN+2 | ||
| 68 | // MIN - 1 overflow | ||
| 69 | // MIN - -1 = MIN+1 | ||
| 70 | // MAX - 1 = MAX-1 | ||
| 71 | // MAX - -1 overflow | ||
| 72 | try test__subosi4(min + 1, min); | ||
| 73 | try test__subosi4(max - 1, max); | ||
| 74 | try test__subosi4(1, min); | ||
| 75 | try test__subosi4(-1, min); | ||
| 76 | try test__subosi4(-1, max); | ||
| 77 | try test__subosi4(1, max); | ||
| 78 | try test__subosi4(min, 1); | ||
| 79 | try test__subosi4(min, -1); | ||
| 80 | try test__subosi4(max, -1); | ||
| 81 | try test__subosi4(max, 1); | ||
| 82 | } | ||
lib/compiler_rt/suboti4_test.zig deleted-84| ... | @@ -1,84 +0,0 @@ | ||
| 1 | const subo = @import("subo.zig"); | ||
| 2 | const builtin = @import("builtin"); | ||
| 3 | const std = @import("std"); | ||
| 4 | const testing = std.testing; | ||
| 5 | const math = std.math; | ||
| 6 | |||
| 7 | fn test__suboti4(a: i128, b: i128) !void { | ||
| 8 | var result_ov: c_int = undefined; | ||
| 9 | var expected_ov: c_int = undefined; | ||
| 10 | const result = subo.__suboti4(a, b, &result_ov); | ||
| 11 | const expected: i128 = simple_suboti4(a, b, &expected_ov); | ||
| 12 | try testing.expectEqual(expected, result); | ||
| 13 | try testing.expectEqual(expected_ov, result_ov); | ||
| 14 | } | ||
| 15 | |||
| 16 | // 2 cases on evaluating `a-b`: | ||
| 17 | // 1. `a-b` may underflow, iff b>0 && a<0 and a-b < min <=> a<min+b | ||
| 18 | // 2. `a-b` may overflow, iff b<0 && a>0 and a-b > max <=> a>max+b | ||
| 19 | // `-b` evaluation may overflow, iff b==min, but this is handled by the hardware | ||
| 20 | pub fn simple_suboti4(a: i128, b: i128, overflow: *c_int) i128 { | ||
| 21 | overflow.* = 0; | ||
| 22 | const min: i128 = math.minInt(i128); | ||
| 23 | const max: i128 = math.maxInt(i128); | ||
| 24 | if (((b > 0) and (a < min + b)) or | ||
| 25 | ((b < 0) and (a > max + b))) | ||
| 26 | overflow.* = 1; | ||
| 27 | return a -% b; | ||
| 28 | } | ||
| 29 | |||
| 30 | test "suboti3" { | ||
| 31 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; | ||
| 32 | |||
| 33 | const min: i128 = math.minInt(i128); | ||
| 34 | const max: i128 = math.maxInt(i128); | ||
| 35 | var i: i128 = 1; | ||
| 36 | while (i < max) : (i *|= 2) { | ||
| 37 | try test__suboti4(i, i); | ||
| 38 | try test__suboti4(-i, -i); | ||
| 39 | try test__suboti4(i, -i); | ||
| 40 | try test__suboti4(-i, i); | ||
| 41 | } | ||
| 42 | |||
| 43 | // edge cases | ||
| 44 | // 0 - 0 = 0 | ||
| 45 | // MIN - MIN = 0 | ||
| 46 | // MAX - MAX = 0 | ||
| 47 | // 0 - MIN overflow | ||
| 48 | // 0 - MAX = MIN+1 | ||
| 49 | // MIN - 0 = MIN | ||
| 50 | // MAX - 0 = MAX | ||
| 51 | // MIN - MAX overflow | ||
| 52 | // MAX - MIN overflow | ||
| 53 | try test__suboti4(0, 0); | ||
| 54 | try test__suboti4(min, min); | ||
| 55 | try test__suboti4(max, max); | ||
| 56 | try test__suboti4(0, min); | ||
| 57 | try test__suboti4(0, max); | ||
| 58 | try test__suboti4(min, 0); | ||
| 59 | try test__suboti4(max, 0); | ||
| 60 | try test__suboti4(min, max); | ||
| 61 | try test__suboti4(max, min); | ||
| 62 | |||
| 63 | // derived edge cases | ||
| 64 | // MIN+1 - MIN = 1 | ||
| 65 | // MAX-1 - MAX = -1 | ||
| 66 | // 1 - MIN overflow | ||
| 67 | // -1 - MIN = MAX | ||
| 68 | // -1 - MAX = MIN | ||
| 69 | // +1 - MAX = MIN+2 | ||
| 70 | // MIN - 1 overflow | ||
| 71 | // MIN - -1 = MIN+1 | ||
| 72 | // MAX - 1 = MAX-1 | ||
| 73 | // MAX - -1 overflow | ||
| 74 | try test__suboti4(min + 1, min); | ||
| 75 | try test__suboti4(max - 1, max); | ||
| 76 | try test__suboti4(1, min); | ||
| 77 | try test__suboti4(-1, min); | ||
| 78 | try test__suboti4(-1, max); | ||
| 79 | try test__suboti4(1, max); | ||
| 80 | try test__suboti4(min, 1); | ||
| 81 | try test__suboti4(min, -1); | ||
| 82 | try test__suboti4(max, -1); | ||
| 83 | try test__suboti4(max, 1); | ||
| 84 | } | ||
lib/compiler_rt/subvdi3.zig+4-4| ... | @@ -1,4 +1,3 @@ | ... | @@ -1,4 +1,3 @@ |
| 1 | const subv = @import("subo.zig"); | ||
| 2 | const common = @import("./common.zig"); | 1 | const common = @import("./common.zig"); |
| 3 | const testing = @import("std").testing; | 2 | const testing = @import("std").testing; |
| 4 | 3 | ||
| ... | @@ -9,9 +8,10 @@ comptime { | ... | @@ -9,9 +8,10 @@ comptime { |
| 9 | } | 8 | } |
| 10 | 9 | ||
| 11 | pub fn __subvdi3(a: i64, b: i64) callconv(.c) i64 { | 10 | pub fn __subvdi3(a: i64, b: i64) callconv(.c) i64 { |
| 12 | var overflow: c_int = 0; | 11 | const sum = a -% b; |
| 13 | const sum = subv.__subodi4(a, b, &overflow); | 12 | // Overflow occurred iff the operands have opposite signs, and the sign of the |
| 14 | if (overflow != 0) @panic("compiler-rt: integer overflow"); | 13 | // sum is the opposite of the lhs sign. |
| 14 | if (((a ^ b) & (sum ^ a)) < 0) @panic("compiler-rt: integer overflow"); | ||
| 15 | return sum; | 15 | return sum; |
| 16 | } | 16 | } |
| 17 | 17 |
lib/compiler_rt/subvsi3.zig+4-4| ... | @@ -1,4 +1,3 @@ | ... | @@ -1,4 +1,3 @@ |
| 1 | const subv = @import("subo.zig"); | ||
| 2 | const common = @import("./common.zig"); | 1 | const common = @import("./common.zig"); |
| 3 | const testing = @import("std").testing; | 2 | const testing = @import("std").testing; |
| 4 | 3 | ||
| ... | @@ -9,9 +8,10 @@ comptime { | ... | @@ -9,9 +8,10 @@ comptime { |
| 9 | } | 8 | } |
| 10 | 9 | ||
| 11 | pub fn __subvsi3(a: i32, b: i32) callconv(.c) i32 { | 10 | pub fn __subvsi3(a: i32, b: i32) callconv(.c) i32 { |
| 12 | var overflow: c_int = 0; | 11 | const sum = a -% b; |
| 13 | const sum = subv.__subosi4(a, b, &overflow); | 12 | // Overflow occurred iff the operands have opposite signs, and the sign of the |
| 14 | if (overflow != 0) @panic("compiler-rt: integer overflow"); | 13 | // sum is the opposite of the lhs sign. |
| 14 | if (((a ^ b) & (sum ^ a)) < 0) @panic("compiler-rt: integer overflow"); | ||
| 15 | return sum; | 15 | return sum; |
| 16 | } | 16 | } |
| 17 | 17 |