authorgravatar for jan.hafer@rwth-aachen.deJan Philipp Hafer <jan.hafer@rwth-aachen.de> 2021-12-12 00:27:41+01:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2021-12-14 14:16:24-08:00
logeb1e75b2b8e788a3d5b590a0061cb736f8183fd3
tree83ce800e91bf4f7ad9cad02cfb84bd528416133e
parent93c6ab4952cb5bed06cb77725893ebf8e12240bd

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

9 files changed, 166 insertions(+), 101 deletions(-)

CMakeLists.txt+1-2
...@@ -494,8 +494,7 @@ set(ZIG_STAGE2_SOURCES...@@ -494,8 +494,7 @@ set(ZIG_STAGE2_SOURCES
494 "${CMAKE_SOURCE_DIR}/lib/std/special/compiler_rt/modti3.zig"494 "${CMAKE_SOURCE_DIR}/lib/std/special/compiler_rt/modti3.zig"
495 "${CMAKE_SOURCE_DIR}/lib/std/special/compiler_rt/mulXf3.zig"495 "${CMAKE_SOURCE_DIR}/lib/std/special/compiler_rt/mulXf3.zig"
496 "${CMAKE_SOURCE_DIR}/lib/std/special/compiler_rt/muldi3.zig"496 "${CMAKE_SOURCE_DIR}/lib/std/special/compiler_rt/muldi3.zig"
497 "${CMAKE_SOURCE_DIR}/lib/std/special/compiler_rt/mulodi4.zig"497 "${CMAKE_SOURCE_DIR}/lib/std/special/compiler_rt/mulo.zig"
498 "${CMAKE_SOURCE_DIR}/lib/std/special/compiler_rt/muloti4.zig"
499 "${CMAKE_SOURCE_DIR}/lib/std/special/compiler_rt/multi3.zig"498 "${CMAKE_SOURCE_DIR}/lib/std/special/compiler_rt/multi3.zig"
500 "${CMAKE_SOURCE_DIR}/lib/std/special/compiler_rt/negXf2.zig"499 "${CMAKE_SOURCE_DIR}/lib/std/special/compiler_rt/negXf2.zig"
501 "${CMAKE_SOURCE_DIR}/lib/std/special/compiler_rt/negXi2.zig"500 "${CMAKE_SOURCE_DIR}/lib/std/special/compiler_rt/negXi2.zig"
lib/std/special/compiler_rt.zig+4-2
...@@ -77,9 +77,11 @@ comptime {...@@ -77,9 +77,11 @@ comptime {
77 @export(__extendhfsf2, .{ .name = "__gnu_h2f_ieee", .linkage = linkage });77 @export(__extendhfsf2, .{ .name = "__gnu_h2f_ieee", .linkage = linkage });
7878
79 // Integral arithmetic which returns if overflow79 // Integral arithmetic which returns if overflow
80 const __mulodi4 = @import("compiler_rt/mulodi4.zig").__mulodi4;80 const __mulosi4 = @import("compiler_rt/mulo.zig").__mulosi4;
81 @export(__mulosi4, .{ .name = "__mulosi4", .linkage = linkage });
82 const __mulodi4 = @import("compiler_rt/mulo.zig").__mulodi4;
81 @export(__mulodi4, .{ .name = "__mulodi4", .linkage = linkage });83 @export(__mulodi4, .{ .name = "__mulodi4", .linkage = linkage });
82 const __muloti4 = @import("compiler_rt/muloti4.zig").__muloti4;84 const __muloti4 = @import("compiler_rt/mulo.zig").__muloti4;
83 @export(__muloti4, .{ .name = "__muloti4", .linkage = linkage });85 @export(__muloti4, .{ .name = "__muloti4", .linkage = linkage });
84 }86 }
8587
lib/std/special/compiler_rt/bswap.zig-1
...@@ -6,7 +6,6 @@ const builtin = @import("builtin");...@@ -6,7 +6,6 @@ const builtin = @import("builtin");
6// ie for u326// ie for u32
7// DE AD BE EF <- little|big endian7// DE AD BE EF <- little|big endian
8// FE BE AD DE <- big|little endian8// FE BE AD DE <- big|little endian
9// ie for u32
10// ff 00 00 00 >> 3*8 (leftmost byte)9// ff 00 00 00 >> 3*8 (leftmost byte)
11// 00 ff 00 00 >> 1*8 (2nd left byte)10// 00 ff 00 00 >> 1*8 (2nd left byte)
12// 00 00 ff 00 << 1*8 (2n right byte)11// 00 00 ff 00 << 1*8 (2n right byte)
lib/std/special/compiler_rt/mulo.zig created+69
...@@ -0,0 +1,69 @@
1const builtin = @import("builtin");
2
3// mulo - multiplication overflow
4// - muloXi4_generic for unoptimized version
5
6// return a*b.
7// return if a*b overflows => 1 else => 0
8// see https://stackoverflow.com/a/26320664 for possible implementations
9
10fn muloXi4_generic(comptime ST: type) fn (a: ST, b: ST, overflow: *c_int) callconv(.C) ST {
11 return struct {
12 fn f(a: ST, b: ST, overflow: *c_int) callconv(.C) ST {
13 @setRuntimeSafety(builtin.is_test);
14 const BSIZE = @bitSizeOf(ST);
15 comptime var UT = switch (ST) {
16 i32 => u32,
17 i64 => u64,
18 i128 => u128,
19 else => unreachable,
20 };
21 const min = @bitCast(ST, @as(UT, 1 << (BSIZE - 1)));
22 const max = ~min;
23 overflow.* = 0;
24 const result = a *% b;
25
26 // edge cases
27 if (a == min) {
28 if (b != 0 and b != 1) overflow.* = 1;
29 return result;
30 }
31 if (b == min) {
32 if (a != 0 and a != 1) overflow.* = 1;
33 return result;
34 }
35
36 // take sign of x sx
37 const sa = a >> (BSIZE - 1);
38 const sb = b >> (BSIZE - 1);
39 // take absolute value of a and b via
40 // abs(x) = (x^sx)) - sx
41 const abs_a = (a ^ sa) -% sa;
42 const abs_b = (b ^ sb) -% sb;
43
44 // unitary magnitude, cannot have overflow
45 if (abs_a < 2 or abs_b < 2) return result;
46
47 // compare the signs of operands
48 if ((a ^ b) >> (BSIZE - 1) != 0) {
49 if (abs_a > @divTrunc(max, abs_b)) overflow.* = 1;
50 } else {
51 if (abs_a > @divTrunc(min, -abs_b)) overflow.* = 1;
52 }
53
54 return result;
55 }
56 }.f;
57}
58
59pub const __mulosi4 = muloXi4_generic(i32);
60
61pub const __mulodi4 = muloXi4_generic(i64);
62
63pub const __muloti4 = muloXi4_generic(i128);
64
65test {
66 _ = @import("mulosi4_test.zig");
67 _ = @import("mulodi4_test.zig");
68 _ = @import("muloti4_test.zig");
69}
lib/std/special/compiler_rt/mulodi4.zig deleted-42
...@@ -1,42 +0,0 @@
1const builtin = @import("builtin");
2const compiler_rt = @import("../compiler_rt.zig");
3
4pub fn __mulodi4(a: i64, b: i64, overflow: *c_int) callconv(.C) i64 {
5 @setRuntimeSafety(builtin.is_test);
6
7 const min = @bitCast(i64, @as(u64, 1 << (64 - 1)));
8 const max = ~min;
9
10 overflow.* = 0;
11 const result = a *% b;
12
13 // Edge cases
14 if (a == min) {
15 if (b != 0 and b != 1) overflow.* = 1;
16 return result;
17 }
18 if (b == min) {
19 if (a != 0 and a != 1) overflow.* = 1;
20 return result;
21 }
22
23 // Take absolute value of a and b via abs(x) = (x^(x >> 63)) - (x >> 63).
24 const abs_a = (a ^ (a >> 63)) -% (a >> 63);
25 const abs_b = (b ^ (b >> 63)) -% (b >> 63);
26
27 // Unitary magnitude, cannot have overflow
28 if (abs_a < 2 or abs_b < 2) return result;
29
30 // Compare the signs of the operands
31 if ((a ^ b) >> 63 != 0) {
32 if (abs_a > @divTrunc(max, abs_b)) overflow.* = 1;
33 } else {
34 if (abs_a > @divTrunc(min, -abs_b)) overflow.* = 1;
35 }
36
37 return result;
38}
39
40test {
41 _ = @import("mulodi4_test.zig");
42}
lib/std/special/compiler_rt/mulodi4_test.zig+4-2
...@@ -1,9 +1,11 @@...@@ -1,9 +1,11 @@
1const __mulodi4 = @import("mulodi4.zig").__mulodi4;1const mulo = @import("mulo.zig");
2const testing = @import("std").testing;2const testing = @import("std").testing;
33
4// ported from https://github.com/llvm-mirror/compiler-rt/tree/release_80/test/builtins/Unit
5
4fn test__mulodi4(a: i64, b: i64, expected: i64, expected_overflow: c_int) !void {6fn test__mulodi4(a: i64, b: i64, expected: i64, expected_overflow: c_int) !void {
5 var overflow: c_int = undefined;7 var overflow: c_int = undefined;
6 const x = __mulodi4(a, b, &overflow);8 const x = mulo.__mulodi4(a, b, &overflow);
7 try testing.expect(overflow == expected_overflow and (expected_overflow != 0 or x == expected));9 try testing.expect(overflow == expected_overflow and (expected_overflow != 0 or x == expected));
8}10}
911
lib/std/special/compiler_rt/mulosi4_test.zig created+72
...@@ -0,0 +1,72 @@
1const mulo = @import("mulo.zig");
2const testing = @import("std").testing;
3
4// ported from https://github.com/llvm-mirror/compiler-rt/tree/release_80/test/builtins/Unit
5
6fn test__mulosi4(a: i32, b: i32, expected: i32, expected_overflow: c_int) !void {
7 var overflow: c_int = undefined;
8 const x = mulo.__mulosi4(a, b, &overflow);
9 try testing.expect(overflow == expected_overflow and (expected_overflow != 0 or x == expected));
10}
11
12test "mulosi4" {
13 try test__mulosi4(0, 0, 0, 0);
14 try test__mulosi4(0, 1, 0, 0);
15 try test__mulosi4(1, 0, 0, 0);
16 try test__mulosi4(0, 10, 0, 0);
17 try test__mulosi4(10, 0, 0, 0);
18 try test__mulosi4(0, 0x1234567, 0, 0);
19 try test__mulosi4(0x1234567, 0, 0, 0);
20
21 try test__mulosi4(0, -1, 0, 0);
22 try test__mulosi4(-1, 0, 0, 0);
23 try test__mulosi4(0, -10, 0, 0);
24 try test__mulosi4(-10, 0, 0, 0);
25 try test__mulosi4(0, -0x1234567, 0, 0);
26 try test__mulosi4(-0x1234567, 0, 0, 0);
27
28 try test__mulosi4(1, 1, 1, 0);
29 try test__mulosi4(1, 10, 10, 0);
30 try test__mulosi4(10, 1, 10, 0);
31 try test__mulosi4(1, 0x1234567, 0x1234567, 0);
32 try test__mulosi4(0x1234567, 1, 0x1234567, 0);
33
34 try test__mulosi4(1, -1, -1, 0);
35 try test__mulosi4(1, -10, -10, 0);
36 try test__mulosi4(-10, 1, -10, 0);
37 try test__mulosi4(1, -0x1234567, -0x1234567, 0);
38 try test__mulosi4(-0x1234567, 1, -0x1234567, 0);
39
40 try test__mulosi4(0x7FFFFFFF, -2, @bitCast(i32, @as(u32, 0x80000001)), 1);
41 try test__mulosi4(-2, 0x7FFFFFFF, @bitCast(i32, @as(u32, 0x80000001)), 1);
42 try test__mulosi4(0x7FFFFFFF, -1, @bitCast(i32, @as(u32, 0x80000001)), 0);
43 try test__mulosi4(-1, 0x7FFFFFFF, @bitCast(i32, @as(u32, 0x80000001)), 0);
44 try test__mulosi4(0x7FFFFFFF, 0, 0, 0);
45 try test__mulosi4(0, 0x7FFFFFFF, 0, 0);
46 try test__mulosi4(0x7FFFFFFF, 1, 0x7FFFFFFF, 0);
47 try test__mulosi4(1, 0x7FFFFFFF, 0x7FFFFFFF, 0);
48 try test__mulosi4(0x7FFFFFFF, 2, @bitCast(i32, @as(u32, 0x80000001)), 1);
49 try test__mulosi4(2, 0x7FFFFFFF, @bitCast(i32, @as(u32, 0x80000001)), 1);
50
51 try test__mulosi4(@bitCast(i32, @as(u32, 0x80000000)), -2, @bitCast(i32, @as(u32, 0x80000000)), 1);
52 try test__mulosi4(-2, @bitCast(i32, @as(u32, 0x80000000)), @bitCast(i32, @as(u32, 0x80000000)), 1);
53 try test__mulosi4(@bitCast(i32, @as(u32, 0x80000000)), -1, @bitCast(i32, @as(u32, 0x80000000)), 1);
54 try test__mulosi4(-1, @bitCast(i32, @as(u32, 0x80000000)), @bitCast(i32, @as(u32, 0x80000000)), 1);
55 try test__mulosi4(@bitCast(i32, @as(u32, 0x80000000)), 0, 0, 0);
56 try test__mulosi4(0, @bitCast(i32, @as(u32, 0x80000000)), 0, 0);
57 try test__mulosi4(@bitCast(i32, @as(u32, 0x80000000)), 1, @bitCast(i32, @as(u32, 0x80000000)), 0);
58 try test__mulosi4(1, @bitCast(i32, @as(u32, 0x80000000)), @bitCast(i32, @as(u32, 0x80000000)), 0);
59 try test__mulosi4(@bitCast(i32, @as(u32, 0x80000000)), 2, @bitCast(i32, @as(u32, 0x80000000)), 1);
60 try test__mulosi4(2, @bitCast(i32, @as(u32, 0x80000000)), @bitCast(i32, @as(u32, 0x80000000)), 1);
61
62 try test__mulosi4(@bitCast(i32, @as(u32, 0x80000001)), -2, @bitCast(i32, @as(u32, 0x80000001)), 1);
63 try test__mulosi4(-2, @bitCast(i32, @as(u32, 0x80000001)), @bitCast(i32, @as(u32, 0x80000001)), 1);
64 try test__mulosi4(@bitCast(i32, @as(u32, 0x80000001)), -1, 0x7FFFFFFF, 0);
65 try test__mulosi4(-1, @bitCast(i32, @as(u32, 0x80000001)), 0x7FFFFFFF, 0);
66 try test__mulosi4(@bitCast(i32, @as(u32, 0x80000001)), 0, 0, 0);
67 try test__mulosi4(0, @bitCast(i32, @as(u32, 0x80000001)), 0, 0);
68 try test__mulosi4(@bitCast(i32, @as(u32, 0x80000001)), 1, @bitCast(i32, @as(u32, 0x80000001)), 0);
69 try test__mulosi4(1, @bitCast(i32, @as(u32, 0x80000001)), @bitCast(i32, @as(u32, 0x80000001)), 0);
70 try test__mulosi4(@bitCast(i32, @as(u32, 0x80000001)), 2, @bitCast(i32, @as(u32, 0x80000000)), 1);
71 try test__mulosi4(2, @bitCast(i32, @as(u32, 0x80000001)), @bitCast(i32, @as(u32, 0x80000000)), 1);
72}
lib/std/special/compiler_rt/muloti4.zig deleted-49
...@@ -1,49 +0,0 @@
1const builtin = @import("builtin");
2const compiler_rt = @import("../compiler_rt.zig");
3
4pub fn __muloti4(a: i128, b: i128, overflow: *c_int) callconv(.C) i128 {
5 @setRuntimeSafety(builtin.is_test);
6
7 const min = @bitCast(i128, @as(u128, 1 << (128 - 1)));
8 const max = ~min;
9 overflow.* = 0;
10
11 const r = a *% b;
12 if (a == min) {
13 if (b != 0 and b != 1) {
14 overflow.* = 1;
15 }
16 return r;
17 }
18 if (b == min) {
19 if (a != 0 and a != 1) {
20 overflow.* = 1;
21 }
22 return r;
23 }
24
25 const sa = a >> (128 - 1);
26 const abs_a = (a ^ sa) -% sa;
27 const sb = b >> (128 - 1);
28 const abs_b = (b ^ sb) -% sb;
29
30 if (abs_a < 2 or abs_b < 2) {
31 return r;
32 }
33
34 if (sa == sb) {
35 if (abs_a > @divTrunc(max, abs_b)) {
36 overflow.* = 1;
37 }
38 } else {
39 if (abs_a > @divTrunc(min, -abs_b)) {
40 overflow.* = 1;
41 }
42 }
43
44 return r;
45}
46
47test {
48 _ = @import("muloti4_test.zig");
49}
lib/std/special/compiler_rt/muloti4_test.zig+16-3
...@@ -1,9 +1,11 @@...@@ -1,9 +1,11 @@
1const __muloti4 = @import("muloti4.zig").__muloti4;1const mulo = @import("mulo.zig");
2const testing = @import("std").testing;2const testing = @import("std").testing;
33
4// ported from https://github.com/llvm-mirror/compiler-rt/tree/release_80/test/builtins/Unit
5
4fn test__muloti4(a: i128, b: i128, expected: i128, expected_overflow: c_int) !void {6fn test__muloti4(a: i128, b: i128, expected: i128, expected_overflow: c_int) !void {
5 var overflow: c_int = undefined;7 var overflow: c_int = undefined;
6 const x = __muloti4(a, b, &overflow);8 const x = mulo.__muloti4(a, b, &overflow);
7 try testing.expect(overflow == expected_overflow and (expected_overflow != 0 or x == expected));9 try testing.expect(overflow == expected_overflow and (expected_overflow != 0 or x == expected));
8}10}
911
...@@ -13,7 +15,6 @@ test "muloti4" {...@@ -13,7 +15,6 @@ test "muloti4" {
13 try test__muloti4(1, 0, 0, 0);15 try test__muloti4(1, 0, 0, 0);
14 try test__muloti4(0, 10, 0, 0);16 try test__muloti4(0, 10, 0, 0);
15 try test__muloti4(10, 0, 0, 0);17 try test__muloti4(10, 0, 0, 0);
16
17 try test__muloti4(0, 81985529216486895, 0, 0);18 try test__muloti4(0, 81985529216486895, 0, 0);
18 try test__muloti4(81985529216486895, 0, 0, 0);19 try test__muloti4(81985529216486895, 0, 0, 0);
1920
...@@ -24,6 +25,18 @@ test "muloti4" {...@@ -24,6 +25,18 @@ test "muloti4" {
24 try test__muloti4(0, -81985529216486895, 0, 0);25 try test__muloti4(0, -81985529216486895, 0, 0);
25 try test__muloti4(-81985529216486895, 0, 0, 0);26 try test__muloti4(-81985529216486895, 0, 0, 0);
2627
28 try test__muloti4(1, 1, 1, 0);
29 try test__muloti4(1, 10, 10, 0);
30 try test__muloti4(10, 1, 10, 0);
31 try test__muloti4(1, 81985529216486895, 81985529216486895, 0);
32 try test__muloti4(81985529216486895, 1, 81985529216486895, 0);
33
34 try test__muloti4(1, -1, -1, 0);
35 try test__muloti4(1, -10, -10, 0);
36 try test__muloti4(-10, 1, -10, 0);
37 try test__muloti4(1, -81985529216486895, -81985529216486895, 0);
38 try test__muloti4(-81985529216486895, 1, -81985529216486895, 0);
39
27 try test__muloti4(3037000499, 3037000499, 9223372030926249001, 0);40 try test__muloti4(3037000499, 3037000499, 9223372030926249001, 0);
28 try test__muloti4(-3037000499, 3037000499, -9223372030926249001, 0);41 try test__muloti4(-3037000499, 3037000499, -9223372030926249001, 0);
29 try test__muloti4(3037000499, -3037000499, -9223372030926249001, 0);42 try test__muloti4(3037000499, -3037000499, -9223372030926249001, 0);