xref: /openbmc/linux/arch/microblaze/lib/muldi3.c (revision 498495dba268b20e8eadd7fe93c140c68b6cc9d2)
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