authorgravatar for jan.hafer@rwth-aachen.deJan Philipp Hafer <jan.hafer@rwth-aachen.de> 2021-12-12 22:25:29+01:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2021-12-26 13:21:18-08:00
log405ff911dae3ca10af380e5dd8e2dfda4a570191
treedb2c12426ecfd16a8b8511b3f9d0482a7b721386
parent71923d7e400e0e5e5b1f935c1f089f34b9d922ea

compiler_rt: add __absvsi2, __absvdi2, __absvti2

- 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 #1290

6 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 });
418418
419 // missing: Integral arithmetic with trapping overflow419 // 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 });
420426
421 // missing: Integral arithmetic which returns if overflow427 // missing: Integral arithmetic which returns if overflow
422428
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
5fn 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}
27pub const __absvsi2 = absvXi_generic(i32);
28pub const __absvdi2 = absvXi_generic(i64);
29pub const __absvti2 = absvXi_generic(i128);
30
31test {
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 @@
1const absv = @import("absv.zig");
2const testing = @import("std").testing;
3
4fn test__absvdi2(a: i64, expected: i64) !void {
5 var result = absv.__absvdi2(a);
6 try testing.expectEqual(expected, result);
7}
8
9test "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 @@
1const absv = @import("absv.zig");
2const testing = @import("std").testing;
3
4fn test__absvsi2(a: i32, expected: i32) !void {
5 var result = absv.__absvsi2(a);
6 try testing.expectEqual(expected, result);
7}
8
9test "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 @@
1const absv = @import("absv.zig");
2const testing = @import("std").testing;
3
4fn test__absvti2(a: i128, expected: i128) !void {
5 var result = absv.__absvti2(a);
6 try testing.expectEqual(expected, result);
7}
8
9test "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}