compiler_rt: refactor __mulodi2 and __muloti2 to get __mulosi2
- use comptime instead of 2 identical implementations - tests: port missing tests and link to archived llvm-mirror release 80 See #1290
This commit is contained in:
parent
93c6ab4952
commit
eb1e75b2b8
|
@ -494,8 +494,7 @@ set(ZIG_STAGE2_SOURCES
|
|||
"${CMAKE_SOURCE_DIR}/lib/std/special/compiler_rt/modti3.zig"
|
||||
"${CMAKE_SOURCE_DIR}/lib/std/special/compiler_rt/mulXf3.zig"
|
||||
"${CMAKE_SOURCE_DIR}/lib/std/special/compiler_rt/muldi3.zig"
|
||||
"${CMAKE_SOURCE_DIR}/lib/std/special/compiler_rt/mulodi4.zig"
|
||||
"${CMAKE_SOURCE_DIR}/lib/std/special/compiler_rt/muloti4.zig"
|
||||
"${CMAKE_SOURCE_DIR}/lib/std/special/compiler_rt/mulo.zig"
|
||||
"${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"
|
||||
|
|
|
@ -77,9 +77,11 @@ comptime {
|
|||
@export(__extendhfsf2, .{ .name = "__gnu_h2f_ieee", .linkage = linkage });
|
||||
|
||||
// Integral arithmetic which returns if overflow
|
||||
const __mulodi4 = @import("compiler_rt/mulodi4.zig").__mulodi4;
|
||||
const __mulosi4 = @import("compiler_rt/mulo.zig").__mulosi4;
|
||||
@export(__mulosi4, .{ .name = "__mulosi4", .linkage = linkage });
|
||||
const __mulodi4 = @import("compiler_rt/mulo.zig").__mulodi4;
|
||||
@export(__mulodi4, .{ .name = "__mulodi4", .linkage = linkage });
|
||||
const __muloti4 = @import("compiler_rt/muloti4.zig").__muloti4;
|
||||
const __muloti4 = @import("compiler_rt/mulo.zig").__muloti4;
|
||||
@export(__muloti4, .{ .name = "__muloti4", .linkage = linkage });
|
||||
}
|
||||
|
||||
|
|
|
@ -6,7 +6,6 @@ const builtin = @import("builtin");
|
|||
// ie for u32
|
||||
// DE AD BE EF <- little|big endian
|
||||
// FE BE AD DE <- big|little endian
|
||||
// ie for u32
|
||||
// ff 00 00 00 >> 3*8 (leftmost byte)
|
||||
// 00 ff 00 00 >> 1*8 (2nd left byte)
|
||||
// 00 00 ff 00 << 1*8 (2n right byte)
|
||||
|
|
69
lib/std/special/compiler_rt/mulo.zig
Normal file
69
lib/std/special/compiler_rt/mulo.zig
Normal file
|
@ -0,0 +1,69 @@
|
|||
const builtin = @import("builtin");
|
||||
|
||||
// mulo - multiplication overflow
|
||||
// - muloXi4_generic for unoptimized version
|
||||
|
||||
// return a*b.
|
||||
// return if a*b overflows => 1 else => 0
|
||||
// see https://stackoverflow.com/a/26320664 for possible implementations
|
||||
|
||||
fn muloXi4_generic(comptime ST: type) fn (a: ST, b: ST, overflow: *c_int) callconv(.C) ST {
|
||||
return struct {
|
||||
fn f(a: ST, b: ST, overflow: *c_int) callconv(.C) ST {
|
||||
@setRuntimeSafety(builtin.is_test);
|
||||
const BSIZE = @bitSizeOf(ST);
|
||||
comptime var UT = switch (ST) {
|
||||
i32 => u32,
|
||||
i64 => u64,
|
||||
i128 => u128,
|
||||
else => unreachable,
|
||||
};
|
||||
const min = @bitCast(ST, @as(UT, 1 << (BSIZE - 1)));
|
||||
const max = ~min;
|
||||
overflow.* = 0;
|
||||
const result = a *% b;
|
||||
|
||||
// edge cases
|
||||
if (a == min) {
|
||||
if (b != 0 and b != 1) overflow.* = 1;
|
||||
return result;
|
||||
}
|
||||
if (b == min) {
|
||||
if (a != 0 and a != 1) overflow.* = 1;
|
||||
return result;
|
||||
}
|
||||
|
||||
// take sign of x sx
|
||||
const sa = a >> (BSIZE - 1);
|
||||
const sb = b >> (BSIZE - 1);
|
||||
// take absolute value of a and b via
|
||||
// abs(x) = (x^sx)) - sx
|
||||
const abs_a = (a ^ sa) -% sa;
|
||||
const abs_b = (b ^ sb) -% sb;
|
||||
|
||||
// unitary magnitude, cannot have overflow
|
||||
if (abs_a < 2 or abs_b < 2) return result;
|
||||
|
||||
// compare the signs of operands
|
||||
if ((a ^ b) >> (BSIZE - 1) != 0) {
|
||||
if (abs_a > @divTrunc(max, abs_b)) overflow.* = 1;
|
||||
} else {
|
||||
if (abs_a > @divTrunc(min, -abs_b)) overflow.* = 1;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
}.f;
|
||||
}
|
||||
|
||||
pub const __mulosi4 = muloXi4_generic(i32);
|
||||
|
||||
pub const __mulodi4 = muloXi4_generic(i64);
|
||||
|
||||
pub const __muloti4 = muloXi4_generic(i128);
|
||||
|
||||
test {
|
||||
_ = @import("mulosi4_test.zig");
|
||||
_ = @import("mulodi4_test.zig");
|
||||
_ = @import("muloti4_test.zig");
|
||||
}
|
|
@ -1,42 +0,0 @@
|
|||
const builtin = @import("builtin");
|
||||
const compiler_rt = @import("../compiler_rt.zig");
|
||||
|
||||
pub fn __mulodi4(a: i64, b: i64, overflow: *c_int) callconv(.C) i64 {
|
||||
@setRuntimeSafety(builtin.is_test);
|
||||
|
||||
const min = @bitCast(i64, @as(u64, 1 << (64 - 1)));
|
||||
const max = ~min;
|
||||
|
||||
overflow.* = 0;
|
||||
const result = a *% b;
|
||||
|
||||
// Edge cases
|
||||
if (a == min) {
|
||||
if (b != 0 and b != 1) overflow.* = 1;
|
||||
return result;
|
||||
}
|
||||
if (b == min) {
|
||||
if (a != 0 and a != 1) overflow.* = 1;
|
||||
return result;
|
||||
}
|
||||
|
||||
// Take absolute value of a and b via abs(x) = (x^(x >> 63)) - (x >> 63).
|
||||
const abs_a = (a ^ (a >> 63)) -% (a >> 63);
|
||||
const abs_b = (b ^ (b >> 63)) -% (b >> 63);
|
||||
|
||||
// Unitary magnitude, cannot have overflow
|
||||
if (abs_a < 2 or abs_b < 2) return result;
|
||||
|
||||
// Compare the signs of the operands
|
||||
if ((a ^ b) >> 63 != 0) {
|
||||
if (abs_a > @divTrunc(max, abs_b)) overflow.* = 1;
|
||||
} else {
|
||||
if (abs_a > @divTrunc(min, -abs_b)) overflow.* = 1;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
test {
|
||||
_ = @import("mulodi4_test.zig");
|
||||
}
|
|
@ -1,9 +1,11 @@
|
|||
const __mulodi4 = @import("mulodi4.zig").__mulodi4;
|
||||
const mulo = @import("mulo.zig");
|
||||
const testing = @import("std").testing;
|
||||
|
||||
// ported from https://github.com/llvm-mirror/compiler-rt/tree/release_80/test/builtins/Unit
|
||||
|
||||
fn test__mulodi4(a: i64, b: i64, expected: i64, expected_overflow: c_int) !void {
|
||||
var overflow: c_int = undefined;
|
||||
const x = __mulodi4(a, b, &overflow);
|
||||
const x = mulo.__mulodi4(a, b, &overflow);
|
||||
try testing.expect(overflow == expected_overflow and (expected_overflow != 0 or x == expected));
|
||||
}
|
||||
|
||||
|
|
72
lib/std/special/compiler_rt/mulosi4_test.zig
Normal file
72
lib/std/special/compiler_rt/mulosi4_test.zig
Normal file
|
@ -0,0 +1,72 @@
|
|||
const mulo = @import("mulo.zig");
|
||||
const testing = @import("std").testing;
|
||||
|
||||
// ported from https://github.com/llvm-mirror/compiler-rt/tree/release_80/test/builtins/Unit
|
||||
|
||||
fn test__mulosi4(a: i32, b: i32, expected: i32, expected_overflow: c_int) !void {
|
||||
var overflow: c_int = undefined;
|
||||
const x = mulo.__mulosi4(a, b, &overflow);
|
||||
try testing.expect(overflow == expected_overflow and (expected_overflow != 0 or x == expected));
|
||||
}
|
||||
|
||||
test "mulosi4" {
|
||||
try test__mulosi4(0, 0, 0, 0);
|
||||
try test__mulosi4(0, 1, 0, 0);
|
||||
try test__mulosi4(1, 0, 0, 0);
|
||||
try test__mulosi4(0, 10, 0, 0);
|
||||
try test__mulosi4(10, 0, 0, 0);
|
||||
try test__mulosi4(0, 0x1234567, 0, 0);
|
||||
try test__mulosi4(0x1234567, 0, 0, 0);
|
||||
|
||||
try test__mulosi4(0, -1, 0, 0);
|
||||
try test__mulosi4(-1, 0, 0, 0);
|
||||
try test__mulosi4(0, -10, 0, 0);
|
||||
try test__mulosi4(-10, 0, 0, 0);
|
||||
try test__mulosi4(0, -0x1234567, 0, 0);
|
||||
try test__mulosi4(-0x1234567, 0, 0, 0);
|
||||
|
||||
try test__mulosi4(1, 1, 1, 0);
|
||||
try test__mulosi4(1, 10, 10, 0);
|
||||
try test__mulosi4(10, 1, 10, 0);
|
||||
try test__mulosi4(1, 0x1234567, 0x1234567, 0);
|
||||
try test__mulosi4(0x1234567, 1, 0x1234567, 0);
|
||||
|
||||
try test__mulosi4(1, -1, -1, 0);
|
||||
try test__mulosi4(1, -10, -10, 0);
|
||||
try test__mulosi4(-10, 1, -10, 0);
|
||||
try test__mulosi4(1, -0x1234567, -0x1234567, 0);
|
||||
try test__mulosi4(-0x1234567, 1, -0x1234567, 0);
|
||||
|
||||
try test__mulosi4(0x7FFFFFFF, -2, @bitCast(i32, @as(u32, 0x80000001)), 1);
|
||||
try test__mulosi4(-2, 0x7FFFFFFF, @bitCast(i32, @as(u32, 0x80000001)), 1);
|
||||
try test__mulosi4(0x7FFFFFFF, -1, @bitCast(i32, @as(u32, 0x80000001)), 0);
|
||||
try test__mulosi4(-1, 0x7FFFFFFF, @bitCast(i32, @as(u32, 0x80000001)), 0);
|
||||
try test__mulosi4(0x7FFFFFFF, 0, 0, 0);
|
||||
try test__mulosi4(0, 0x7FFFFFFF, 0, 0);
|
||||
try test__mulosi4(0x7FFFFFFF, 1, 0x7FFFFFFF, 0);
|
||||
try test__mulosi4(1, 0x7FFFFFFF, 0x7FFFFFFF, 0);
|
||||
try test__mulosi4(0x7FFFFFFF, 2, @bitCast(i32, @as(u32, 0x80000001)), 1);
|
||||
try test__mulosi4(2, 0x7FFFFFFF, @bitCast(i32, @as(u32, 0x80000001)), 1);
|
||||
|
||||
try test__mulosi4(@bitCast(i32, @as(u32, 0x80000000)), -2, @bitCast(i32, @as(u32, 0x80000000)), 1);
|
||||
try test__mulosi4(-2, @bitCast(i32, @as(u32, 0x80000000)), @bitCast(i32, @as(u32, 0x80000000)), 1);
|
||||
try test__mulosi4(@bitCast(i32, @as(u32, 0x80000000)), -1, @bitCast(i32, @as(u32, 0x80000000)), 1);
|
||||
try test__mulosi4(-1, @bitCast(i32, @as(u32, 0x80000000)), @bitCast(i32, @as(u32, 0x80000000)), 1);
|
||||
try test__mulosi4(@bitCast(i32, @as(u32, 0x80000000)), 0, 0, 0);
|
||||
try test__mulosi4(0, @bitCast(i32, @as(u32, 0x80000000)), 0, 0);
|
||||
try test__mulosi4(@bitCast(i32, @as(u32, 0x80000000)), 1, @bitCast(i32, @as(u32, 0x80000000)), 0);
|
||||
try test__mulosi4(1, @bitCast(i32, @as(u32, 0x80000000)), @bitCast(i32, @as(u32, 0x80000000)), 0);
|
||||
try test__mulosi4(@bitCast(i32, @as(u32, 0x80000000)), 2, @bitCast(i32, @as(u32, 0x80000000)), 1);
|
||||
try test__mulosi4(2, @bitCast(i32, @as(u32, 0x80000000)), @bitCast(i32, @as(u32, 0x80000000)), 1);
|
||||
|
||||
try test__mulosi4(@bitCast(i32, @as(u32, 0x80000001)), -2, @bitCast(i32, @as(u32, 0x80000001)), 1);
|
||||
try test__mulosi4(-2, @bitCast(i32, @as(u32, 0x80000001)), @bitCast(i32, @as(u32, 0x80000001)), 1);
|
||||
try test__mulosi4(@bitCast(i32, @as(u32, 0x80000001)), -1, 0x7FFFFFFF, 0);
|
||||
try test__mulosi4(-1, @bitCast(i32, @as(u32, 0x80000001)), 0x7FFFFFFF, 0);
|
||||
try test__mulosi4(@bitCast(i32, @as(u32, 0x80000001)), 0, 0, 0);
|
||||
try test__mulosi4(0, @bitCast(i32, @as(u32, 0x80000001)), 0, 0);
|
||||
try test__mulosi4(@bitCast(i32, @as(u32, 0x80000001)), 1, @bitCast(i32, @as(u32, 0x80000001)), 0);
|
||||
try test__mulosi4(1, @bitCast(i32, @as(u32, 0x80000001)), @bitCast(i32, @as(u32, 0x80000001)), 0);
|
||||
try test__mulosi4(@bitCast(i32, @as(u32, 0x80000001)), 2, @bitCast(i32, @as(u32, 0x80000000)), 1);
|
||||
try test__mulosi4(2, @bitCast(i32, @as(u32, 0x80000001)), @bitCast(i32, @as(u32, 0x80000000)), 1);
|
||||
}
|
|
@ -1,49 +0,0 @@
|
|||
const builtin = @import("builtin");
|
||||
const compiler_rt = @import("../compiler_rt.zig");
|
||||
|
||||
pub fn __muloti4(a: i128, b: i128, overflow: *c_int) callconv(.C) i128 {
|
||||
@setRuntimeSafety(builtin.is_test);
|
||||
|
||||
const min = @bitCast(i128, @as(u128, 1 << (128 - 1)));
|
||||
const max = ~min;
|
||||
overflow.* = 0;
|
||||
|
||||
const r = a *% b;
|
||||
if (a == min) {
|
||||
if (b != 0 and b != 1) {
|
||||
overflow.* = 1;
|
||||
}
|
||||
return r;
|
||||
}
|
||||
if (b == min) {
|
||||
if (a != 0 and a != 1) {
|
||||
overflow.* = 1;
|
||||
}
|
||||
return r;
|
||||
}
|
||||
|
||||
const sa = a >> (128 - 1);
|
||||
const abs_a = (a ^ sa) -% sa;
|
||||
const sb = b >> (128 - 1);
|
||||
const abs_b = (b ^ sb) -% sb;
|
||||
|
||||
if (abs_a < 2 or abs_b < 2) {
|
||||
return r;
|
||||
}
|
||||
|
||||
if (sa == sb) {
|
||||
if (abs_a > @divTrunc(max, abs_b)) {
|
||||
overflow.* = 1;
|
||||
}
|
||||
} else {
|
||||
if (abs_a > @divTrunc(min, -abs_b)) {
|
||||
overflow.* = 1;
|
||||
}
|
||||
}
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
test {
|
||||
_ = @import("muloti4_test.zig");
|
||||
}
|
|
@ -1,9 +1,11 @@
|
|||
const __muloti4 = @import("muloti4.zig").__muloti4;
|
||||
const mulo = @import("mulo.zig");
|
||||
const testing = @import("std").testing;
|
||||
|
||||
// ported from https://github.com/llvm-mirror/compiler-rt/tree/release_80/test/builtins/Unit
|
||||
|
||||
fn test__muloti4(a: i128, b: i128, expected: i128, expected_overflow: c_int) !void {
|
||||
var overflow: c_int = undefined;
|
||||
const x = __muloti4(a, b, &overflow);
|
||||
const x = mulo.__muloti4(a, b, &overflow);
|
||||
try testing.expect(overflow == expected_overflow and (expected_overflow != 0 or x == expected));
|
||||
}
|
||||
|
||||
|
@ -13,7 +15,6 @@ test "muloti4" {
|
|||
try test__muloti4(1, 0, 0, 0);
|
||||
try test__muloti4(0, 10, 0, 0);
|
||||
try test__muloti4(10, 0, 0, 0);
|
||||
|
||||
try test__muloti4(0, 81985529216486895, 0, 0);
|
||||
try test__muloti4(81985529216486895, 0, 0, 0);
|
||||
|
||||
|
@ -24,6 +25,18 @@ test "muloti4" {
|
|||
try test__muloti4(0, -81985529216486895, 0, 0);
|
||||
try test__muloti4(-81985529216486895, 0, 0, 0);
|
||||
|
||||
try test__muloti4(1, 1, 1, 0);
|
||||
try test__muloti4(1, 10, 10, 0);
|
||||
try test__muloti4(10, 1, 10, 0);
|
||||
try test__muloti4(1, 81985529216486895, 81985529216486895, 0);
|
||||
try test__muloti4(81985529216486895, 1, 81985529216486895, 0);
|
||||
|
||||
try test__muloti4(1, -1, -1, 0);
|
||||
try test__muloti4(1, -10, -10, 0);
|
||||
try test__muloti4(-10, 1, -10, 0);
|
||||
try test__muloti4(1, -81985529216486895, -81985529216486895, 0);
|
||||
try test__muloti4(-81985529216486895, 1, -81985529216486895, 0);
|
||||
|
||||
try test__muloti4(3037000499, 3037000499, 9223372030926249001, 0);
|
||||
try test__muloti4(-3037000499, 3037000499, -9223372030926249001, 0);
|
||||
try test__muloti4(3037000499, -3037000499, -9223372030926249001, 0);
|
||||
|
|
Loading…
Reference in New Issue
Block a user