From 17046674a745faaa34cf2646b9cf43455b12aba9 Mon Sep 17 00:00:00 2001 From: Jan Philipp Hafer Date: Sun, 12 Dec 2021 22:25:29 +0100 Subject: [PATCH] compiler_rt: add __negvsi2, __negvdi2, __negvti2 - 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 #1290 --- CMakeLists.txt | 1 + lib/std/special/compiler_rt.zig | 6 ++++ lib/std/special/compiler_rt/negv.zig | 31 ++++++++++++++++++++ lib/std/special/compiler_rt/negvdi2_test.zig | 30 +++++++++++++++++++ lib/std/special/compiler_rt/negvsi2_test.zig | 30 +++++++++++++++++++ lib/std/special/compiler_rt/negvti2_test.zig | 30 +++++++++++++++++++ 6 files changed, 128 insertions(+) create mode 100644 lib/std/special/compiler_rt/negv.zig create mode 100644 lib/std/special/compiler_rt/negvdi2_test.zig create mode 100644 lib/std/special/compiler_rt/negvsi2_test.zig create mode 100644 lib/std/special/compiler_rt/negvti2_test.zig diff --git a/CMakeLists.txt b/CMakeLists.txt index 12df765268..0cdedece99 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -500,6 +500,7 @@ set(ZIG_STAGE2_SOURCES "${CMAKE_SOURCE_DIR}/lib/std/special/compiler_rt/multi3.zig" "${CMAKE_SOURCE_DIR}/lib/std/special/compiler_rt/negXf2.zig" "${CMAKE_SOURCE_DIR}/lib/std/special/compiler_rt/negXi2.zig" + "${CMAKE_SOURCE_DIR}/lib/std/special/compiler_rt/negv.zig" "${CMAKE_SOURCE_DIR}/lib/std/special/compiler_rt/os_version_check.zig" "${CMAKE_SOURCE_DIR}/lib/std/special/compiler_rt/parity.zig" "${CMAKE_SOURCE_DIR}/lib/std/special/compiler_rt/popcount.zig" diff --git a/lib/std/special/compiler_rt.zig b/lib/std/special/compiler_rt.zig index 6d2f76bf3c..5445edc25a 100644 --- a/lib/std/special/compiler_rt.zig +++ b/lib/std/special/compiler_rt.zig @@ -423,6 +423,12 @@ comptime { @export(__absvdi2, .{ .name = "__absvdi2", .linkage = linkage }); const __absvti2 = @import("compiler_rt/absv.zig").__absvti2; @export(__absvti2, .{ .name = "__absvti2", .linkage = linkage }); + const __negvsi2 = @import("compiler_rt/negv.zig").__negvsi2; + @export(__negvsi2, .{ .name = "__negvsi2", .linkage = linkage }); + const __negvdi2 = @import("compiler_rt/negv.zig").__negvdi2; + @export(__negvdi2, .{ .name = "__negvdi2", .linkage = linkage }); + const __negvti2 = @import("compiler_rt/negv.zig").__negvti2; + @export(__negvti2, .{ .name = "__negvti2", .linkage = linkage }); // missing: Integral arithmetic which returns if overflow diff --git a/lib/std/special/compiler_rt/negv.zig b/lib/std/special/compiler_rt/negv.zig new file mode 100644 index 0000000000..99525a6e5b --- /dev/null +++ b/lib/std/special/compiler_rt/negv.zig @@ -0,0 +1,31 @@ +// negv - negate oVerflow +// * @panic, if result can not be represented +// - negvXi4_generic for unoptimized version + +// assume -0 == 0 is gracefully handled by the hardware +fn negvXi_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, + }; + const N: UT = @bitSizeOf(ST); + const min: ST = @bitCast(ST, (@as(UT, 1) << (N - 1))); + if (a == min) + @panic("compiler_rt negv: overflow"); + return -a; + } + }.f; +} +pub const __negvsi2 = negvXi_generic(i32); +pub const __negvdi2 = negvXi_generic(i64); +pub const __negvti2 = negvXi_generic(i128); + +test { + _ = @import("negvsi2_test.zig"); + _ = @import("negvdi2_test.zig"); + _ = @import("negvti2_test.zig"); +} diff --git a/lib/std/special/compiler_rt/negvdi2_test.zig b/lib/std/special/compiler_rt/negvdi2_test.zig new file mode 100644 index 0000000000..25a7213f69 --- /dev/null +++ b/lib/std/special/compiler_rt/negvdi2_test.zig @@ -0,0 +1,30 @@ +const negv = @import("negv.zig"); +const testing = @import("std").testing; + +fn test__negvdi2(a: i64, expected: i64) !void { + var result = negv.__negvdi2(a); + try testing.expectEqual(expected, result); +} + +test "negvdi2" { + // -2^63 <= i64 <= 2^63-1 + // 2^63 = 9223372036854775808 + // 2^63-1 = 9223372036854775807 + // TODO write panic handler for testing panics + //try test__negvdi2(-9223372036854775808, -5); // tested with return -5; and panic + try test__negvdi2(-9223372036854775807, 9223372036854775807); + try test__negvdi2(-9223372036854775806, 9223372036854775806); + try test__negvdi2(-9223372036854775805, 9223372036854775805); + try test__negvdi2(-9223372036854775804, 9223372036854775804); + try test__negvdi2(-42, 42); + try test__negvdi2(-7, 7); + try test__negvdi2(-1, 1); + try test__negvdi2(0, 0); + try test__negvdi2(1, -1); + try test__negvdi2(7, -7); + try test__negvdi2(42, -42); + try test__negvdi2(9223372036854775804, -9223372036854775804); + try test__negvdi2(9223372036854775805, -9223372036854775805); + try test__negvdi2(9223372036854775806, -9223372036854775806); + try test__negvdi2(9223372036854775807, -9223372036854775807); +} diff --git a/lib/std/special/compiler_rt/negvsi2_test.zig b/lib/std/special/compiler_rt/negvsi2_test.zig new file mode 100644 index 0000000000..4e0c27c9ae --- /dev/null +++ b/lib/std/special/compiler_rt/negvsi2_test.zig @@ -0,0 +1,30 @@ +const negv = @import("negv.zig"); +const testing = @import("std").testing; + +fn test__negvsi2(a: i32, expected: i32) !void { + var result = negv.__negvsi2(a); + try testing.expectEqual(expected, result); +} + +test "negvsi2" { + // -2^31 <= i32 <= 2^31-1 + // 2^31 = 2147483648 + // 2^31-1 = 2147483647 + // TODO write panic handler for testing panics + //try test__negvsi2(-2147483648, -5); // tested with return -5; and panic + try test__negvsi2(-2147483647, 2147483647); + try test__negvsi2(-2147483646, 2147483646); + try test__negvsi2(-2147483645, 2147483645); + try test__negvsi2(-2147483644, 2147483644); + try test__negvsi2(-42, 42); + try test__negvsi2(-7, 7); + try test__negvsi2(-1, 1); + try test__negvsi2(0, 0); + try test__negvsi2(1, -1); + try test__negvsi2(7, -7); + try test__negvsi2(42, -42); + try test__negvsi2(2147483644, -2147483644); + try test__negvsi2(2147483645, -2147483645); + try test__negvsi2(2147483646, -2147483646); + try test__negvsi2(2147483647, -2147483647); +} diff --git a/lib/std/special/compiler_rt/negvti2_test.zig b/lib/std/special/compiler_rt/negvti2_test.zig new file mode 100644 index 0000000000..aa50f2bd43 --- /dev/null +++ b/lib/std/special/compiler_rt/negvti2_test.zig @@ -0,0 +1,30 @@ +const negv = @import("negv.zig"); +const testing = @import("std").testing; + +fn test__negvti2(a: i128, expected: i128) !void { + var result = negv.__negvti2(a); + try testing.expectEqual(expected, result); +} + +test "negvti2" { + // -2^127 <= i128 <= 2^127-1 + // 2^127 = 170141183460469231731687303715884105728 + // 2^127+1 = 170141183460469231731687303715884105727 + // TODO write panic handler for testing panics + //try test__negvti2(-170141183460469231731687303715884105728, -5); // tested with return -5; and panic + try test__negvti2(-170141183460469231731687303715884105727, 170141183460469231731687303715884105727); + try test__negvti2(-170141183460469231731687303715884105726, 170141183460469231731687303715884105726); + try test__negvti2(-170141183460469231731687303715884105725, 170141183460469231731687303715884105725); + try test__negvti2(-170141183460469231731687303715884105724, 170141183460469231731687303715884105724); + try test__negvti2(-42, 42); + try test__negvti2(-7, 7); + try test__negvti2(-1, 1); + try test__negvti2(0, 0); + try test__negvti2(1, -1); + try test__negvti2(7, -7); + try test__negvti2(42, -42); + try test__negvti2(170141183460469231731687303715884105724, -170141183460469231731687303715884105724); + try test__negvti2(170141183460469231731687303715884105725, -170141183460469231731687303715884105725); + try test__negvti2(170141183460469231731687303715884105726, -170141183460469231731687303715884105726); + try test__negvti2(170141183460469231731687303715884105727, -170141183460469231731687303715884105727); +}