| author | |
| committer | |
| log | 97b9facb98cffa05064315d69a11b96836aa5be3 |
| tree | 063bb8d02a752df2d33fc8d2d8a2b1def1ee3728 |
| parent | 5f70c36fa88a17c045839b8b422e04db3b545426 |
| signature |
- Combine mulXi3 routines for follow-up cleanup.
- DRY up Dwords and Twords
- rename both to HalveInt and use instance
* Justification: Not all processors have word size 32 bit.
* remove test file from CMakeLists
* DRY things.11 files changed, 294 insertions(+), 354 deletions(-)
CMakeLists.txt+3-5| ... | ... | @@ -434,13 +434,12 @@ set(ZIG_STAGE2_SOURCES |
| 434 | 434 | "${CMAKE_SOURCE_DIR}/lib/compiler_rt/log10.zig" |
| 435 | 435 | "${CMAKE_SOURCE_DIR}/lib/compiler_rt/log2.zig" |
| 436 | 436 | "${CMAKE_SOURCE_DIR}/lib/compiler_rt/modti3.zig" |
| 437 | "${CMAKE_SOURCE_DIR}/lib/compiler_rt/mulXi3.zig" | |
| 437 | 438 | "${CMAKE_SOURCE_DIR}/lib/compiler_rt/muldf3.zig" |
| 438 | "${CMAKE_SOURCE_DIR}/lib/compiler_rt/muldi3.zig" | |
| 439 | 439 | "${CMAKE_SOURCE_DIR}/lib/compiler_rt/mulf3.zig" |
| 440 | 440 | "${CMAKE_SOURCE_DIR}/lib/compiler_rt/mulo.zig" |
| 441 | 441 | "${CMAKE_SOURCE_DIR}/lib/compiler_rt/mulsf3.zig" |
| 442 | 442 | "${CMAKE_SOURCE_DIR}/lib/compiler_rt/multf3.zig" |
| 443 | "${CMAKE_SOURCE_DIR}/lib/compiler_rt/multi3.zig" | |
| 444 | 443 | "${CMAKE_SOURCE_DIR}/lib/compiler_rt/mulxf3.zig" |
| 445 | 444 | "${CMAKE_SOURCE_DIR}/lib/compiler_rt/negXi2.zig" |
| 446 | 445 | "${CMAKE_SOURCE_DIR}/lib/compiler_rt/negv.zig" |
| ... | ... | @@ -613,7 +612,6 @@ set(ZIG_STAGE2_SOURCES |
| 613 | 612 | "${CMAKE_SOURCE_DIR}/src/link/tapi.zig" |
| 614 | 613 | "${CMAKE_SOURCE_DIR}/src/link/tapi/Tokenizer.zig" |
| 615 | 614 | "${CMAKE_SOURCE_DIR}/src/link/tapi/parse.zig" |
| 616 | "${CMAKE_SOURCE_DIR}/src/link/tapi/parse/test.zig" | |
| 617 | 615 | "${CMAKE_SOURCE_DIR}/src/link/tapi/yaml.zig" |
| 618 | 616 | "${CMAKE_SOURCE_DIR}/src/main.zig" |
| 619 | 617 | "${CMAKE_SOURCE_DIR}/src/mingw.zig" |
| ... | ... | @@ -753,7 +751,7 @@ set(BUILD_ZIG2_ARGS |
| 753 | 751 | --deps build_options |
| 754 | 752 | -target "${HOST_TARGET_TRIPLE}" |
| 755 | 753 | ) |
| 756 | ||
| 754 | ||
| 757 | 755 | add_custom_command( |
| 758 | 756 | OUTPUT "${ZIG2_C_SOURCE}" |
| 759 | 757 | COMMAND zig1 ${BUILD_ZIG2_ARGS} |
| ... | ... | @@ -771,7 +769,7 @@ set(BUILD_COMPILER_RT_ARGS |
| 771 | 769 | --deps build_options |
| 772 | 770 | -target "${HOST_TARGET_TRIPLE}" |
| 773 | 771 | ) |
| 774 | ||
| 772 | ||
| 775 | 773 | add_custom_command( |
| 776 | 774 | OUTPUT "${ZIG_COMPILER_RT_C_SOURCE}" |
| 777 | 775 | COMMAND zig1 ${BUILD_COMPILER_RT_ARGS} |
lib/compiler_rt.zig+1-2| ... | ... | @@ -13,8 +13,7 @@ comptime { |
| 13 | 13 | _ = @import("compiler_rt/shift.zig"); |
| 14 | 14 | _ = @import("compiler_rt/negXi2.zig"); |
| 15 | 15 | _ = @import("compiler_rt/int.zig"); |
| 16 | _ = @import("compiler_rt/muldi3.zig"); | |
| 17 | _ = @import("compiler_rt/multi3.zig"); | |
| 16 | _ = @import("compiler_rt/mulXi3.zig"); | |
| 18 | 17 | _ = @import("compiler_rt/divti3.zig"); |
| 19 | 18 | _ = @import("compiler_rt/udivti3.zig"); |
| 20 | 19 | _ = @import("compiler_rt/modti3.zig"); |
lib/compiler_rt/common.zig+18| ... | ... | @@ -1,5 +1,6 @@ |
| 1 | 1 | const std = @import("std"); |
| 2 | 2 | const builtin = @import("builtin"); |
| 3 | const native_endian = builtin.cpu.arch.endian(); | |
| 3 | 4 | |
| 4 | 5 | pub const linkage: std.builtin.GlobalLinkage = if (builtin.is_test) .Internal else .Weak; |
| 5 | 6 | /// Determines the symbol's visibility to other objects. |
| ... | ... | @@ -221,3 +222,20 @@ pub inline fn fneg(a: anytype) @TypeOf(a) { |
| 221 | 222 | const negated = @bitCast(U, a) ^ sign_bit_mask; |
| 222 | 223 | return @bitCast(F, negated); |
| 223 | 224 | } |
| 225 | ||
| 226 | /// Allows to access underlying bits as two equally sized lower and higher | |
| 227 | /// signed or unsigned integers. | |
| 228 | pub fn HalveInt(comptime T: type, comptime signed_half: bool) type { | |
| 229 | return extern union { | |
| 230 | pub const bits = @divExact(@typeInfo(T).Int.bits, 2); | |
| 231 | pub const HalfTU = std.meta.Int(.unsigned, bits); | |
| 232 | pub const HalfTS = std.meta.Int(.signed, bits); | |
| 233 | pub const HalfT = if (signed_half) HalfTS else HalfTU; | |
| 234 | ||
| 235 | all: T, | |
| 236 | s: if (native_endian == .Little) | |
| 237 | extern struct { low: HalfT, high: HalfT } | |
| 238 | else | |
| 239 | extern struct { high: HalfT, low: HalfT }, | |
| 240 | }; | |
| 241 | } |
lib/compiler_rt/int.zig-57| ... | ... | @@ -16,7 +16,6 @@ pub const panic = common.panic; |
| 16 | 16 | comptime { |
| 17 | 17 | @export(__divmodti4, .{ .name = "__divmodti4", .linkage = common.linkage, .visibility = common.visibility }); |
| 18 | 18 | @export(__udivmoddi4, .{ .name = "__udivmoddi4", .linkage = common.linkage, .visibility = common.visibility }); |
| 19 | @export(__mulsi3, .{ .name = "__mulsi3", .linkage = common.linkage, .visibility = common.visibility }); | |
| 20 | 19 | @export(__divmoddi4, .{ .name = "__divmoddi4", .linkage = common.linkage, .visibility = common.visibility }); |
| 21 | 20 | if (common.want_aeabi) { |
| 22 | 21 | @export(__aeabi_idiv, .{ .name = "__aeabi_idiv", .linkage = common.linkage, .visibility = common.visibility }); |
| ... | ... | @@ -663,59 +662,3 @@ fn test_one_umodsi3(a: u32, b: u32, expected_r: u32) !void { |
| 663 | 662 | const r: u32 = __umodsi3(a, b); |
| 664 | 663 | try testing.expect(r == expected_r); |
| 665 | 664 | } |
| 666 | ||
| 667 | pub fn __mulsi3(a: i32, b: i32) callconv(.C) i32 { | |
| 668 | var ua = @bitCast(u32, a); | |
| 669 | var ub = @bitCast(u32, b); | |
| 670 | var r: u32 = 0; | |
| 671 | ||
| 672 | while (ua > 0) { | |
| 673 | if ((ua & 1) != 0) r +%= ub; | |
| 674 | ua >>= 1; | |
| 675 | ub <<= 1; | |
| 676 | } | |
| 677 | ||
| 678 | return @bitCast(i32, r); | |
| 679 | } | |
| 680 | ||
| 681 | fn test_one_mulsi3(a: i32, b: i32, result: i32) !void { | |
| 682 | try testing.expectEqual(result, __mulsi3(a, b)); | |
| 683 | } | |
| 684 | ||
| 685 | test "mulsi3" { | |
| 686 | try test_one_mulsi3(0, 0, 0); | |
| 687 | try test_one_mulsi3(0, 1, 0); | |
| 688 | try test_one_mulsi3(1, 0, 0); | |
| 689 | try test_one_mulsi3(0, 10, 0); | |
| 690 | try test_one_mulsi3(10, 0, 0); | |
| 691 | try test_one_mulsi3(0, maxInt(i32), 0); | |
| 692 | try test_one_mulsi3(maxInt(i32), 0, 0); | |
| 693 | try test_one_mulsi3(0, -1, 0); | |
| 694 | try test_one_mulsi3(-1, 0, 0); | |
| 695 | try test_one_mulsi3(0, -10, 0); | |
| 696 | try test_one_mulsi3(-10, 0, 0); | |
| 697 | try test_one_mulsi3(0, minInt(i32), 0); | |
| 698 | try test_one_mulsi3(minInt(i32), 0, 0); | |
| 699 | try test_one_mulsi3(1, 1, 1); | |
| 700 | try test_one_mulsi3(1, 10, 10); | |
| 701 | try test_one_mulsi3(10, 1, 10); | |
| 702 | try test_one_mulsi3(1, maxInt(i32), maxInt(i32)); | |
| 703 | try test_one_mulsi3(maxInt(i32), 1, maxInt(i32)); | |
| 704 | try test_one_mulsi3(1, -1, -1); | |
| 705 | try test_one_mulsi3(1, -10, -10); | |
| 706 | try test_one_mulsi3(-10, 1, -10); | |
| 707 | try test_one_mulsi3(1, minInt(i32), minInt(i32)); | |
| 708 | try test_one_mulsi3(minInt(i32), 1, minInt(i32)); | |
| 709 | try test_one_mulsi3(46340, 46340, 2147395600); | |
| 710 | try test_one_mulsi3(-46340, 46340, -2147395600); | |
| 711 | try test_one_mulsi3(46340, -46340, -2147395600); | |
| 712 | try test_one_mulsi3(-46340, -46340, 2147395600); | |
| 713 | try test_one_mulsi3(4194303, 8192, @truncate(i32, 34359730176)); | |
| 714 | try test_one_mulsi3(-4194303, 8192, @truncate(i32, -34359730176)); | |
| 715 | try test_one_mulsi3(4194303, -8192, @truncate(i32, -34359730176)); | |
| 716 | try test_one_mulsi3(-4194303, -8192, @truncate(i32, 34359730176)); | |
| 717 | try test_one_mulsi3(8192, 4194303, @truncate(i32, 34359730176)); | |
| 718 | try test_one_mulsi3(-8192, 4194303, @truncate(i32, -34359730176)); | |
| 719 | try test_one_mulsi3(8192, -4194303, @truncate(i32, -34359730176)); | |
| 720 | try test_one_mulsi3(-8192, -4194303, @truncate(i32, 34359730176)); | |
| 721 | } |
lib/compiler_rt/mulXi3.zig created+101| ... | ... | @@ -0,0 +1,101 @@ |
| 1 | const builtin = @import("builtin"); | |
| 2 | const std = @import("std"); | |
| 3 | const testing = std.testing; | |
| 4 | const common = @import("common.zig"); | |
| 5 | const native_endian = builtin.cpu.arch.endian(); | |
| 6 | ||
| 7 | pub const panic = common.panic; | |
| 8 | ||
| 9 | comptime { | |
| 10 | @export(__mulsi3, .{ .name = "__mulsi3", .linkage = common.linkage, .visibility = common.visibility }); | |
| 11 | if (common.want_aeabi) { | |
| 12 | @export(__aeabi_lmul, .{ .name = "__aeabi_lmul", .linkage = common.linkage, .visibility = common.visibility }); | |
| 13 | } else { | |
| 14 | @export(__muldi3, .{ .name = "__muldi3", .linkage = common.linkage, .visibility = common.visibility }); | |
| 15 | } | |
| 16 | if (common.want_windows_v2u64_abi) { | |
| 17 | @export(__multi3_windows_x86_64, .{ .name = "__multi3", .linkage = common.linkage, .visibility = common.visibility }); | |
| 18 | } else { | |
| 19 | @export(__multi3, .{ .name = "__multi3", .linkage = common.linkage, .visibility = common.visibility }); | |
| 20 | } | |
| 21 | } | |
| 22 | ||
| 23 | pub fn __mulsi3(a: i32, b: i32) callconv(.C) i32 { | |
| 24 | var ua = @bitCast(u32, a); | |
| 25 | var ub = @bitCast(u32, b); | |
| 26 | var r: u32 = 0; | |
| 27 | ||
| 28 | while (ua > 0) { | |
| 29 | if ((ua & 1) != 0) r +%= ub; | |
| 30 | ua >>= 1; | |
| 31 | ub <<= 1; | |
| 32 | } | |
| 33 | ||
| 34 | return @bitCast(i32, r); | |
| 35 | } | |
| 36 | ||
| 37 | pub fn __muldi3(a: i64, b: i64) callconv(.C) i64 { | |
| 38 | return mulX(i64, a, b); | |
| 39 | } | |
| 40 | ||
| 41 | fn __aeabi_lmul(a: i64, b: i64) callconv(.AAPCS) i64 { | |
| 42 | return mulX(i64, a, b); | |
| 43 | } | |
| 44 | ||
| 45 | inline fn mulX(comptime T: type, a: T, b: T) T { | |
| 46 | const word_t = common.HalveInt(T, false); | |
| 47 | const x = word_t{ .all = a }; | |
| 48 | const y = word_t{ .all = b }; | |
| 49 | var r = switch (T) { | |
| 50 | i64, i128 => word_t{ .all = muldXi(word_t.HalfT, x.s.low, y.s.low) }, | |
| 51 | else => unreachable, | |
| 52 | }; | |
| 53 | r.s.high +%= x.s.high *% y.s.low +% x.s.low *% y.s.high; | |
| 54 | return r.all; | |
| 55 | } | |
| 56 | ||
| 57 | fn DoubleInt(comptime T: type) type { | |
| 58 | return switch (T) { | |
| 59 | u32 => i64, | |
| 60 | u64 => i128, | |
| 61 | i32 => i64, | |
| 62 | i64 => i128, | |
| 63 | else => unreachable, | |
| 64 | }; | |
| 65 | } | |
| 66 | ||
| 67 | fn muldXi(comptime T: type, a: T, b: T) DoubleInt(T) { | |
| 68 | const DT = DoubleInt(T); | |
| 69 | const word_t = common.HalveInt(DT, false); | |
| 70 | const bits_in_word_2 = @sizeOf(T) * 8 / 2; | |
| 71 | const lower_mask = (~@as(T, 0)) >> bits_in_word_2; | |
| 72 | ||
| 73 | var r: word_t = undefined; | |
| 74 | r.s.low = (a & lower_mask) *% (b & lower_mask); | |
| 75 | var t: T = r.s.low >> bits_in_word_2; | |
| 76 | r.s.low &= lower_mask; | |
| 77 | t += (a >> bits_in_word_2) *% (b & lower_mask); | |
| 78 | r.s.low +%= (t & lower_mask) << bits_in_word_2; | |
| 79 | r.s.high = t >> bits_in_word_2; | |
| 80 | t = r.s.low >> bits_in_word_2; | |
| 81 | r.s.low &= lower_mask; | |
| 82 | t +%= (b >> bits_in_word_2) *% (a & lower_mask); | |
| 83 | r.s.low +%= (t & lower_mask) << bits_in_word_2; | |
| 84 | r.s.high +%= t >> bits_in_word_2; | |
| 85 | r.s.high +%= (a >> bits_in_word_2) *% (b >> bits_in_word_2); | |
| 86 | return r.all; | |
| 87 | } | |
| 88 | ||
| 89 | pub fn __multi3(a: i128, b: i128) callconv(.C) i128 { | |
| 90 | return mulX(i128, a, b); | |
| 91 | } | |
| 92 | ||
| 93 | const v2u64 = @Vector(2, u64); | |
| 94 | ||
| 95 | fn __multi3_windows_x86_64(a: v2u64, b: v2u64) callconv(.C) v2u64 { | |
| 96 | return @bitCast(v2u64, mulX(i128, @bitCast(i128, a), @bitCast(i128, b))); | |
| 97 | } | |
| 98 | ||
| 99 | test { | |
| 100 | _ = @import("mulXi3_test.zig"); | |
| 101 | } |
lib/compiler_rt/mulXi3_test.zig created+147| ... | ... | @@ -0,0 +1,147 @@ |
| 1 | const std = @import("std"); | |
| 2 | const testing = std.testing; | |
| 3 | const mulXi3 = @import("mulXi3.zig"); | |
| 4 | const maxInt = std.math.maxInt; | |
| 5 | const minInt = std.math.minInt; | |
| 6 | ||
| 7 | fn test_one_mulsi3(a: i32, b: i32, result: i32) !void { | |
| 8 | try testing.expectEqual(result, mulXi3.__mulsi3(a, b)); | |
| 9 | } | |
| 10 | ||
| 11 | fn test__muldi3(a: i64, b: i64, expected: i64) !void { | |
| 12 | const x = mulXi3.__muldi3(a, b); | |
| 13 | try testing.expect(x == expected); | |
| 14 | } | |
| 15 | ||
| 16 | fn test__multi3(a: i128, b: i128, expected: i128) !void { | |
| 17 | const x = mulXi3.__multi3(a, b); | |
| 18 | try testing.expect(x == expected); | |
| 19 | } | |
| 20 | ||
| 21 | test "mulsi3" { | |
| 22 | try test_one_mulsi3(0, 0, 0); | |
| 23 | try test_one_mulsi3(0, 1, 0); | |
| 24 | try test_one_mulsi3(1, 0, 0); | |
| 25 | try test_one_mulsi3(0, 10, 0); | |
| 26 | try test_one_mulsi3(10, 0, 0); | |
| 27 | try test_one_mulsi3(0, maxInt(i32), 0); | |
| 28 | try test_one_mulsi3(maxInt(i32), 0, 0); | |
| 29 | try test_one_mulsi3(0, -1, 0); | |
| 30 | try test_one_mulsi3(-1, 0, 0); | |
| 31 | try test_one_mulsi3(0, -10, 0); | |
| 32 | try test_one_mulsi3(-10, 0, 0); | |
| 33 | try test_one_mulsi3(0, minInt(i32), 0); | |
| 34 | try test_one_mulsi3(minInt(i32), 0, 0); | |
| 35 | try test_one_mulsi3(1, 1, 1); | |
| 36 | try test_one_mulsi3(1, 10, 10); | |
| 37 | try test_one_mulsi3(10, 1, 10); | |
| 38 | try test_one_mulsi3(1, maxInt(i32), maxInt(i32)); | |
| 39 | try test_one_mulsi3(maxInt(i32), 1, maxInt(i32)); | |
| 40 | try test_one_mulsi3(1, -1, -1); | |
| 41 | try test_one_mulsi3(1, -10, -10); | |
| 42 | try test_one_mulsi3(-10, 1, -10); | |
| 43 | try test_one_mulsi3(1, minInt(i32), minInt(i32)); | |
| 44 | try test_one_mulsi3(minInt(i32), 1, minInt(i32)); | |
| 45 | try test_one_mulsi3(46340, 46340, 2147395600); | |
| 46 | try test_one_mulsi3(-46340, 46340, -2147395600); | |
| 47 | try test_one_mulsi3(46340, -46340, -2147395600); | |
| 48 | try test_one_mulsi3(-46340, -46340, 2147395600); | |
| 49 | try test_one_mulsi3(4194303, 8192, @truncate(i32, 34359730176)); | |
| 50 | try test_one_mulsi3(-4194303, 8192, @truncate(i32, -34359730176)); | |
| 51 | try test_one_mulsi3(4194303, -8192, @truncate(i32, -34359730176)); | |
| 52 | try test_one_mulsi3(-4194303, -8192, @truncate(i32, 34359730176)); | |
| 53 | try test_one_mulsi3(8192, 4194303, @truncate(i32, 34359730176)); | |
| 54 | try test_one_mulsi3(-8192, 4194303, @truncate(i32, -34359730176)); | |
| 55 | try test_one_mulsi3(8192, -4194303, @truncate(i32, -34359730176)); | |
| 56 | try test_one_mulsi3(-8192, -4194303, @truncate(i32, 34359730176)); | |
| 57 | } | |
| 58 | ||
| 59 | test "muldi3" { | |
| 60 | try test__muldi3(0, 0, 0); | |
| 61 | try test__muldi3(0, 1, 0); | |
| 62 | try test__muldi3(1, 0, 0); | |
| 63 | try test__muldi3(0, 10, 0); | |
| 64 | try test__muldi3(10, 0, 0); | |
| 65 | try test__muldi3(0, 81985529216486895, 0); | |
| 66 | try test__muldi3(81985529216486895, 0, 0); | |
| 67 | ||
| 68 | try test__muldi3(0, -1, 0); | |
| 69 | try test__muldi3(-1, 0, 0); | |
| 70 | try test__muldi3(0, -10, 0); | |
| 71 | try test__muldi3(-10, 0, 0); | |
| 72 | try test__muldi3(0, -81985529216486895, 0); | |
| 73 | try test__muldi3(-81985529216486895, 0, 0); | |
| 74 | ||
| 75 | try test__muldi3(1, 1, 1); | |
| 76 | try test__muldi3(1, 10, 10); | |
| 77 | try test__muldi3(10, 1, 10); | |
| 78 | try test__muldi3(1, 81985529216486895, 81985529216486895); | |
| 79 | try test__muldi3(81985529216486895, 1, 81985529216486895); | |
| 80 | ||
| 81 | try test__muldi3(1, -1, -1); | |
| 82 | try test__muldi3(1, -10, -10); | |
| 83 | try test__muldi3(-10, 1, -10); | |
| 84 | try test__muldi3(1, -81985529216486895, -81985529216486895); | |
| 85 | try test__muldi3(-81985529216486895, 1, -81985529216486895); | |
| 86 | ||
| 87 | try test__muldi3(3037000499, 3037000499, 9223372030926249001); | |
| 88 | try test__muldi3(-3037000499, 3037000499, -9223372030926249001); | |
| 89 | try test__muldi3(3037000499, -3037000499, -9223372030926249001); | |
| 90 | try test__muldi3(-3037000499, -3037000499, 9223372030926249001); | |
| 91 | ||
| 92 | try test__muldi3(4398046511103, 2097152, 9223372036852678656); | |
| 93 | try test__muldi3(-4398046511103, 2097152, -9223372036852678656); | |
| 94 | try test__muldi3(4398046511103, -2097152, -9223372036852678656); | |
| 95 | try test__muldi3(-4398046511103, -2097152, 9223372036852678656); | |
| 96 | ||
| 97 | try test__muldi3(2097152, 4398046511103, 9223372036852678656); | |
| 98 | try test__muldi3(-2097152, 4398046511103, -9223372036852678656); | |
| 99 | try test__muldi3(2097152, -4398046511103, -9223372036852678656); | |
| 100 | try test__muldi3(-2097152, -4398046511103, 9223372036852678656); | |
| 101 | } | |
| 102 | ||
| 103 | test "multi3" { | |
| 104 | try test__multi3(0, 0, 0); | |
| 105 | try test__multi3(0, 1, 0); | |
| 106 | try test__multi3(1, 0, 0); | |
| 107 | try test__multi3(0, 10, 0); | |
| 108 | try test__multi3(10, 0, 0); | |
| 109 | try test__multi3(0, 81985529216486895, 0); | |
| 110 | try test__multi3(81985529216486895, 0, 0); | |
| 111 | ||
| 112 | try test__multi3(0, -1, 0); | |
| 113 | try test__multi3(-1, 0, 0); | |
| 114 | try test__multi3(0, -10, 0); | |
| 115 | try test__multi3(-10, 0, 0); | |
| 116 | try test__multi3(0, -81985529216486895, 0); | |
| 117 | try test__multi3(-81985529216486895, 0, 0); | |
| 118 | ||
| 119 | try test__multi3(1, 1, 1); | |
| 120 | try test__multi3(1, 10, 10); | |
| 121 | try test__multi3(10, 1, 10); | |
| 122 | try test__multi3(1, 81985529216486895, 81985529216486895); | |
| 123 | try test__multi3(81985529216486895, 1, 81985529216486895); | |
| 124 | ||
| 125 | try test__multi3(1, -1, -1); | |
| 126 | try test__multi3(1, -10, -10); | |
| 127 | try test__multi3(-10, 1, -10); | |
| 128 | try test__multi3(1, -81985529216486895, -81985529216486895); | |
| 129 | try test__multi3(-81985529216486895, 1, -81985529216486895); | |
| 130 | ||
| 131 | try test__multi3(3037000499, 3037000499, 9223372030926249001); | |
| 132 | try test__multi3(-3037000499, 3037000499, -9223372030926249001); | |
| 133 | try test__multi3(3037000499, -3037000499, -9223372030926249001); | |
| 134 | try test__multi3(-3037000499, -3037000499, 9223372030926249001); | |
| 135 | ||
| 136 | try test__multi3(4398046511103, 2097152, 9223372036852678656); | |
| 137 | try test__multi3(-4398046511103, 2097152, -9223372036852678656); | |
| 138 | try test__multi3(4398046511103, -2097152, -9223372036852678656); | |
| 139 | try test__multi3(-4398046511103, -2097152, 9223372036852678656); | |
| 140 | ||
| 141 | try test__multi3(2097152, 4398046511103, 9223372036852678656); | |
| 142 | try test__multi3(-2097152, 4398046511103, -9223372036852678656); | |
| 143 | try test__multi3(2097152, -4398046511103, -9223372036852678656); | |
| 144 | try test__multi3(-2097152, -4398046511103, 9223372036852678656); | |
| 145 | ||
| 146 | try test__multi3(0x00000000000000B504F333F9DE5BE000, 0x000000000000000000B504F333F9DE5B, 0x7FFFFFFFFFFFF328DF915DA296E8A000); | |
| 147 | } |
lib/compiler_rt/muldi3.zig deleted-71| ... | ... | @@ -1,71 +0,0 @@ |
| 1 | //! Ported from | |
| 2 | //! https://github.com/llvm/llvm-project/blob/llvmorg-9.0.0/compiler-rt/lib/builtins/muldi3.c | |
| 3 | ||
| 4 | const std = @import("std"); | |
| 5 | const builtin = @import("builtin"); | |
| 6 | const native_endian = builtin.cpu.arch.endian(); | |
| 7 | const common = @import("common.zig"); | |
| 8 | ||
| 9 | pub const panic = common.panic; | |
| 10 | ||
| 11 | comptime { | |
| 12 | if (common.want_aeabi) { | |
| 13 | @export(__aeabi_lmul, .{ .name = "__aeabi_lmul", .linkage = common.linkage, .visibility = common.visibility }); | |
| 14 | } else { | |
| 15 | @export(__muldi3, .{ .name = "__muldi3", .linkage = common.linkage, .visibility = common.visibility }); | |
| 16 | } | |
| 17 | } | |
| 18 | ||
| 19 | pub fn __muldi3(a: i64, b: i64) callconv(.C) i64 { | |
| 20 | return mul(a, b); | |
| 21 | } | |
| 22 | ||
| 23 | fn __aeabi_lmul(a: i64, b: i64) callconv(.AAPCS) i64 { | |
| 24 | return mul(a, b); | |
| 25 | } | |
| 26 | ||
| 27 | inline fn mul(a: i64, b: i64) i64 { | |
| 28 | const x = dwords{ .all = a }; | |
| 29 | const y = dwords{ .all = b }; | |
| 30 | var r = dwords{ .all = muldsi3(x.s.low, y.s.low) }; | |
| 31 | r.s.high +%= x.s.high *% y.s.low +% x.s.low *% y.s.high; | |
| 32 | return r.all; | |
| 33 | } | |
| 34 | ||
| 35 | const dwords = extern union { | |
| 36 | all: i64, | |
| 37 | s: switch (native_endian) { | |
| 38 | .Little => extern struct { | |
| 39 | low: u32, | |
| 40 | high: u32, | |
| 41 | }, | |
| 42 | .Big => extern struct { | |
| 43 | high: u32, | |
| 44 | low: u32, | |
| 45 | }, | |
| 46 | }, | |
| 47 | }; | |
| 48 | ||
| 49 | fn muldsi3(a: u32, b: u32) i64 { | |
| 50 | const bits_in_word_2 = @sizeOf(i32) * 8 / 2; | |
| 51 | const lower_mask = (~@as(u32, 0)) >> bits_in_word_2; | |
| 52 | ||
| 53 | var r: dwords = undefined; | |
| 54 | r.s.low = (a & lower_mask) *% (b & lower_mask); | |
| 55 | var t: u32 = r.s.low >> bits_in_word_2; | |
| 56 | r.s.low &= lower_mask; | |
| 57 | t += (a >> bits_in_word_2) *% (b & lower_mask); | |
| 58 | r.s.low +%= (t & lower_mask) << bits_in_word_2; | |
| 59 | r.s.high = t >> bits_in_word_2; | |
| 60 | t = r.s.low >> bits_in_word_2; | |
| 61 | r.s.low &= lower_mask; | |
| 62 | t +%= (b >> bits_in_word_2) *% (a & lower_mask); | |
| 63 | r.s.low +%= (t & lower_mask) << bits_in_word_2; | |
| 64 | r.s.high +%= t >> bits_in_word_2; | |
| 65 | r.s.high +%= (a >> bits_in_word_2) *% (b >> bits_in_word_2); | |
| 66 | return r.all; | |
| 67 | } | |
| 68 | ||
| 69 | test { | |
| 70 | _ = @import("muldi3_test.zig"); | |
| 71 | } |
lib/compiler_rt/muldi3_test.zig deleted-51| ... | ... | @@ -1,51 +0,0 @@ |
| 1 | const __muldi3 = @import("muldi3.zig").__muldi3; | |
| 2 | const testing = @import("std").testing; | |
| 3 | ||
| 4 | fn test__muldi3(a: i64, b: i64, expected: i64) !void { | |
| 5 | const x = __muldi3(a, b); | |
| 6 | try testing.expect(x == expected); | |
| 7 | } | |
| 8 | ||
| 9 | test "muldi3" { | |
| 10 | try test__muldi3(0, 0, 0); | |
| 11 | try test__muldi3(0, 1, 0); | |
| 12 | try test__muldi3(1, 0, 0); | |
| 13 | try test__muldi3(0, 10, 0); | |
| 14 | try test__muldi3(10, 0, 0); | |
| 15 | try test__muldi3(0, 81985529216486895, 0); | |
| 16 | try test__muldi3(81985529216486895, 0, 0); | |
| 17 | ||
| 18 | try test__muldi3(0, -1, 0); | |
| 19 | try test__muldi3(-1, 0, 0); | |
| 20 | try test__muldi3(0, -10, 0); | |
| 21 | try test__muldi3(-10, 0, 0); | |
| 22 | try test__muldi3(0, -81985529216486895, 0); | |
| 23 | try test__muldi3(-81985529216486895, 0, 0); | |
| 24 | ||
| 25 | try test__muldi3(1, 1, 1); | |
| 26 | try test__muldi3(1, 10, 10); | |
| 27 | try test__muldi3(10, 1, 10); | |
| 28 | try test__muldi3(1, 81985529216486895, 81985529216486895); | |
| 29 | try test__muldi3(81985529216486895, 1, 81985529216486895); | |
| 30 | ||
| 31 | try test__muldi3(1, -1, -1); | |
| 32 | try test__muldi3(1, -10, -10); | |
| 33 | try test__muldi3(-10, 1, -10); | |
| 34 | try test__muldi3(1, -81985529216486895, -81985529216486895); | |
| 35 | try test__muldi3(-81985529216486895, 1, -81985529216486895); | |
| 36 | ||
| 37 | try test__muldi3(3037000499, 3037000499, 9223372030926249001); | |
| 38 | try test__muldi3(-3037000499, 3037000499, -9223372030926249001); | |
| 39 | try test__muldi3(3037000499, -3037000499, -9223372030926249001); | |
| 40 | try test__muldi3(-3037000499, -3037000499, 9223372030926249001); | |
| 41 | ||
| 42 | try test__muldi3(4398046511103, 2097152, 9223372036852678656); | |
| 43 | try test__muldi3(-4398046511103, 2097152, -9223372036852678656); | |
| 44 | try test__muldi3(4398046511103, -2097152, -9223372036852678656); | |
| 45 | try test__muldi3(-4398046511103, -2097152, 9223372036852678656); | |
| 46 | ||
| 47 | try test__muldi3(2097152, 4398046511103, 9223372036852678656); | |
| 48 | try test__muldi3(-2097152, 4398046511103, -9223372036852678656); | |
| 49 | try test__muldi3(2097152, -4398046511103, -9223372036852678656); | |
| 50 | try test__muldi3(-2097152, -4398046511103, 9223372036852678656); | |
| 51 | } |
lib/compiler_rt/multi3.zig deleted-75| ... | ... | @@ -1,75 +0,0 @@ |
| 1 | //! Ported from git@github.com:llvm-project/llvm-project-20170507.git | |
| 2 | //! ae684fad6d34858c014c94da69c15e7774a633c3 | |
| 3 | //! 2018-08-13 | |
| 4 | ||
| 5 | const std = @import("std"); | |
| 6 | const builtin = @import("builtin"); | |
| 7 | const native_endian = builtin.cpu.arch.endian(); | |
| 8 | const common = @import("common.zig"); | |
| 9 | ||
| 10 | pub const panic = common.panic; | |
| 11 | ||
| 12 | comptime { | |
| 13 | if (common.want_windows_v2u64_abi) { | |
| 14 | @export(__multi3_windows_x86_64, .{ .name = "__multi3", .linkage = common.linkage, .visibility = common.visibility }); | |
| 15 | } else { | |
| 16 | @export(__multi3, .{ .name = "__multi3", .linkage = common.linkage, .visibility = common.visibility }); | |
| 17 | } | |
| 18 | } | |
| 19 | ||
| 20 | pub fn __multi3(a: i128, b: i128) callconv(.C) i128 { | |
| 21 | return mul(a, b); | |
| 22 | } | |
| 23 | ||
| 24 | const v2u64 = @Vector(2, u64); | |
| 25 | ||
| 26 | fn __multi3_windows_x86_64(a: v2u64, b: v2u64) callconv(.C) v2u64 { | |
| 27 | return @bitCast(v2u64, mul(@bitCast(i128, a), @bitCast(i128, b))); | |
| 28 | } | |
| 29 | ||
| 30 | inline fn mul(a: i128, b: i128) i128 { | |
| 31 | const x = twords{ .all = a }; | |
| 32 | const y = twords{ .all = b }; | |
| 33 | var r = twords{ .all = mulddi3(x.s.low, y.s.low) }; | |
| 34 | r.s.high +%= x.s.high *% y.s.low +% x.s.low *% y.s.high; | |
| 35 | return r.all; | |
| 36 | } | |
| 37 | ||
| 38 | fn mulddi3(a: u64, b: u64) i128 { | |
| 39 | const bits_in_dword_2 = (@sizeOf(i64) * 8) / 2; | |
| 40 | const lower_mask = ~@as(u64, 0) >> bits_in_dword_2; | |
| 41 | var r: twords = undefined; | |
| 42 | r.s.low = (a & lower_mask) *% (b & lower_mask); | |
| 43 | var t: u64 = r.s.low >> bits_in_dword_2; | |
| 44 | r.s.low &= lower_mask; | |
| 45 | t +%= (a >> bits_in_dword_2) *% (b & lower_mask); | |
| 46 | r.s.low +%= (t & lower_mask) << bits_in_dword_2; | |
| 47 | r.s.high = t >> bits_in_dword_2; | |
| 48 | t = r.s.low >> bits_in_dword_2; | |
| 49 | r.s.low &= lower_mask; | |
| 50 | t +%= (b >> bits_in_dword_2) *% (a & lower_mask); | |
| 51 | r.s.low +%= (t & lower_mask) << bits_in_dword_2; | |
| 52 | r.s.high +%= t >> bits_in_dword_2; | |
| 53 | r.s.high +%= (a >> bits_in_dword_2) *% (b >> bits_in_dword_2); | |
| 54 | return r.all; | |
| 55 | } | |
| 56 | ||
| 57 | const twords = extern union { | |
| 58 | all: i128, | |
| 59 | s: S, | |
| 60 | ||
| 61 | const S = if (native_endian == .Little) | |
| 62 | extern struct { | |
| 63 | low: u64, | |
| 64 | high: u64, | |
| 65 | } | |
| 66 | else | |
| 67 | extern struct { | |
| 68 | high: u64, | |
| 69 | low: u64, | |
| 70 | }; | |
| 71 | }; | |
| 72 | ||
| 73 | test { | |
| 74 | _ = @import("multi3_test.zig"); | |
| 75 | } |
lib/compiler_rt/multi3_test.zig deleted-53| ... | ... | @@ -1,53 +0,0 @@ |
| 1 | const __multi3 = @import("multi3.zig").__multi3; | |
| 2 | const testing = @import("std").testing; | |
| 3 | ||
| 4 | fn test__multi3(a: i128, b: i128, expected: i128) !void { | |
| 5 | const x = __multi3(a, b); | |
| 6 | try testing.expect(x == expected); | |
| 7 | } | |
| 8 | ||
| 9 | test "multi3" { | |
| 10 | try test__multi3(0, 0, 0); | |
| 11 | try test__multi3(0, 1, 0); | |
| 12 | try test__multi3(1, 0, 0); | |
| 13 | try test__multi3(0, 10, 0); | |
| 14 | try test__multi3(10, 0, 0); | |
| 15 | try test__multi3(0, 81985529216486895, 0); | |
| 16 | try test__multi3(81985529216486895, 0, 0); | |
| 17 | ||
| 18 | try test__multi3(0, -1, 0); | |
| 19 | try test__multi3(-1, 0, 0); | |
| 20 | try test__multi3(0, -10, 0); | |
| 21 | try test__multi3(-10, 0, 0); | |
| 22 | try test__multi3(0, -81985529216486895, 0); | |
| 23 | try test__multi3(-81985529216486895, 0, 0); | |
| 24 | ||
| 25 | try test__multi3(1, 1, 1); | |
| 26 | try test__multi3(1, 10, 10); | |
| 27 | try test__multi3(10, 1, 10); | |
| 28 | try test__multi3(1, 81985529216486895, 81985529216486895); | |
| 29 | try test__multi3(81985529216486895, 1, 81985529216486895); | |
| 30 | ||
| 31 | try test__multi3(1, -1, -1); | |
| 32 | try test__multi3(1, -10, -10); | |
| 33 | try test__multi3(-10, 1, -10); | |
| 34 | try test__multi3(1, -81985529216486895, -81985529216486895); | |
| 35 | try test__multi3(-81985529216486895, 1, -81985529216486895); | |
| 36 | ||
| 37 | try test__multi3(3037000499, 3037000499, 9223372030926249001); | |
| 38 | try test__multi3(-3037000499, 3037000499, -9223372030926249001); | |
| 39 | try test__multi3(3037000499, -3037000499, -9223372030926249001); | |
| 40 | try test__multi3(-3037000499, -3037000499, 9223372030926249001); | |
| 41 | ||
| 42 | try test__multi3(4398046511103, 2097152, 9223372036852678656); | |
| 43 | try test__multi3(-4398046511103, 2097152, -9223372036852678656); | |
| 44 | try test__multi3(4398046511103, -2097152, -9223372036852678656); | |
| 45 | try test__multi3(-4398046511103, -2097152, 9223372036852678656); | |
| 46 | ||
| 47 | try test__multi3(2097152, 4398046511103, 9223372036852678656); | |
| 48 | try test__multi3(-2097152, 4398046511103, -9223372036852678656); | |
| 49 | try test__multi3(2097152, -4398046511103, -9223372036852678656); | |
| 50 | try test__multi3(-2097152, -4398046511103, 9223372036852678656); | |
| 51 | ||
| 52 | try test__multi3(0x00000000000000B504F333F9DE5BE000, 0x000000000000000000B504F333F9DE5B, 0x7FFFFFFFFFFFF328DF915DA296E8A000); | |
| 53 | } |
lib/compiler_rt/shift.zig+24-40| ... | ... | @@ -1,7 +1,6 @@ |
| 1 | 1 | const std = @import("std"); |
| 2 | 2 | const builtin = @import("builtin"); |
| 3 | 3 | const Log2Int = std.math.Log2Int; |
| 4 | const native_endian = builtin.cpu.arch.endian(); | |
| 5 | 4 | const common = @import("common.zig"); |
| 6 | 5 | |
| 7 | 6 | pub const panic = common.panic; |
| ... | ... | @@ -27,39 +26,24 @@ comptime { |
| 27 | 26 | } |
| 28 | 27 | } |
| 29 | 28 | |
| 30 | fn Dwords(comptime T: type, comptime signed_half: bool) type { | |
| 31 | return extern union { | |
| 32 | const bits = @divExact(@typeInfo(T).Int.bits, 2); | |
| 33 | const HalfTU = std.meta.Int(.unsigned, bits); | |
| 34 | const HalfTS = std.meta.Int(.signed, bits); | |
| 35 | const HalfT = if (signed_half) HalfTS else HalfTU; | |
| 36 | ||
| 37 | all: T, | |
| 38 | s: if (native_endian == .Little) | |
| 39 | extern struct { low: HalfT, high: HalfT } | |
| 40 | else | |
| 41 | extern struct { high: HalfT, low: HalfT }, | |
| 42 | }; | |
| 43 | } | |
| 44 | ||
| 45 | 29 | // Arithmetic shift left: shift in 0 from right to left |
| 46 | 30 | // Precondition: 0 <= b < bits_in_dword |
| 47 | 31 | inline fn ashlXi3(comptime T: type, a: T, b: i32) T { |
| 48 | const dwords = Dwords(T, false); | |
| 49 | const S = Log2Int(dwords.HalfT); | |
| 32 | const word_t = common.HalveInt(T, false); | |
| 33 | const S = Log2Int(word_t.HalfT); | |
| 50 | 34 | |
| 51 | const input = dwords{ .all = a }; | |
| 52 | var output: dwords = undefined; | |
| 35 | const input = word_t{ .all = a }; | |
| 36 | var output: word_t = undefined; | |
| 53 | 37 | |
| 54 | if (b >= dwords.bits) { | |
| 38 | if (b >= word_t.bits) { | |
| 55 | 39 | output.s.low = 0; |
| 56 | output.s.high = input.s.low << @intCast(S, b - dwords.bits); | |
| 40 | output.s.high = input.s.low << @intCast(S, b - word_t.bits); | |
| 57 | 41 | } else if (b == 0) { |
| 58 | 42 | return a; |
| 59 | 43 | } else { |
| 60 | 44 | output.s.low = input.s.low << @intCast(S, b); |
| 61 | 45 | output.s.high = input.s.high << @intCast(S, b); |
| 62 | output.s.high |= input.s.low >> @intCast(S, dwords.bits - b); | |
| 46 | output.s.high |= input.s.low >> @intCast(S, word_t.bits - b); | |
| 63 | 47 | } |
| 64 | 48 | |
| 65 | 49 | return output.all; |
| ... | ... | @@ -68,24 +52,24 @@ inline fn ashlXi3(comptime T: type, a: T, b: i32) T { |
| 68 | 52 | // Arithmetic shift right: shift in 1 from left to right |
| 69 | 53 | // Precondition: 0 <= b < T.bit_count |
| 70 | 54 | inline fn ashrXi3(comptime T: type, a: T, b: i32) T { |
| 71 | const dwords = Dwords(T, true); | |
| 72 | const S = Log2Int(dwords.HalfT); | |
| 55 | const word_t = common.HalveInt(T, true); | |
| 56 | const S = Log2Int(word_t.HalfT); | |
| 73 | 57 | |
| 74 | const input = dwords{ .all = a }; | |
| 75 | var output: dwords = undefined; | |
| 58 | const input = word_t{ .all = a }; | |
| 59 | var output: word_t = undefined; | |
| 76 | 60 | |
| 77 | if (b >= dwords.bits) { | |
| 78 | output.s.high = input.s.high >> (dwords.bits - 1); | |
| 79 | output.s.low = input.s.high >> @intCast(S, b - dwords.bits); | |
| 61 | if (b >= word_t.bits) { | |
| 62 | output.s.high = input.s.high >> (word_t.bits - 1); | |
| 63 | output.s.low = input.s.high >> @intCast(S, b - word_t.bits); | |
| 80 | 64 | } else if (b == 0) { |
| 81 | 65 | return a; |
| 82 | 66 | } else { |
| 83 | 67 | output.s.high = input.s.high >> @intCast(S, b); |
| 84 | output.s.low = input.s.high << @intCast(S, dwords.bits - b); | |
| 68 | output.s.low = input.s.high << @intCast(S, word_t.bits - b); | |
| 85 | 69 | // Avoid sign-extension here |
| 86 | 70 | output.s.low |= @bitCast( |
| 87 | dwords.HalfT, | |
| 88 | @bitCast(dwords.HalfTU, input.s.low) >> @intCast(S, b), | |
| 71 | word_t.HalfT, | |
| 72 | @bitCast(word_t.HalfTU, input.s.low) >> @intCast(S, b), | |
| 89 | 73 | ); |
| 90 | 74 | } |
| 91 | 75 | |
| ... | ... | @@ -95,20 +79,20 @@ inline fn ashrXi3(comptime T: type, a: T, b: i32) T { |
| 95 | 79 | // Logical shift right: shift in 0 from left to right |
| 96 | 80 | // Precondition: 0 <= b < T.bit_count |
| 97 | 81 | inline fn lshrXi3(comptime T: type, a: T, b: i32) T { |
| 98 | const dwords = Dwords(T, false); | |
| 99 | const S = Log2Int(dwords.HalfT); | |
| 82 | const word_t = common.HalveInt(T, false); | |
| 83 | const S = Log2Int(word_t.HalfT); | |
| 100 | 84 | |
| 101 | const input = dwords{ .all = a }; | |
| 102 | var output: dwords = undefined; | |
| 85 | const input = word_t{ .all = a }; | |
| 86 | var output: word_t = undefined; | |
| 103 | 87 | |
| 104 | if (b >= dwords.bits) { | |
| 88 | if (b >= word_t.bits) { | |
| 105 | 89 | output.s.high = 0; |
| 106 | output.s.low = input.s.high >> @intCast(S, b - dwords.bits); | |
| 90 | output.s.low = input.s.high >> @intCast(S, b - word_t.bits); | |
| 107 | 91 | } else if (b == 0) { |
| 108 | 92 | return a; |
| 109 | 93 | } else { |
| 110 | 94 | output.s.high = input.s.high >> @intCast(S, b); |
| 111 | output.s.low = input.s.high << @intCast(S, dwords.bits - b); | |
| 95 | output.s.low = input.s.high << @intCast(S, word_t.bits - b); | |
| 112 | 96 | output.s.low |= input.s.low >> @intCast(S, b); |
| 113 | 97 | } |
| 114 | 98 |