| author | |
| committer | |
| log | eb1e75b2b8e788a3d5b590a0061cb736f8183fd3 |
| tree | 83ce800e91bf4f7ad9cad02cfb84bd528416133e |
| parent | 93c6ab4952cb5bed06cb77725893ebf8e12240bd |
- use comptime instead of 2 identical implementations
- tests: port missing tests and link to archived llvm-mirror release 80
See #12909 files changed, 166 insertions(+), 101 deletions(-)
CMakeLists.txt+1-2| ... | ... | @@ -494,8 +494,7 @@ set(ZIG_STAGE2_SOURCES |
| 494 | 494 | "${CMAKE_SOURCE_DIR}/lib/std/special/compiler_rt/modti3.zig" |
| 495 | 495 | "${CMAKE_SOURCE_DIR}/lib/std/special/compiler_rt/mulXf3.zig" |
| 496 | 496 | "${CMAKE_SOURCE_DIR}/lib/std/special/compiler_rt/muldi3.zig" |
| 497 | "${CMAKE_SOURCE_DIR}/lib/std/special/compiler_rt/mulodi4.zig" | |
| 498 | "${CMAKE_SOURCE_DIR}/lib/std/special/compiler_rt/muloti4.zig" | |
| 497 | "${CMAKE_SOURCE_DIR}/lib/std/special/compiler_rt/mulo.zig" | |
| 499 | 498 | "${CMAKE_SOURCE_DIR}/lib/std/special/compiler_rt/multi3.zig" |
| 500 | 499 | "${CMAKE_SOURCE_DIR}/lib/std/special/compiler_rt/negXf2.zig" |
| 501 | 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 | 77 | @export(__extendhfsf2, .{ .name = "__gnu_h2f_ieee", .linkage = linkage }); |
| 78 | 78 | |
| 79 | 79 | // 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 | 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 | 85 | @export(__muloti4, .{ .name = "__muloti4", .linkage = linkage }); |
| 84 | 86 | } |
| 85 | 87 |
lib/std/special/compiler_rt/bswap.zig-1| ... | ... | @@ -6,7 +6,6 @@ const builtin = @import("builtin"); |
| 6 | 6 | // ie for u32 |
| 7 | 7 | // DE AD BE EF <- little|big endian |
| 8 | 8 | // FE BE AD DE <- big|little endian |
| 9 | // ie for u32 | |
| 10 | 9 | // ff 00 00 00 >> 3*8 (leftmost byte) |
| 11 | 10 | // 00 ff 00 00 >> 1*8 (2nd left byte) |
| 12 | 11 | // 00 00 ff 00 << 1*8 (2n right byte) |
lib/std/special/compiler_rt/mulo.zig created+69| ... | ... | @@ -0,0 +1,69 @@ |
| 1 | const 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 | ||
| 10 | fn 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 | ||
| 59 | pub const __mulosi4 = muloXi4_generic(i32); | |
| 60 | ||
| 61 | pub const __mulodi4 = muloXi4_generic(i64); | |
| 62 | ||
| 63 | pub const __muloti4 = muloXi4_generic(i128); | |
| 64 | ||
| 65 | test { | |
| 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 @@ |
| 1 | const builtin = @import("builtin"); | |
| 2 | const compiler_rt = @import("../compiler_rt.zig"); | |
| 3 | ||
| 4 | pub 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 | ||
| 40 | test { | |
| 41 | _ = @import("mulodi4_test.zig"); | |
| 42 | } |
lib/std/special/compiler_rt/mulodi4_test.zig+4-2| ... | ... | @@ -1,9 +1,11 @@ |
| 1 | const __mulodi4 = @import("mulodi4.zig").__mulodi4; | |
| 1 | const mulo = @import("mulo.zig"); | |
| 2 | 2 | const testing = @import("std").testing; |
| 3 | 3 | |
| 4 | // ported from https://github.com/llvm-mirror/compiler-rt/tree/release_80/test/builtins/Unit | |
| 5 | ||
| 4 | 6 | fn test__mulodi4(a: i64, b: i64, expected: i64, expected_overflow: c_int) !void { |
| 5 | 7 | var overflow: c_int = undefined; |
| 6 | const x = __mulodi4(a, b, &overflow); | |
| 8 | const x = mulo.__mulodi4(a, b, &overflow); | |
| 7 | 9 | try testing.expect(overflow == expected_overflow and (expected_overflow != 0 or x == expected)); |
| 8 | 10 | } |
| 9 | 11 |
lib/std/special/compiler_rt/mulosi4_test.zig created+72| ... | ... | @@ -0,0 +1,72 @@ |
| 1 | const mulo = @import("mulo.zig"); | |
| 2 | const testing = @import("std").testing; | |
| 3 | ||
| 4 | // ported from https://github.com/llvm-mirror/compiler-rt/tree/release_80/test/builtins/Unit | |
| 5 | ||
| 6 | fn 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 | ||
| 12 | test "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 @@ |
| 1 | const builtin = @import("builtin"); | |
| 2 | const compiler_rt = @import("../compiler_rt.zig"); | |
| 3 | ||
| 4 | pub 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 | ||
| 47 | test { | |
| 48 | _ = @import("muloti4_test.zig"); | |
| 49 | } |
lib/std/special/compiler_rt/muloti4_test.zig+16-3| ... | ... | @@ -1,9 +1,11 @@ |
| 1 | const __muloti4 = @import("muloti4.zig").__muloti4; | |
| 1 | const mulo = @import("mulo.zig"); | |
| 2 | 2 | const testing = @import("std").testing; |
| 3 | 3 | |
| 4 | // ported from https://github.com/llvm-mirror/compiler-rt/tree/release_80/test/builtins/Unit | |
| 5 | ||
| 4 | 6 | fn test__muloti4(a: i128, b: i128, expected: i128, expected_overflow: c_int) !void { |
| 5 | 7 | var overflow: c_int = undefined; |
| 6 | const x = __muloti4(a, b, &overflow); | |
| 8 | const x = mulo.__muloti4(a, b, &overflow); | |
| 7 | 9 | try testing.expect(overflow == expected_overflow and (expected_overflow != 0 or x == expected)); |
| 8 | 10 | } |
| 9 | 11 | |
| ... | ... | @@ -13,7 +15,6 @@ test "muloti4" { |
| 13 | 15 | try test__muloti4(1, 0, 0, 0); |
| 14 | 16 | try test__muloti4(0, 10, 0, 0); |
| 15 | 17 | try test__muloti4(10, 0, 0, 0); |
| 16 | ||
| 17 | 18 | try test__muloti4(0, 81985529216486895, 0, 0); |
| 18 | 19 | try test__muloti4(81985529216486895, 0, 0, 0); |
| 19 | 20 | |
| ... | ... | @@ -24,6 +25,18 @@ test "muloti4" { |
| 24 | 25 | try test__muloti4(0, -81985529216486895, 0, 0); |
| 25 | 26 | try test__muloti4(-81985529216486895, 0, 0, 0); |
| 26 | 27 | |
| 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 | 40 | try test__muloti4(3037000499, 3037000499, 9223372030926249001, 0); |
| 28 | 41 | try test__muloti4(-3037000499, 3037000499, -9223372030926249001, 0); |
| 29 | 42 | try test__muloti4(3037000499, -3037000499, -9223372030926249001, 0); |