aboutsummaryrefslogtreecommitdiff
path: root/lib/std
diff options
context:
space:
mode:
authorJan Philipp Hafer <jan.hafer@rwth-aachen.de>2021-12-12 22:25:29 +0100
committerAndrew Kelley <andrew@ziglang.org>2021-12-26 13:21:18 -0800
commit405ff911dae3ca10af380e5dd8e2dfda4a570191 (patch)
treedb2c12426ecfd16a8b8511b3f9d0482a7b721386 /lib/std
parent71923d7e400e0e5e5b1f935c1f089f34b9d922ea (diff)
downloadzig-405ff911dae3ca10af380e5dd8e2dfda4a570191.tar.gz
zig-405ff911dae3ca10af380e5dd8e2dfda4a570191.zip
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
Diffstat (limited to 'lib/std')
-rw-r--r--lib/std/special/compiler_rt.zig8
-rw-r--r--lib/std/special/compiler_rt/absv.zig35
-rw-r--r--lib/std/special/compiler_rt/absvdi2_test.zig30
-rw-r--r--lib/std/special/compiler_rt/absvsi2_test.zig30
-rw-r--r--lib/std/special/compiler_rt/absvti2_test.zig30
5 files changed, 132 insertions, 1 deletions
diff --git a/lib/std/special/compiler_rt.zig b/lib/std/special/compiler_rt.zig
index c8cb00ee3e..6d2f76bf3c 100644
--- a/lib/std/special/compiler_rt.zig
+++ b/lib/std/special/compiler_rt.zig
@@ -416,7 +416,13 @@ comptime {
const __udivmodsi4 = @import("compiler_rt/int.zig").__udivmodsi4;
@export(__udivmodsi4, .{ .name = "__udivmodsi4", .linkage = linkage });
- // missing: Integral arithmetic with trapping overflow
+ // Integral arithmetic with trapping overflow
+ const __absvsi2 = @import("compiler_rt/absv.zig").__absvsi2;
+ @export(__absvsi2, .{ .name = "__absvsi2", .linkage = linkage });
+ const __absvdi2 = @import("compiler_rt/absv.zig").__absvdi2;
+ @export(__absvdi2, .{ .name = "__absvdi2", .linkage = linkage });
+ const __absvti2 = @import("compiler_rt/absv.zig").__absvti2;
+ @export(__absvti2, .{ .name = "__absvti2", .linkage = linkage });
// missing: Integral arithmetic which returns if overflow
diff --git a/lib/std/special/compiler_rt/absv.zig b/lib/std/special/compiler_rt/absv.zig
new file mode 100644
index 0000000000..5c46d028a9
--- /dev/null
+++ b/lib/std/special/compiler_rt/absv.zig
@@ -0,0 +1,35 @@
+// absv - absolute oVerflow
+// * @panic, if value can not be represented
+// - absvXi4_generic for unoptimized version
+
+fn absvXi_generic(comptime ST: type) fn (a: ST) callconv(.C) ST {
+ return struct {
+ fn f(a: ST) callconv(.C) ST {
+ const UT = switch (ST) {
+ i32 => u32,
+ i64 => u64,
+ i128 => u128,
+ else => unreachable,
+ };
+ // taken from Bit Twiddling Hacks
+ // compute the integer absolute value (abs) without branching
+ var x: ST = a;
+ const N: UT = @bitSizeOf(ST);
+ const sign: ST = a >> N - 1;
+ x +%= sign;
+ x ^= sign;
+ if (x < 0)
+ @panic("compiler_rt absv: overflow");
+ return x;
+ }
+ }.f;
+}
+pub const __absvsi2 = absvXi_generic(i32);
+pub const __absvdi2 = absvXi_generic(i64);
+pub const __absvti2 = absvXi_generic(i128);
+
+test {
+ _ = @import("absvsi2_test.zig");
+ _ = @import("absvdi2_test.zig");
+ _ = @import("absvti2_test.zig");
+}
diff --git a/lib/std/special/compiler_rt/absvdi2_test.zig b/lib/std/special/compiler_rt/absvdi2_test.zig
new file mode 100644
index 0000000000..4aa73513ee
--- /dev/null
+++ b/lib/std/special/compiler_rt/absvdi2_test.zig
@@ -0,0 +1,30 @@
+const absv = @import("absv.zig");
+const testing = @import("std").testing;
+
+fn test__absvdi2(a: i64, expected: i64) !void {
+ var result = absv.__absvdi2(a);
+ try testing.expectEqual(expected, result);
+}
+
+test "absvdi2" {
+ // -2^63 <= i64 <= 2^63-1
+ // 2^63 = 9223372036854775808
+ // 2^63-1 = 9223372036854775807
+ // TODO write panic handler for testing panics
+ //try test__absvdi2(-9223372036854775808, -5); // tested with return -5; and panic
+ try test__absvdi2(-9223372036854775807, 9223372036854775807);
+ try test__absvdi2(-9223372036854775806, 9223372036854775806);
+ try test__absvdi2(-9223372036854775805, 9223372036854775805);
+ try test__absvdi2(-9223372036854775804, 9223372036854775804);
+ try test__absvdi2(-42, 42);
+ try test__absvdi2(-7, 7);
+ try test__absvdi2(-1, 1);
+ try test__absvdi2(0, 0);
+ try test__absvdi2(1, 1);
+ try test__absvdi2(7, 7);
+ try test__absvdi2(42, 42);
+ try test__absvdi2(9223372036854775804, 9223372036854775804);
+ try test__absvdi2(9223372036854775805, 9223372036854775805);
+ try test__absvdi2(9223372036854775806, 9223372036854775806);
+ try test__absvdi2(9223372036854775807, 9223372036854775807);
+}
diff --git a/lib/std/special/compiler_rt/absvsi2_test.zig b/lib/std/special/compiler_rt/absvsi2_test.zig
new file mode 100644
index 0000000000..2cc3dbf991
--- /dev/null
+++ b/lib/std/special/compiler_rt/absvsi2_test.zig
@@ -0,0 +1,30 @@
+const absv = @import("absv.zig");
+const testing = @import("std").testing;
+
+fn test__absvsi2(a: i32, expected: i32) !void {
+ var result = absv.__absvsi2(a);
+ try testing.expectEqual(expected, result);
+}
+
+test "absvsi2" {
+ // -2^31 <= i32 <= 2^31-1
+ // 2^31 = 2147483648
+ // 2^31-1 = 2147483647
+ // TODO write panic handler for testing panics
+ //try test__absvsi2(-2147483648, -5); // tested with return -5; and panic
+ try test__absvsi2(-2147483647, 2147483647);
+ try test__absvsi2(-2147483646, 2147483646);
+ try test__absvsi2(-2147483645, 2147483645);
+ try test__absvsi2(-2147483644, 2147483644);
+ try test__absvsi2(-42, 42);
+ try test__absvsi2(-7, 7);
+ try test__absvsi2(-1, 1);
+ try test__absvsi2(0, 0);
+ try test__absvsi2(1, 1);
+ try test__absvsi2(7, 7);
+ try test__absvsi2(42, 42);
+ try test__absvsi2(2147483644, 2147483644);
+ try test__absvsi2(2147483645, 2147483645);
+ try test__absvsi2(2147483646, 2147483646);
+ try test__absvsi2(2147483647, 2147483647);
+}
diff --git a/lib/std/special/compiler_rt/absvti2_test.zig b/lib/std/special/compiler_rt/absvti2_test.zig
new file mode 100644
index 0000000000..5b4deb3640
--- /dev/null
+++ b/lib/std/special/compiler_rt/absvti2_test.zig
@@ -0,0 +1,30 @@
+const absv = @import("absv.zig");
+const testing = @import("std").testing;
+
+fn test__absvti2(a: i128, expected: i128) !void {
+ var result = absv.__absvti2(a);
+ try testing.expectEqual(expected, result);
+}
+
+test "absvti2" {
+ // -2^127 <= i128 <= 2^127-1
+ // 2^127 = 170141183460469231731687303715884105728
+ // 2^127+1 = 170141183460469231731687303715884105727
+ // TODO write panic handler for testing panics
+ //try test__absvti2(-170141183460469231731687303715884105728, -5); // tested with return -5; and panic
+ try test__absvti2(-170141183460469231731687303715884105727, 170141183460469231731687303715884105727);
+ try test__absvti2(-170141183460469231731687303715884105726, 170141183460469231731687303715884105726);
+ try test__absvti2(-170141183460469231731687303715884105725, 170141183460469231731687303715884105725);
+ try test__absvti2(-170141183460469231731687303715884105724, 170141183460469231731687303715884105724);
+ try test__absvti2(-42, 42);
+ try test__absvti2(-7, 7);
+ try test__absvti2(-1, 1);
+ try test__absvti2(0, 0);
+ try test__absvti2(1, 1);
+ try test__absvti2(7, 7);
+ try test__absvti2(42, 42);
+ try test__absvti2(170141183460469231731687303715884105724, 170141183460469231731687303715884105724);
+ try test__absvti2(170141183460469231731687303715884105725, 170141183460469231731687303715884105725);
+ try test__absvti2(170141183460469231731687303715884105726, 170141183460469231731687303715884105726);
+ try test__absvti2(170141183460469231731687303715884105727, 170141183460469231731687303715884105727);
+}