| author | |
| committer | |
| log | 17046674a745faaa34cf2646b9cf43455b12aba9 |
| tree | 0826d357cbfedea2e0b5309b1316b2ea731d1dbf |
| parent | 70894d5c2f6032b0d0be1fa00a30554b7e6db2d6 |
- neg can only overflow, if a == MIN
- case `-0` is properly handled by hardware, so overflow check by comparing
`a == MIN` is sufficient
- tests: MIN, MIN+1, MIN+4, -42, -7, -1, 0, 1, 7..
See #12906 files changed, 128 insertions(+), 0 deletions(-)
CMakeLists.txt+1| ... | ... | @@ -500,6 +500,7 @@ set(ZIG_STAGE2_SOURCES |
| 500 | 500 | "${CMAKE_SOURCE_DIR}/lib/std/special/compiler_rt/multi3.zig" |
| 501 | 501 | "${CMAKE_SOURCE_DIR}/lib/std/special/compiler_rt/negXf2.zig" |
| 502 | 502 | "${CMAKE_SOURCE_DIR}/lib/std/special/compiler_rt/negXi2.zig" |
| 503 | "${CMAKE_SOURCE_DIR}/lib/std/special/compiler_rt/negv.zig" | |
| 503 | 504 | "${CMAKE_SOURCE_DIR}/lib/std/special/compiler_rt/os_version_check.zig" |
| 504 | 505 | "${CMAKE_SOURCE_DIR}/lib/std/special/compiler_rt/parity.zig" |
| 505 | 506 | "${CMAKE_SOURCE_DIR}/lib/std/special/compiler_rt/popcount.zig" |
lib/std/special/compiler_rt.zig+6| ... | ... | @@ -423,6 +423,12 @@ comptime { |
| 423 | 423 | @export(__absvdi2, .{ .name = "__absvdi2", .linkage = linkage }); |
| 424 | 424 | const __absvti2 = @import("compiler_rt/absv.zig").__absvti2; |
| 425 | 425 | @export(__absvti2, .{ .name = "__absvti2", .linkage = linkage }); |
| 426 | const __negvsi2 = @import("compiler_rt/negv.zig").__negvsi2; | |
| 427 | @export(__negvsi2, .{ .name = "__negvsi2", .linkage = linkage }); | |
| 428 | const __negvdi2 = @import("compiler_rt/negv.zig").__negvdi2; | |
| 429 | @export(__negvdi2, .{ .name = "__negvdi2", .linkage = linkage }); | |
| 430 | const __negvti2 = @import("compiler_rt/negv.zig").__negvti2; | |
| 431 | @export(__negvti2, .{ .name = "__negvti2", .linkage = linkage }); | |
| 426 | 432 | |
| 427 | 433 | // missing: Integral arithmetic which returns if overflow |
| 428 | 434 |
lib/std/special/compiler_rt/negv.zig created+31| ... | ... | @@ -0,0 +1,31 @@ |
| 1 | // negv - negate oVerflow | |
| 2 | // * @panic, if result can not be represented | |
| 3 | // - negvXi4_generic for unoptimized version | |
| 4 | ||
| 5 | // assume -0 == 0 is gracefully handled by the hardware | |
| 6 | fn negvXi_generic(comptime ST: type) fn (a: ST) callconv(.C) ST { | |
| 7 | return struct { | |
| 8 | fn f(a: ST) callconv(.C) ST { | |
| 9 | const UT = switch (ST) { | |
| 10 | i32 => u32, | |
| 11 | i64 => u64, | |
| 12 | i128 => u128, | |
| 13 | else => unreachable, | |
| 14 | }; | |
| 15 | const N: UT = @bitSizeOf(ST); | |
| 16 | const min: ST = @bitCast(ST, (@as(UT, 1) << (N - 1))); | |
| 17 | if (a == min) | |
| 18 | @panic("compiler_rt negv: overflow"); | |
| 19 | return -a; | |
| 20 | } | |
| 21 | }.f; | |
| 22 | } | |
| 23 | pub const __negvsi2 = negvXi_generic(i32); | |
| 24 | pub const __negvdi2 = negvXi_generic(i64); | |
| 25 | pub const __negvti2 = negvXi_generic(i128); | |
| 26 | ||
| 27 | test { | |
| 28 | _ = @import("negvsi2_test.zig"); | |
| 29 | _ = @import("negvdi2_test.zig"); | |
| 30 | _ = @import("negvti2_test.zig"); | |
| 31 | } |
lib/std/special/compiler_rt/negvdi2_test.zig created+30| ... | ... | @@ -0,0 +1,30 @@ |
| 1 | const negv = @import("negv.zig"); | |
| 2 | const testing = @import("std").testing; | |
| 3 | ||
| 4 | fn test__negvdi2(a: i64, expected: i64) !void { | |
| 5 | var result = negv.__negvdi2(a); | |
| 6 | try testing.expectEqual(expected, result); | |
| 7 | } | |
| 8 | ||
| 9 | test "negvdi2" { | |
| 10 | // -2^63 <= i64 <= 2^63-1 | |
| 11 | // 2^63 = 9223372036854775808 | |
| 12 | // 2^63-1 = 9223372036854775807 | |
| 13 | // TODO write panic handler for testing panics | |
| 14 | //try test__negvdi2(-9223372036854775808, -5); // tested with return -5; and panic | |
| 15 | try test__negvdi2(-9223372036854775807, 9223372036854775807); | |
| 16 | try test__negvdi2(-9223372036854775806, 9223372036854775806); | |
| 17 | try test__negvdi2(-9223372036854775805, 9223372036854775805); | |
| 18 | try test__negvdi2(-9223372036854775804, 9223372036854775804); | |
| 19 | try test__negvdi2(-42, 42); | |
| 20 | try test__negvdi2(-7, 7); | |
| 21 | try test__negvdi2(-1, 1); | |
| 22 | try test__negvdi2(0, 0); | |
| 23 | try test__negvdi2(1, -1); | |
| 24 | try test__negvdi2(7, -7); | |
| 25 | try test__negvdi2(42, -42); | |
| 26 | try test__negvdi2(9223372036854775804, -9223372036854775804); | |
| 27 | try test__negvdi2(9223372036854775805, -9223372036854775805); | |
| 28 | try test__negvdi2(9223372036854775806, -9223372036854775806); | |
| 29 | try test__negvdi2(9223372036854775807, -9223372036854775807); | |
| 30 | } |
lib/std/special/compiler_rt/negvsi2_test.zig created+30| ... | ... | @@ -0,0 +1,30 @@ |
| 1 | const negv = @import("negv.zig"); | |
| 2 | const testing = @import("std").testing; | |
| 3 | ||
| 4 | fn test__negvsi2(a: i32, expected: i32) !void { | |
| 5 | var result = negv.__negvsi2(a); | |
| 6 | try testing.expectEqual(expected, result); | |
| 7 | } | |
| 8 | ||
| 9 | test "negvsi2" { | |
| 10 | // -2^31 <= i32 <= 2^31-1 | |
| 11 | // 2^31 = 2147483648 | |
| 12 | // 2^31-1 = 2147483647 | |
| 13 | // TODO write panic handler for testing panics | |
| 14 | //try test__negvsi2(-2147483648, -5); // tested with return -5; and panic | |
| 15 | try test__negvsi2(-2147483647, 2147483647); | |
| 16 | try test__negvsi2(-2147483646, 2147483646); | |
| 17 | try test__negvsi2(-2147483645, 2147483645); | |
| 18 | try test__negvsi2(-2147483644, 2147483644); | |
| 19 | try test__negvsi2(-42, 42); | |
| 20 | try test__negvsi2(-7, 7); | |
| 21 | try test__negvsi2(-1, 1); | |
| 22 | try test__negvsi2(0, 0); | |
| 23 | try test__negvsi2(1, -1); | |
| 24 | try test__negvsi2(7, -7); | |
| 25 | try test__negvsi2(42, -42); | |
| 26 | try test__negvsi2(2147483644, -2147483644); | |
| 27 | try test__negvsi2(2147483645, -2147483645); | |
| 28 | try test__negvsi2(2147483646, -2147483646); | |
| 29 | try test__negvsi2(2147483647, -2147483647); | |
| 30 | } |
lib/std/special/compiler_rt/negvti2_test.zig created+30| ... | ... | @@ -0,0 +1,30 @@ |
| 1 | const negv = @import("negv.zig"); | |
| 2 | const testing = @import("std").testing; | |
| 3 | ||
| 4 | fn test__negvti2(a: i128, expected: i128) !void { | |
| 5 | var result = negv.__negvti2(a); | |
| 6 | try testing.expectEqual(expected, result); | |
| 7 | } | |
| 8 | ||
| 9 | test "negvti2" { | |
| 10 | // -2^127 <= i128 <= 2^127-1 | |
| 11 | // 2^127 = 170141183460469231731687303715884105728 | |
| 12 | // 2^127+1 = 170141183460469231731687303715884105727 | |
| 13 | // TODO write panic handler for testing panics | |
| 14 | //try test__negvti2(-170141183460469231731687303715884105728, -5); // tested with return -5; and panic | |
| 15 | try test__negvti2(-170141183460469231731687303715884105727, 170141183460469231731687303715884105727); | |
| 16 | try test__negvti2(-170141183460469231731687303715884105726, 170141183460469231731687303715884105726); | |
| 17 | try test__negvti2(-170141183460469231731687303715884105725, 170141183460469231731687303715884105725); | |
| 18 | try test__negvti2(-170141183460469231731687303715884105724, 170141183460469231731687303715884105724); | |
| 19 | try test__negvti2(-42, 42); | |
| 20 | try test__negvti2(-7, 7); | |
| 21 | try test__negvti2(-1, 1); | |
| 22 | try test__negvti2(0, 0); | |
| 23 | try test__negvti2(1, -1); | |
| 24 | try test__negvti2(7, -7); | |
| 25 | try test__negvti2(42, -42); | |
| 26 | try test__negvti2(170141183460469231731687303715884105724, -170141183460469231731687303715884105724); | |
| 27 | try test__negvti2(170141183460469231731687303715884105725, -170141183460469231731687303715884105725); | |
| 28 | try test__negvti2(170141183460469231731687303715884105726, -170141183460469231731687303715884105726); | |
| 29 | try test__negvti2(170141183460469231731687303715884105727, -170141183460469231731687303715884105727); | |
| 30 | } |