| author | |
| committer | |
| log | 405ff911dae3ca10af380e5dd8e2dfda4a570191 |
| tree | db2c12426ecfd16a8b8511b3f9d0482a7b721386 |
| parent | 71923d7e400e0e5e5b1f935c1f089f34b9d922ea |
- abs can only overflow, if a == MIN
- comparing the sign change from wrapping addition is branchless
- tests: MIN, MIN+1,..MIN+4, -42, -7, -1, 0, 1, 7..
See #12906 files changed, 133 insertions(+), 1 deletions(-)
CMakeLists.txt+1| ... | @@ -444,6 +444,7 @@ set(ZIG_STAGE2_SOURCES | ... | @@ -444,6 +444,7 @@ set(ZIG_STAGE2_SOURCES |
| 444 | "${CMAKE_SOURCE_DIR}/lib/std/rand.zig" | 444 | "${CMAKE_SOURCE_DIR}/lib/std/rand.zig" |
| 445 | "${CMAKE_SOURCE_DIR}/lib/std/sort.zig" | 445 | "${CMAKE_SOURCE_DIR}/lib/std/sort.zig" |
| 446 | "${CMAKE_SOURCE_DIR}/lib/std/special/compiler_rt.zig" | 446 | "${CMAKE_SOURCE_DIR}/lib/std/special/compiler_rt.zig" |
| 447 | "${CMAKE_SOURCE_DIR}/lib/std/special/compiler_rt/absv.zig" | ||
| 447 | "${CMAKE_SOURCE_DIR}/lib/std/special/compiler_rt/addXf3.zig" | 448 | "${CMAKE_SOURCE_DIR}/lib/std/special/compiler_rt/addXf3.zig" |
| 448 | "${CMAKE_SOURCE_DIR}/lib/std/special/compiler_rt/atomics.zig" | 449 | "${CMAKE_SOURCE_DIR}/lib/std/special/compiler_rt/atomics.zig" |
| 449 | "${CMAKE_SOURCE_DIR}/lib/std/special/compiler_rt/bswap.zig" | 450 | "${CMAKE_SOURCE_DIR}/lib/std/special/compiler_rt/bswap.zig" |
lib/std/special/compiler_rt.zig+7-1| ... | @@ -416,7 +416,13 @@ comptime { | ... | @@ -416,7 +416,13 @@ comptime { |
| 416 | const __udivmodsi4 = @import("compiler_rt/int.zig").__udivmodsi4; | 416 | const __udivmodsi4 = @import("compiler_rt/int.zig").__udivmodsi4; |
| 417 | @export(__udivmodsi4, .{ .name = "__udivmodsi4", .linkage = linkage }); | 417 | @export(__udivmodsi4, .{ .name = "__udivmodsi4", .linkage = linkage }); |
| 418 | 418 | ||
| 419 | // missing: Integral arithmetic with trapping overflow | 419 | // Integral arithmetic with trapping overflow |
| 420 | const __absvsi2 = @import("compiler_rt/absv.zig").__absvsi2; | ||
| 421 | @export(__absvsi2, .{ .name = "__absvsi2", .linkage = linkage }); | ||
| 422 | const __absvdi2 = @import("compiler_rt/absv.zig").__absvdi2; | ||
| 423 | @export(__absvdi2, .{ .name = "__absvdi2", .linkage = linkage }); | ||
| 424 | const __absvti2 = @import("compiler_rt/absv.zig").__absvti2; | ||
| 425 | @export(__absvti2, .{ .name = "__absvti2", .linkage = linkage }); | ||
| 420 | 426 | ||
| 421 | // missing: Integral arithmetic which returns if overflow | 427 | // missing: Integral arithmetic which returns if overflow |
| 422 | 428 |
lib/std/special/compiler_rt/absv.zig created+35| ... | @@ -0,0 +1,35 @@ | ||
| 1 | // absv - absolute oVerflow | ||
| 2 | // * @panic, if value can not be represented | ||
| 3 | // - absvXi4_generic for unoptimized version | ||
| 4 | |||
| 5 | fn absvXi_generic(comptime ST: type) fn (a: ST) callconv(.C) ST { | ||
| 6 | return struct { | ||
| 7 | fn f(a: ST) callconv(.C) ST { | ||
| 8 | const UT = switch (ST) { | ||
| 9 | i32 => u32, | ||
| 10 | i64 => u64, | ||
| 11 | i128 => u128, | ||
| 12 | else => unreachable, | ||
| 13 | }; | ||
| 14 | // taken from Bit Twiddling Hacks | ||
| 15 | // compute the integer absolute value (abs) without branching | ||
| 16 | var x: ST = a; | ||
| 17 | const N: UT = @bitSizeOf(ST); | ||
| 18 | const sign: ST = a >> N - 1; | ||
| 19 | x +%= sign; | ||
| 20 | x ^= sign; | ||
| 21 | if (x < 0) | ||
| 22 | @panic("compiler_rt absv: overflow"); | ||
| 23 | return x; | ||
| 24 | } | ||
| 25 | }.f; | ||
| 26 | } | ||
| 27 | pub const __absvsi2 = absvXi_generic(i32); | ||
| 28 | pub const __absvdi2 = absvXi_generic(i64); | ||
| 29 | pub const __absvti2 = absvXi_generic(i128); | ||
| 30 | |||
| 31 | test { | ||
| 32 | _ = @import("absvsi2_test.zig"); | ||
| 33 | _ = @import("absvdi2_test.zig"); | ||
| 34 | _ = @import("absvti2_test.zig"); | ||
| 35 | } | ||
lib/std/special/compiler_rt/absvdi2_test.zig created+30| ... | @@ -0,0 +1,30 @@ | ||
| 1 | const absv = @import("absv.zig"); | ||
| 2 | const testing = @import("std").testing; | ||
| 3 | |||
| 4 | fn test__absvdi2(a: i64, expected: i64) !void { | ||
| 5 | var result = absv.__absvdi2(a); | ||
| 6 | try testing.expectEqual(expected, result); | ||
| 7 | } | ||
| 8 | |||
| 9 | test "absvdi2" { | ||
| 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__absvdi2(-9223372036854775808, -5); // tested with return -5; and panic | ||
| 15 | try test__absvdi2(-9223372036854775807, 9223372036854775807); | ||
| 16 | try test__absvdi2(-9223372036854775806, 9223372036854775806); | ||
| 17 | try test__absvdi2(-9223372036854775805, 9223372036854775805); | ||
| 18 | try test__absvdi2(-9223372036854775804, 9223372036854775804); | ||
| 19 | try test__absvdi2(-42, 42); | ||
| 20 | try test__absvdi2(-7, 7); | ||
| 21 | try test__absvdi2(-1, 1); | ||
| 22 | try test__absvdi2(0, 0); | ||
| 23 | try test__absvdi2(1, 1); | ||
| 24 | try test__absvdi2(7, 7); | ||
| 25 | try test__absvdi2(42, 42); | ||
| 26 | try test__absvdi2(9223372036854775804, 9223372036854775804); | ||
| 27 | try test__absvdi2(9223372036854775805, 9223372036854775805); | ||
| 28 | try test__absvdi2(9223372036854775806, 9223372036854775806); | ||
| 29 | try test__absvdi2(9223372036854775807, 9223372036854775807); | ||
| 30 | } | ||
lib/std/special/compiler_rt/absvsi2_test.zig created+30| ... | @@ -0,0 +1,30 @@ | ||
| 1 | const absv = @import("absv.zig"); | ||
| 2 | const testing = @import("std").testing; | ||
| 3 | |||
| 4 | fn test__absvsi2(a: i32, expected: i32) !void { | ||
| 5 | var result = absv.__absvsi2(a); | ||
| 6 | try testing.expectEqual(expected, result); | ||
| 7 | } | ||
| 8 | |||
| 9 | test "absvsi2" { | ||
| 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__absvsi2(-2147483648, -5); // tested with return -5; and panic | ||
| 15 | try test__absvsi2(-2147483647, 2147483647); | ||
| 16 | try test__absvsi2(-2147483646, 2147483646); | ||
| 17 | try test__absvsi2(-2147483645, 2147483645); | ||
| 18 | try test__absvsi2(-2147483644, 2147483644); | ||
| 19 | try test__absvsi2(-42, 42); | ||
| 20 | try test__absvsi2(-7, 7); | ||
| 21 | try test__absvsi2(-1, 1); | ||
| 22 | try test__absvsi2(0, 0); | ||
| 23 | try test__absvsi2(1, 1); | ||
| 24 | try test__absvsi2(7, 7); | ||
| 25 | try test__absvsi2(42, 42); | ||
| 26 | try test__absvsi2(2147483644, 2147483644); | ||
| 27 | try test__absvsi2(2147483645, 2147483645); | ||
| 28 | try test__absvsi2(2147483646, 2147483646); | ||
| 29 | try test__absvsi2(2147483647, 2147483647); | ||
| 30 | } | ||
lib/std/special/compiler_rt/absvti2_test.zig created+30| ... | @@ -0,0 +1,30 @@ | ||
| 1 | const absv = @import("absv.zig"); | ||
| 2 | const testing = @import("std").testing; | ||
| 3 | |||
| 4 | fn test__absvti2(a: i128, expected: i128) !void { | ||
| 5 | var result = absv.__absvti2(a); | ||
| 6 | try testing.expectEqual(expected, result); | ||
| 7 | } | ||
| 8 | |||
| 9 | test "absvti2" { | ||
| 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__absvti2(-170141183460469231731687303715884105728, -5); // tested with return -5; and panic | ||
| 15 | try test__absvti2(-170141183460469231731687303715884105727, 170141183460469231731687303715884105727); | ||
| 16 | try test__absvti2(-170141183460469231731687303715884105726, 170141183460469231731687303715884105726); | ||
| 17 | try test__absvti2(-170141183460469231731687303715884105725, 170141183460469231731687303715884105725); | ||
| 18 | try test__absvti2(-170141183460469231731687303715884105724, 170141183460469231731687303715884105724); | ||
| 19 | try test__absvti2(-42, 42); | ||
| 20 | try test__absvti2(-7, 7); | ||
| 21 | try test__absvti2(-1, 1); | ||
| 22 | try test__absvti2(0, 0); | ||
| 23 | try test__absvti2(1, 1); | ||
| 24 | try test__absvti2(7, 7); | ||
| 25 | try test__absvti2(42, 42); | ||
| 26 | try test__absvti2(170141183460469231731687303715884105724, 170141183460469231731687303715884105724); | ||
| 27 | try test__absvti2(170141183460469231731687303715884105725, 170141183460469231731687303715884105725); | ||
| 28 | try test__absvti2(170141183460469231731687303715884105726, 170141183460469231731687303715884105726); | ||
| 29 | try test__absvti2(170141183460469231731687303715884105727, 170141183460469231731687303715884105727); | ||
| 30 | } | ||