1const builtin = @import("builtin");
2const std = @import("std");
3const testing = std.testing;
4const compiler_rt = @import("../compiler_rt.zig");
5const symbol = compiler_rt.symbol;
6const native_endian = builtin.cpu.arch.endian();
7
8comptime {
9 symbol(&__mulsi3, "__mulsi3");
10 if (compiler_rt.want_aeabi) {
11 symbol(&__aeabi_lmul, "__aeabi_lmul");
12 } else {
13 symbol(&__muldi3, "__muldi3");
14 }
15 symbol(&__multi3, "__multi3");
16}
17
18pub fn __mulsi3(a: i32, b: i32) callconv(.c) i32 {
19 var ua: u32 = @bitCast(a);
20 var ub: u32 = @bitCast(b);
21 var r: u32 = 0;
22
23 while (ua > 0) {
24 if ((ua & 1) != 0) r +%= ub;
25 ua >>= 1;
26 ub <<= 1;
27 }
28
29 return @bitCast(r);
30}
31
32pub fn __muldi3(a: i64, b: i64) callconv(.c) i64 {
33 return mulX(i64, a, b);
34}
35
36fn __aeabi_lmul(a: i64, b: i64) callconv(.{ .arm_aapcs = .{} }) i64 {
37 return mulX(i64, a, b);
38}
39
40inline fn mulX(comptime T: type, a: T, b: T) T {
41 const word_t = compiler_rt.HalveInt(T, false);
42 const x = word_t{ .all = a };
43 const y = word_t{ .all = b };
44 var r = switch (T) {
45 i64, i128 => word_t{ .all = muldXi(word_t.HalfT, x.s.low, y.s.low) },
46 else => unreachable,
47 };
48 r.s.high +%= x.s.high *% y.s.low +% x.s.low *% y.s.high;
49 return r.all;
50}
51
52fn DoubleInt(comptime T: type) type {
53 return switch (T) {
54 u32 => i64,
55 u64 => i128,
56 i32 => i64,
57 i64 => i128,
58 else => unreachable,
59 };
60}
61
62pub fn muldXi(comptime T: type, a: T, b: T) DoubleInt(T) {
63 const DT = DoubleInt(T);
64 const word_t = compiler_rt.HalveInt(DT, false);
65 const bits_in_word_2 = @sizeOf(T) * 8 / 2;
66 const lower_mask = (~@as(T, 0)) >> bits_in_word_2;
67
68 var r: word_t = undefined;
69 r.s.low = (a & lower_mask) *% (b & lower_mask);
70 var t: T = r.s.low >> bits_in_word_2;
71 r.s.low &= lower_mask;
72 t += (a >> bits_in_word_2) *% (b & lower_mask);
73 r.s.low +%= (t & lower_mask) << bits_in_word_2;
74 r.s.high = t >> bits_in_word_2;
75 t = r.s.low >> bits_in_word_2;
76 r.s.low &= lower_mask;
77 t +%= (b >> bits_in_word_2) *% (a & lower_mask);
78 r.s.low +%= (t & lower_mask) << bits_in_word_2;
79 r.s.high +%= t >> bits_in_word_2;
80 r.s.high +%= (a >> bits_in_word_2) *% (b >> bits_in_word_2);
81 return r.all;
82}
83
84pub fn __multi3(a: i128, b: i128) callconv(.c) i128 {
85 return mulX(i128, a, b);
86}
87
88test {
89 _ = @import("mulXi3_test.zig");
90}