| 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 | 211 | lib/compiler_rt/absvti2.zig |
| 212 | 212 | lib/compiler_rt/adddf3.zig |
| 213 | 213 | lib/compiler_rt/addf3.zig |
| 214 | lib/compiler_rt/addo.zig | |
| 215 | 214 | lib/compiler_rt/addsf3.zig |
| 216 | 215 | lib/compiler_rt/addtf3.zig |
| 217 | 216 | lib/compiler_rt/addvsi3.zig |
| 217 | lib/compiler_rt/addvdi3.zig | |
| 218 | 218 | lib/compiler_rt/addxf3.zig |
| 219 | 219 | lib/compiler_rt/arm.zig |
| 220 | 220 | lib/compiler_rt/atomics.zig |
| ... | ... | @@ -354,7 +354,6 @@ set(ZIG_STAGE2_SOURCES |
| 354 | 354 | lib/compiler_rt/sqrt.zig |
| 355 | 355 | lib/compiler_rt/stack_probe.zig |
| 356 | 356 | lib/compiler_rt/subdf3.zig |
| 357 | lib/compiler_rt/subo.zig | |
| 358 | 357 | lib/compiler_rt/subsf3.zig |
| 359 | 358 | lib/compiler_rt/subtf3.zig |
| 360 | 359 | lib/compiler_rt/subvdi3.zig |
lib/compiler_rt.zig+3-2| ... | ... | @@ -28,12 +28,13 @@ comptime { |
| 28 | 28 | _ = @import("compiler_rt/negv.zig"); |
| 29 | 29 | |
| 30 | 30 | _ = @import("compiler_rt/addvsi3.zig"); |
| 31 | _ = @import("compiler_rt/addvdi3.zig"); | |
| 32 | ||
| 31 | 33 | _ = @import("compiler_rt/subvsi3.zig"); |
| 32 | 34 | _ = @import("compiler_rt/subvdi3.zig"); |
| 35 | ||
| 33 | 36 | _ = @import("compiler_rt/mulvsi3.zig"); |
| 34 | 37 | |
| 35 | _ = @import("compiler_rt/addo.zig"); | |
| 36 | _ = @import("compiler_rt/subo.zig"); | |
| 37 | 38 | _ = @import("compiler_rt/mulo.zig"); |
| 38 | 39 | |
| 39 | 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 | const addv = @import("addo.zig"); | |
| 2 | 1 | const common = @import("./common.zig"); |
| 3 | 2 | const testing = @import("std").testing; |
| 4 | 3 | |
| ... | ... | @@ -9,9 +8,10 @@ comptime { |
| 9 | 8 | } |
| 10 | 9 | |
| 11 | 10 | pub fn __addvsi3(a: i32, b: i32) callconv(.c) i32 { |
| 12 | var overflow: c_int = 0; | |
| 13 | const sum = addv.__addosi4(a, b, &overflow); | |
| 14 | if (overflow != 0) @panic("compiler-rt: integer overflow"); | |
| 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 | 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 | const subv = @import("subo.zig"); | |
| 2 | 1 | const common = @import("./common.zig"); |
| 3 | 2 | const testing = @import("std").testing; |
| 4 | 3 | |
| ... | ... | @@ -9,9 +8,10 @@ comptime { |
| 9 | 8 | } |
| 10 | 9 | |
| 11 | 10 | pub fn __subvdi3(a: i64, b: i64) callconv(.c) i64 { |
| 12 | var overflow: c_int = 0; | |
| 13 | const sum = subv.__subodi4(a, b, &overflow); | |
| 14 | if (overflow != 0) @panic("compiler-rt: integer overflow"); | |
| 11 | const sum = a -% b; | |
| 12 | // Overflow occurred iff the operands have opposite signs, and the sign of the | |
| 13 | // sum is the opposite of the lhs sign. | |
| 14 | if (((a ^ b) & (sum ^ a)) < 0) @panic("compiler-rt: integer overflow"); | |
| 15 | 15 | return sum; |
| 16 | 16 | } |
| 17 | 17 |
lib/compiler_rt/subvsi3.zig+4-4| ... | ... | @@ -1,4 +1,3 @@ |
| 1 | const subv = @import("subo.zig"); | |
| 2 | 1 | const common = @import("./common.zig"); |
| 3 | 2 | const testing = @import("std").testing; |
| 4 | 3 | |
| ... | ... | @@ -9,9 +8,10 @@ comptime { |
| 9 | 8 | } |
| 10 | 9 | |
| 11 | 10 | pub fn __subvsi3(a: i32, b: i32) callconv(.c) i32 { |
| 12 | var overflow: c_int = 0; | |
| 13 | const sum = subv.__subosi4(a, b, &overflow); | |
| 14 | if (overflow != 0) @panic("compiler-rt: integer overflow"); | |
| 11 | const sum = a -% b; | |
| 12 | // Overflow occurred iff the operands have opposite signs, and the sign of the | |
| 13 | // sum is the opposite of the lhs sign. | |
| 14 | if (((a ^ b) & (sum ^ a)) < 0) @panic("compiler-rt: integer overflow"); | |
| 15 | 15 | return sum; |
| 16 | 16 | } |
| 17 | 17 |