Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0
0002 #include <linux/export.h>
0003 
0004 #include "libgcc.h"
0005 
0006 /*
0007  * GCC 7 & older can suboptimally generate __multi3 calls for mips64r6, so for
0008  * that specific case only we implement that intrinsic here.
0009  *
0010  * See https://gcc.gnu.org/bugzilla/show_bug.cgi?id=82981
0011  */
0012 #if defined(CONFIG_64BIT) && defined(CONFIG_CPU_MIPSR6) && (__GNUC__ < 8)
0013 
0014 /* multiply 64-bit values, low 64-bits returned */
0015 static inline long long notrace dmulu(long long a, long long b)
0016 {
0017     long long res;
0018 
0019     asm ("dmulu %0,%1,%2" : "=r" (res) : "r" (a), "r" (b));
0020     return res;
0021 }
0022 
0023 /* multiply 64-bit unsigned values, high 64-bits of 128-bit result returned */
0024 static inline long long notrace dmuhu(long long a, long long b)
0025 {
0026     long long res;
0027 
0028     asm ("dmuhu %0,%1,%2" : "=r" (res) : "r" (a), "r" (b));
0029     return res;
0030 }
0031 
0032 /* multiply 128-bit values, low 128-bits returned */
0033 ti_type notrace __multi3(ti_type a, ti_type b)
0034 {
0035     TWunion res, aa, bb;
0036 
0037     aa.ti = a;
0038     bb.ti = b;
0039 
0040     /*
0041      * a * b =           (a.lo * b.lo)
0042      *         + 2^64  * (a.hi * b.lo + a.lo * b.hi)
0043      *        [+ 2^128 * (a.hi * b.hi)]
0044      */
0045     res.s.low = dmulu(aa.s.low, bb.s.low);
0046     res.s.high = dmuhu(aa.s.low, bb.s.low);
0047     res.s.high += dmulu(aa.s.high, bb.s.low);
0048     res.s.high += dmulu(aa.s.low, bb.s.high);
0049 
0050     return res.ti;
0051 }
0052 EXPORT_SYMBOL(__multi3);
0053 
0054 #endif /* 64BIT && CPU_MIPSR6 && GCC7 */