muldi3.c (1679B)
1// SPDX-License-Identifier: GPL-2.0 2#include <linux/export.h> 3 4#include "libgcc.h" 5 6#define W_TYPE_SIZE 32 7 8#define __ll_B ((unsigned long) 1 << (W_TYPE_SIZE / 2)) 9#define __ll_lowpart(t) ((unsigned long) (t) & (__ll_B - 1)) 10#define __ll_highpart(t) ((unsigned long) (t) >> (W_TYPE_SIZE / 2)) 11 12/* If we still don't have umul_ppmm, define it using plain C. */ 13#if !defined(umul_ppmm) 14#define umul_ppmm(w1, w0, u, v) \ 15 do { \ 16 unsigned long __x0, __x1, __x2, __x3; \ 17 unsigned short __ul, __vl, __uh, __vh; \ 18 \ 19 __ul = __ll_lowpart(u); \ 20 __uh = __ll_highpart(u); \ 21 __vl = __ll_lowpart(v); \ 22 __vh = __ll_highpart(v); \ 23 \ 24 __x0 = (unsigned long) __ul * __vl; \ 25 __x1 = (unsigned long) __ul * __vh; \ 26 __x2 = (unsigned long) __uh * __vl; \ 27 __x3 = (unsigned long) __uh * __vh; \ 28 \ 29 __x1 += __ll_highpart(__x0); /* this can't give carry */\ 30 __x1 += __x2; /* but this indeed can */ \ 31 if (__x1 < __x2) /* did we get it? */ \ 32 __x3 += __ll_B; /* yes, add it in the proper pos */ \ 33 \ 34 (w1) = __x3 + __ll_highpart(__x1); \ 35 (w0) = __ll_lowpart(__x1) * __ll_B + __ll_lowpart(__x0);\ 36 } while (0) 37#endif 38 39#if !defined(__umulsidi3) 40#define __umulsidi3(u, v) ({ \ 41 DWunion __w; \ 42 umul_ppmm(__w.s.high, __w.s.low, u, v); \ 43 __w.ll; \ 44 }) 45#endif 46 47long long __muldi3(long long u, long long v) 48{ 49 const DWunion uu = {.ll = u}; 50 const DWunion vv = {.ll = v}; 51 DWunion w = {.ll = __umulsidi3(uu.s.low, vv.s.low)}; 52 53 w.s.high += ((unsigned long) uu.s.low * (unsigned long) vv.s.high 54 + (unsigned long) uu.s.high * (unsigned long) vv.s.low); 55 56 return w.ll; 57} 58EXPORT_SYMBOL(__muldi3);