Skip to content

Commit

Permalink
compiler_rt: add __absvsi2, __absvdi2, _$absvti2
Browse files Browse the repository at this point in the history
- abs can only overflow, if a == MIN
- comparing the sign change from wrapping addition is branchless
- tests: MIN, MIN+1,..MIN+3, -42, -7, 0, 7..

See ziglang#1290
  • Loading branch information
matu3ba committed Dec 23, 2021
1 parent 303bad9 commit 9c7105f
Show file tree
Hide file tree
Showing 6 changed files with 133 additions and 1 deletion.
1 change: 1 addition & 0 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -444,6 +444,7 @@ set(ZIG_STAGE2_SOURCES
"${CMAKE_SOURCE_DIR}/lib/std/rand.zig"
"${CMAKE_SOURCE_DIR}/lib/std/sort.zig"
"${CMAKE_SOURCE_DIR}/lib/std/special/compiler_rt.zig"
"${CMAKE_SOURCE_DIR}/lib/std/special/compiler_rt/absv.zig"
"${CMAKE_SOURCE_DIR}/lib/std/special/compiler_rt/addXf3.zig"
"${CMAKE_SOURCE_DIR}/lib/std/special/compiler_rt/atomics.zig"
"${CMAKE_SOURCE_DIR}/lib/std/special/compiler_rt/bswap.zig"
Expand Down
8 changes: 7 additions & 1 deletion lib/std/special/compiler_rt.zig
Original file line number Diff line number Diff line change
Expand Up @@ -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

Expand Down
35 changes: 35 additions & 0 deletions lib/std/special/compiler_rt/absv.zig
Original file line number Diff line number Diff line change
@@ -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");
}
30 changes: 30 additions & 0 deletions lib/std/special/compiler_rt/absvdi2_test.zig
Original file line number Diff line number Diff line change
@@ -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);
}
30 changes: 30 additions & 0 deletions lib/std/special/compiler_rt/absvsi2_test.zig
Original file line number Diff line number Diff line change
@@ -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);
}
30 changes: 30 additions & 0 deletions lib/std/special/compiler_rt/absvti2_test.zig
Original file line number Diff line number Diff line change
@@ -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);
}

0 comments on commit 9c7105f

Please sign in to comment.