1*b2441318SGreg Kroah-Hartman // SPDX-License-Identifier: GPL-2.0
2d64af918SMichal Simek #include <linux/export.h>
33370d82fSMichal Simek
43370d82fSMichal Simek #include "libgcc.h"
53370d82fSMichal Simek
63370d82fSMichal Simek #define W_TYPE_SIZE 32
73370d82fSMichal Simek
8a671de08SMichal Simek #define __ll_B ((unsigned long) 1 << (W_TYPE_SIZE / 2))
9a671de08SMichal Simek #define __ll_lowpart(t) ((unsigned long) (t) & (__ll_B - 1))
10a671de08SMichal Simek #define __ll_highpart(t) ((unsigned long) (t) >> (W_TYPE_SIZE / 2))
113370d82fSMichal Simek
123370d82fSMichal Simek /* If we still don't have umul_ppmm, define it using plain C. */
133370d82fSMichal Simek #if !defined(umul_ppmm)
143370d82fSMichal Simek #define umul_ppmm(w1, w0, u, v) \
153370d82fSMichal Simek do { \
16a671de08SMichal Simek unsigned long __x0, __x1, __x2, __x3; \
17a671de08SMichal Simek unsigned short __ul, __vl, __uh, __vh; \
183370d82fSMichal Simek \
193370d82fSMichal Simek __ul = __ll_lowpart(u); \
203370d82fSMichal Simek __uh = __ll_highpart(u); \
213370d82fSMichal Simek __vl = __ll_lowpart(v); \
223370d82fSMichal Simek __vh = __ll_highpart(v); \
233370d82fSMichal Simek \
24a671de08SMichal Simek __x0 = (unsigned long) __ul * __vl; \
25a671de08SMichal Simek __x1 = (unsigned long) __ul * __vh; \
26a671de08SMichal Simek __x2 = (unsigned long) __uh * __vl; \
27a671de08SMichal Simek __x3 = (unsigned long) __uh * __vh; \
283370d82fSMichal Simek \
293370d82fSMichal Simek __x1 += __ll_highpart(__x0); /* this can't give carry */\
303370d82fSMichal Simek __x1 += __x2; /* but this indeed can */ \
313370d82fSMichal Simek if (__x1 < __x2) /* did we get it? */ \
323370d82fSMichal Simek __x3 += __ll_B; /* yes, add it in the proper pos */ \
333370d82fSMichal Simek \
343370d82fSMichal Simek (w1) = __x3 + __ll_highpart(__x1); \
353370d82fSMichal Simek (w0) = __ll_lowpart(__x1) * __ll_B + __ll_lowpart(__x0);\
363370d82fSMichal Simek } while (0)
373370d82fSMichal Simek #endif
383370d82fSMichal Simek
393370d82fSMichal Simek #if !defined(__umulsidi3)
403370d82fSMichal Simek #define __umulsidi3(u, v) ({ \
413370d82fSMichal Simek DWunion __w; \
423370d82fSMichal Simek umul_ppmm(__w.s.high, __w.s.low, u, v); \
433370d82fSMichal Simek __w.ll; \
443370d82fSMichal Simek })
453370d82fSMichal Simek #endif
463370d82fSMichal Simek
__muldi3(long long u,long long v)47a671de08SMichal Simek long long __muldi3(long long u, long long v)
483370d82fSMichal Simek {
493370d82fSMichal Simek const DWunion uu = {.ll = u};
503370d82fSMichal Simek const DWunion vv = {.ll = v};
513370d82fSMichal Simek DWunion w = {.ll = __umulsidi3(uu.s.low, vv.s.low)};
523370d82fSMichal Simek
53a671de08SMichal Simek w.s.high += ((unsigned long) uu.s.low * (unsigned long) vv.s.high
54a671de08SMichal Simek + (unsigned long) uu.s.high * (unsigned long) vv.s.low);
553370d82fSMichal Simek
563370d82fSMichal Simek return w.ll;
573370d82fSMichal Simek }
58d50c3036SMichal Simek EXPORT_SYMBOL(__muldi3);
59