Commit 07f0de6a8a

Andrew Kelley <andrew@ziglang.org>
2019-07-18 19:54:22
compiler-rt: add __muldi3
1 parent afbf99c
Changed files (6)
std/special/compiler_rt/divti3.zig
@@ -1,6 +1,5 @@
 const udivmod = @import("udivmod.zig").udivmod;
 const builtin = @import("builtin");
-const compiler_rt = @import("../compiler_rt.zig");
 
 pub extern fn __divti3(a: i128, b: i128) i128 {
     @setRuntimeSafety(builtin.is_test);
std/special/compiler_rt/muldi3.zig
@@ -0,0 +1,54 @@
+const builtin = @import("builtin");
+
+// Ported from
+// https://github.com/llvm/llvm-project/blob/552c2c09d354a3ad9c1c9647e0a3bb5099c31088/compiler-rt/lib/builtins/muldi3.c
+
+const dwords = extern union {
+    all: i64,
+    s: switch (builtin.endian) {
+        .Little => extern struct {
+            low: u32,
+            high: u32,
+        },
+        .Big => extern struct {
+            high: u32,
+            low: u32,
+        },
+    },
+};
+
+fn __muldsi3(a: u32, b: u32) i64 {
+    @setRuntimeSafety(builtin.is_test);
+
+    const bits_in_word_2 = @sizeOf(i32) * 8 / 2;
+    const lower_mask = (~u32(0)) >> bits_in_word_2;
+
+    var r: dwords = undefined;
+    r.s.low = (a & lower_mask) *% (b & lower_mask);
+    var t: u32 = r.s.low >> bits_in_word_2;
+    r.s.low &= lower_mask;
+    t += (a >> bits_in_word_2) *% (b & lower_mask);
+    r.s.low +%= (t & lower_mask) << bits_in_word_2;
+    r.s.high = t >> bits_in_word_2;
+    t = r.s.low >> bits_in_word_2;
+    r.s.low &= lower_mask;
+    t +%= (b >> bits_in_word_2) *% (a & lower_mask);
+    r.s.low +%= (t & lower_mask) << bits_in_word_2;
+    r.s.high +%= t >> bits_in_word_2;
+    r.s.high +%= (a >> bits_in_word_2) *% (b >> bits_in_word_2);
+    return r.all;
+}
+
+pub extern fn __muldi3(a: i64, b: i64) i64 {
+    @setRuntimeSafety(builtin.is_test);
+
+    const x = dwords{ .all = a };
+    const y = dwords{ .all = b };
+    var r = dwords{ .all = __muldsi3(x.s.low, y.s.low) };
+    r.s.high +%= x.s.high *% y.s.low +% x.s.low *% y.s.high;
+    return r.all;
+}
+
+test "import muldi3" {
+    _ = @import("muldi3_test.zig");
+}
std/special/compiler_rt/muldi3_test.zig
@@ -0,0 +1,51 @@
+const __muldi3 = @import("muldi3.zig").__muldi3;
+const testing = @import("std").testing;
+
+fn test__muldi3(a: i64, b: i64, expected: i64) void {
+    const x = __muldi3(a, b);
+    testing.expect(x == expected);
+}
+
+test "muldi3" {
+    test__muldi3(0, 0, 0);
+    test__muldi3(0, 1, 0);
+    test__muldi3(1, 0, 0);
+    test__muldi3(0, 10, 0);
+    test__muldi3(10, 0, 0);
+    test__muldi3(0, 81985529216486895, 0);
+    test__muldi3(81985529216486895, 0, 0);
+
+    test__muldi3(0, -1, 0);
+    test__muldi3(-1, 0, 0);
+    test__muldi3(0, -10, 0);
+    test__muldi3(-10, 0, 0);
+    test__muldi3(0, -81985529216486895, 0);
+    test__muldi3(-81985529216486895, 0, 0);
+
+    test__muldi3(1, 1, 1);
+    test__muldi3(1, 10, 10);
+    test__muldi3(10, 1, 10);
+    test__muldi3(1, 81985529216486895, 81985529216486895);
+    test__muldi3(81985529216486895, 1, 81985529216486895);
+
+    test__muldi3(1, -1, -1);
+    test__muldi3(1, -10, -10);
+    test__muldi3(-10, 1, -10);
+    test__muldi3(1, -81985529216486895, -81985529216486895);
+    test__muldi3(-81985529216486895, 1, -81985529216486895);
+
+    test__muldi3(3037000499, 3037000499, 9223372030926249001);
+    test__muldi3(-3037000499, 3037000499, -9223372030926249001);
+    test__muldi3(3037000499, -3037000499, -9223372030926249001);
+    test__muldi3(-3037000499, -3037000499, 9223372030926249001);
+
+    test__muldi3(4398046511103, 2097152, 9223372036852678656);
+    test__muldi3(-4398046511103, 2097152, -9223372036852678656);
+    test__muldi3(4398046511103, -2097152, -9223372036852678656);
+    test__muldi3(-4398046511103, -2097152, 9223372036852678656);
+
+    test__muldi3(2097152, 4398046511103, 9223372036852678656);
+    test__muldi3(-2097152, 4398046511103, -9223372036852678656);
+    test__muldi3(2097152, -4398046511103, -9223372036852678656);
+    test__muldi3(-2097152, -4398046511103, 9223372036852678656);
+}
std/special/compiler_rt.zig
@@ -127,6 +127,7 @@ comptime {
     @export("__udivmoddi4", @import("compiler_rt/udivmoddi4.zig").__udivmoddi4, linkage);
     @export("__popcountdi2", @import("compiler_rt/popcountdi2.zig").__popcountdi2, linkage);
 
+    @export("__muldi3", @import("compiler_rt/muldi3.zig").__muldi3, linkage);
     @export("__divmoddi4", __divmoddi4, linkage);
     @export("__divsi3", __divsi3, linkage);
     @export("__divdi3", __divdi3, linkage);
@@ -147,6 +148,8 @@ comptime {
         @export("__aeabi_unwind_cpp_pr1", __aeabi_unwind_cpp_pr1, linkage);
         @export("__aeabi_unwind_cpp_pr2", __aeabi_unwind_cpp_pr2, linkage);
 
+        @export("__aeabi_lmul", @import("compiler_rt/muldi3.zig").__muldi3, linkage);
+
         @export("__aeabi_ldivmod", __aeabi_ldivmod, linkage);
         @export("__aeabi_uldivmod", __aeabi_uldivmod, linkage);
 
test/tests.zig
@@ -170,6 +170,7 @@ pub fn addPkgTests(
     name: []const u8,
     desc: []const u8,
     modes: []const Mode,
+    single_threaded_list: []const bool,
     skip_non_native: bool,
 ) *build.Step {
     const step = b.step(b.fmt("test-{}", name), desc);
@@ -179,7 +180,7 @@ pub fn addPkgTests(
             continue;
         for (modes) |mode| {
             for ([_]bool{ false, true }) |link_libc| {
-                for ([_]bool{ false, true }) |single_threaded| {
+                for (single_threaded_list) |single_threaded| {
                     if (link_libc and !is_native) {
                         // don't assume we have a cross-compiling libc set up
                         continue;
build.zig
@@ -122,16 +122,19 @@ pub fn build(b: *Builder) !void {
     }
     const modes = chosen_modes[0..chosen_mode_index];
 
+    const multi_and_single = [_]bool{ false, true };
+    const just_multi = [_]bool{false};
+
     // run stage1 `zig fmt` on this build.zig file just to make sure it works
     test_step.dependOn(&fmt_build_zig.step);
     const fmt_step = b.step("test-fmt", "Run zig fmt against build.zig to make sure it works");
     fmt_step.dependOn(&fmt_build_zig.step);
 
-    test_step.dependOn(tests.addPkgTests(b, test_filter, "test/stage1/behavior.zig", "behavior", "Run the behavior tests", modes, skip_non_native));
+    test_step.dependOn(tests.addPkgTests(b, test_filter, "test/stage1/behavior.zig", "behavior", "Run the behavior tests", modes, multi_and_single, skip_non_native));
 
-    test_step.dependOn(tests.addPkgTests(b, test_filter, "std/std.zig", "std", "Run the standard library tests", modes, skip_non_native));
+    test_step.dependOn(tests.addPkgTests(b, test_filter, "std/std.zig", "std", "Run the standard library tests", modes, multi_and_single, skip_non_native));
 
-    test_step.dependOn(tests.addPkgTests(b, test_filter, "std/special/compiler_rt.zig", "compiler-rt", "Run the compiler_rt tests", modes, skip_non_native));
+    test_step.dependOn(tests.addPkgTests(b, test_filter, "std/special/compiler_rt.zig", "compiler-rt", "Run the compiler_rt tests", modes, just_multi, skip_non_native));
 
     test_step.dependOn(tests.addCompareOutputTests(b, test_filter, modes));
     test_step.dependOn(tests.addStandaloneTests(b, test_filter, modes));