diff options
Diffstat (limited to 'lib/std/special/compiler_rt/muldi3.zig')
| -rw-r--r-- | lib/std/special/compiler_rt/muldi3.zig | 54 |
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"); +} |
