aboutsummaryrefslogtreecommitdiff
path: root/lib/std
diff options
context:
space:
mode:
Diffstat (limited to 'lib/std')
-rw-r--r--lib/std/special/compiler_rt.zig6
-rw-r--r--lib/std/special/compiler_rt/addo.zig38
-rw-r--r--lib/std/special/compiler_rt/addodi4_test.zig77
-rw-r--r--lib/std/special/compiler_rt/addosi4_test.zig78
-rw-r--r--lib/std/special/compiler_rt/addoti4_test.zig77
-rw-r--r--lib/std/special/compiler_rt/mulo.zig2
6 files changed, 277 insertions, 1 deletions
diff --git a/lib/std/special/compiler_rt.zig b/lib/std/special/compiler_rt.zig
index da21745cce..286237aa7b 100644
--- a/lib/std/special/compiler_rt.zig
+++ b/lib/std/special/compiler_rt.zig
@@ -106,6 +106,12 @@ comptime {
}
// Integral arithmetic which returns if overflow
+ const __addosi4 = @import("compiler_rt/addo.zig").__addosi4;
+ @export(__addosi4, .{ .name = "__addosi4", .linkage = linkage });
+ const __addodi4 = @import("compiler_rt/addo.zig").__addodi4;
+ @export(__addodi4, .{ .name = "__addodi4", .linkage = linkage });
+ const __addoti4 = @import("compiler_rt/addo.zig").__addoti4;
+ @export(__addoti4, .{ .name = "__addoti4", .linkage = linkage });
const __mulosi4 = @import("compiler_rt/mulo.zig").__mulosi4;
@export(__mulosi4, .{ .name = "__mulosi4", .linkage = linkage });
const __mulodi4 = @import("compiler_rt/mulo.zig").__mulodi4;
diff --git a/lib/std/special/compiler_rt/addo.zig b/lib/std/special/compiler_rt/addo.zig
new file mode 100644
index 0000000000..966c74cb8e
--- /dev/null
+++ b/lib/std/special/compiler_rt/addo.zig
@@ -0,0 +1,38 @@
+const builtin = @import("builtin");
+
+// addo - add overflow
+// * return a+%b.
+// * return if a+b overflows => 1 else => 0
+// - addoXi4_generic as default
+
+inline fn addoXi4_generic(comptime ST: type, a: ST, b: ST, overflow: *c_int) ST {
+ @setRuntimeSafety(builtin.is_test);
+ overflow.* = 0;
+ var sum: ST = a +% b;
+ // Hackers Delight: section Overflow Detection, subsection Signed Add/Subtract
+ // Let sum = a +% b == a + b + carry == wraparound addition.
+ // Overflow in a+b+carry occurs, iff a and b have opposite signs
+ // and the sign of a+b+carry is the same as a (or equivalently b).
+ // Slower routine: res = ~(a ^ b) & ((sum ^ a)
+ // Faster routine: res = (sum ^ a) & (sum ^ b)
+ // Oerflow occured, iff (res < 0)
+ if (((sum ^ a) & (sum ^ b)) < 0)
+ overflow.* = 1;
+ return sum;
+}
+
+pub fn __addosi4(a: i32, b: i32, overflow: *c_int) callconv(.C) i32 {
+ return addoXi4_generic(i32, a, b, overflow);
+}
+pub fn __addodi4(a: i64, b: i64, overflow: *c_int) callconv(.C) i64 {
+ return addoXi4_generic(i64, a, b, overflow);
+}
+pub fn __addoti4(a: i128, b: i128, overflow: *c_int) callconv(.C) i128 {
+ return addoXi4_generic(i128, a, b, overflow);
+}
+
+test {
+ _ = @import("addosi4_test.zig");
+ _ = @import("addodi4_test.zig");
+ _ = @import("addoti4_test.zig");
+}
diff --git a/lib/std/special/compiler_rt/addodi4_test.zig b/lib/std/special/compiler_rt/addodi4_test.zig
new file mode 100644
index 0000000000..f70a80a5b2
--- /dev/null
+++ b/lib/std/special/compiler_rt/addodi4_test.zig
@@ -0,0 +1,77 @@
+const addv = @import("addo.zig");
+const std = @import("std");
+const testing = std.testing;
+const math = std.math;
+
+fn test__addodi4(a: i64, b: i64) !void {
+ var result_ov: c_int = undefined;
+ var expected_ov: c_int = undefined;
+ var result = addv.__addodi4(a, b, &result_ov);
+ var expected: i64 = simple_addodi4(a, b, &expected_ov);
+ try testing.expectEqual(expected, result);
+ try testing.expectEqual(expected_ov, result_ov);
+}
+
+fn simple_addodi4(a: i64, b: i64, overflow: *c_int) i64 {
+ overflow.* = 0;
+ const min: i64 = math.minInt(i64);
+ const max: i64 = math.maxInt(i64);
+ if (((a > 0) and (b > max - a)) or
+ ((a < 0) and (b < min - a)))
+ overflow.* = 1;
+ return a +% b;
+}
+
+test "addodi4" {
+ const min: i64 = math.minInt(i64);
+ const max: i64 = math.maxInt(i64);
+ var i: i64 = 1;
+ while (i < max) : (i *|= 2) {
+ try test__addodi4(i, i);
+ try test__addodi4(-i, -i);
+ try test__addodi4(i, -i);
+ try test__addodi4(-i, i);
+ }
+
+ // edge cases
+ // 0 + 0 = 0
+ // MIN + MIN overflow
+ // MAX + MAX overflow
+ // 0 + MIN MIN
+ // 0 + MAX MAX
+ // MIN + 0 MIN
+ // MAX + 0 MAX
+ // MIN + MAX -1
+ // MAX + MIN -1
+ try test__addodi4(0, 0);
+ try test__addodi4(min, min);
+ try test__addodi4(max, max);
+ try test__addodi4(0, min);
+ try test__addodi4(0, max);
+ try test__addodi4(min, 0);
+ try test__addodi4(max, 0);
+ try test__addodi4(min, max);
+ try test__addodi4(max, min);
+
+ // derived edge cases
+ // MIN+1 + MIN overflow
+ // MAX-1 + MAX overflow
+ // 1 + MIN = MIN+1
+ // -1 + MIN overflow
+ // -1 + MAX = MAX-1
+ // +1 + MAX overflow
+ // MIN + 1 = MIN+1
+ // MIN + -1 overflow
+ // MAX + 1 overflow
+ // MAX + -1 = MAX-1
+ try test__addodi4(min + 1, min);
+ try test__addodi4(max - 1, max);
+ try test__addodi4(1, min);
+ try test__addodi4(-1, min);
+ try test__addodi4(-1, max);
+ try test__addodi4(1, max);
+ try test__addodi4(min, 1);
+ try test__addodi4(min, -1);
+ try test__addodi4(max, -1);
+ try test__addodi4(max, 1);
+}
diff --git a/lib/std/special/compiler_rt/addosi4_test.zig b/lib/std/special/compiler_rt/addosi4_test.zig
new file mode 100644
index 0000000000..a8f81d70d1
--- /dev/null
+++ b/lib/std/special/compiler_rt/addosi4_test.zig
@@ -0,0 +1,78 @@
+const addv = @import("addo.zig");
+const testing = @import("std").testing;
+
+fn test__addosi4(a: i32, b: i32) !void {
+ var result_ov: c_int = undefined;
+ var expected_ov: c_int = undefined;
+ var result = addv.__addosi4(a, b, &result_ov);
+ var expected: i32 = simple_addosi4(a, b, &expected_ov);
+ try testing.expectEqual(expected, result);
+ try testing.expectEqual(expected_ov, result_ov);
+}
+
+fn simple_addosi4(a: i32, b: i32, overflow: *c_int) i32 {
+ overflow.* = 0;
+ const min: i32 = -2147483648;
+ const max: i32 = 2147483647;
+ if (((a > 0) and (b > max - a)) or
+ ((a < 0) and (b < min - a)))
+ overflow.* = 1;
+ return a +% b;
+}
+
+test "addosi4" {
+ // -2^31 <= i32 <= 2^31-1
+ // 2^31 = 2147483648
+ // 2^31-1 = 2147483647
+ const min: i32 = -2147483648;
+ const max: i32 = 2147483647;
+ var i: i32 = 1;
+ while (i < max) : (i *|= 2) {
+ try test__addosi4(i, i);
+ try test__addosi4(-i, -i);
+ try test__addosi4(i, -i);
+ try test__addosi4(-i, i);
+ }
+
+ // edge cases
+ // 0 + 0 = 0
+ // MIN + MIN overflow
+ // MAX + MAX overflow
+ // 0 + MIN MIN
+ // 0 + MAX MAX
+ // MIN + 0 MIN
+ // MAX + 0 MAX
+ // MIN + MAX -1
+ // MAX + MIN -1
+ try test__addosi4(0, 0);
+ try test__addosi4(min, min);
+ try test__addosi4(max, max);
+ try test__addosi4(0, min);
+ try test__addosi4(0, max);
+ try test__addosi4(min, 0);
+ try test__addosi4(max, 0);
+ try test__addosi4(min, max);
+ try test__addosi4(max, min);
+
+ // derived edge cases
+ // MIN+1 + MIN overflow
+ // MAX-1 + MAX overflow
+ // 1 + MIN = MIN+1
+ // -1 + MIN overflow
+ // -1 + MAX = MAX-1
+ // +1 + MAX overflow
+ // MIN + 1 = MIN+1
+ // MIN + -1 overflow
+ // MAX + 1 overflow
+ // MAX + -1 = MAX-1
+ try test__addosi4(min + 1, min);
+ try test__addosi4(max - 1, max);
+ try test__addosi4(1, min);
+ try test__addosi4(-1, min);
+ try test__addosi4(-1, max);
+ try test__addosi4(1, max);
+ try test__addosi4(min, 1);
+ try test__addosi4(min, -1);
+ try test__addosi4(max, -1);
+ try test__addosi4(max, 1);
+}
diff --git a/lib/std/special/compiler_rt/addoti4_test.zig b/lib/std/special/compiler_rt/addoti4_test.zig
new file mode 100644
index 0000000000..dd0f4e3d3c
--- /dev/null
+++ b/lib/std/special/compiler_rt/addoti4_test.zig
@@ -0,0 +1,77 @@
+const addv = @import("addo.zig");
+const std = @import("std");
+const testing = std.testing;
+const math = std.math;
+
+fn test__addoti4(a: i128, b: i128) !void {
+ var result_ov: c_int = undefined;
+ var expected_ov: c_int = undefined;
+ var result = addv.__addoti4(a, b, &result_ov);
+ var expected: i128 = simple_addoti4(a, b, &expected_ov);
+ try testing.expectEqual(expected, result);
+ try testing.expectEqual(expected_ov, result_ov);
+}
+
+fn simple_addoti4(a: i128, b: i128, overflow: *c_int) i128 {
+ overflow.* = 0;
+ const min: i128 = math.minInt(i128);
+ const max: i128 = math.maxInt(i128);
+ if (((a > 0) and (b > max - a)) or
+ ((a < 0) and (b < min - a)))
+ overflow.* = 1;
+ return a +% b;
+}
+
+test "addoti4" {
+ const min: i128 = math.minInt(i128);
+ const max: i128 = math.maxInt(i128);
+ var i: i128 = 1;
+ while (i < max) : (i *|= 2) {
+ try test__addoti4(i, i);
+ try test__addoti4(-i, -i);
+ try test__addoti4(i, -i);
+ try test__addoti4(-i, i);
+ }
+
+ // edge cases
+ // 0 + 0 = 0
+ // MIN + MIN overflow
+ // MAX + MAX overflow
+ // 0 + MIN MIN
+ // 0 + MAX MAX
+ // MIN + 0 MIN
+ // MAX + 0 MAX
+ // MIN + MAX -1
+ // MAX + MIN -1
+ try test__addoti4(0, 0);
+ try test__addoti4(min, min);
+ try test__addoti4(max, max);
+ try test__addoti4(0, min);
+ try test__addoti4(0, max);
+ try test__addoti4(min, 0);
+ try test__addoti4(max, 0);
+ try test__addoti4(min, max);
+ try test__addoti4(max, min);
+
+ // derived edge cases
+ // MIN+1 + MIN overflow
+ // MAX-1 + MAX overflow
+ // 1 + MIN = MIN+1
+ // -1 + MIN overflow
+ // -1 + MAX = MAX-1
+ // +1 + MAX overflow
+ // MIN + 1 = MIN+1
+ // MIN + -1 overflow
+ // MAX + 1 overflow
+ // MAX + -1 = MAX-1
+ try test__addoti4(min + 1, min);
+ try test__addoti4(max - 1, max);
+ try test__addoti4(1, min);
+ try test__addoti4(-1, min);
+ try test__addoti4(-1, max);
+ try test__addoti4(1, max);
+ try test__addoti4(min, 1);
+ try test__addoti4(min, -1);
+ try test__addoti4(max, -1);
+ try test__addoti4(max, 1);
+}
diff --git a/lib/std/special/compiler_rt/mulo.zig b/lib/std/special/compiler_rt/mulo.zig
index df4c98134c..78590e5ce1 100644
--- a/lib/std/special/compiler_rt/mulo.zig
+++ b/lib/std/special/compiler_rt/mulo.zig
@@ -3,7 +3,7 @@ const std = @import("std");
const math = std.math;
// mulo - multiplication overflow
-// * return a*b.
+// * return a*%b.
// * return if a*b overflows => 1 else => 0
// - muloXi4_genericSmall as default
// - muloXi4_genericFast for 2*bitsize <= usize