aboutsummaryrefslogtreecommitdiff
path: root/lib/std/special/compiler_rt/muldi3.zig
diff options
context:
space:
mode:
Diffstat (limited to 'lib/std/special/compiler_rt/muldi3.zig')
-rw-r--r--lib/std/special/compiler_rt/muldi3.zig54
1 files changed, 54 insertions, 0 deletions
diff --git a/lib/std/special/compiler_rt/muldi3.zig b/lib/std/special/compiler_rt/muldi3.zig
new file mode 100644
index 0000000000..7700777c16
--- /dev/null
+++ b/lib/std/special/compiler_rt/muldi3.zig
@@ -0,0 +1,54 @@
+const builtin = @import("builtin");
+
+// Ported from
+// https://github.com/llvm/llvm-project/blob/llvmorg-9.0.0/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");
+}