~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~

TOMOYO Linux Cross Reference
Linux/arch/arm/include/asm/div64.h

Version: ~ [ linux-5.5-rc1 ] ~ [ linux-5.4.2 ] ~ [ linux-5.3.15 ] ~ [ linux-5.2.21 ] ~ [ linux-5.1.21 ] ~ [ linux-5.0.21 ] ~ [ linux-4.20.17 ] ~ [ linux-4.19.88 ] ~ [ linux-4.18.20 ] ~ [ linux-4.17.19 ] ~ [ linux-4.16.18 ] ~ [ linux-4.15.18 ] ~ [ linux-4.14.158 ] ~ [ linux-4.13.16 ] ~ [ linux-4.12.14 ] ~ [ linux-4.11.12 ] ~ [ linux-4.10.17 ] ~ [ linux-4.9.206 ] ~ [ linux-4.8.17 ] ~ [ linux-4.7.10 ] ~ [ linux-4.6.7 ] ~ [ linux-4.5.7 ] ~ [ linux-4.4.206 ] ~ [ linux-4.3.6 ] ~ [ linux-4.2.8 ] ~ [ linux-4.1.52 ] ~ [ linux-4.0.9 ] ~ [ linux-3.19.8 ] ~ [ linux-3.18.140 ] ~ [ linux-3.17.8 ] ~ [ linux-3.16.78 ] ~ [ linux-3.15.10 ] ~ [ linux-3.14.79 ] ~ [ linux-3.13.11 ] ~ [ linux-3.12.74 ] ~ [ linux-3.11.10 ] ~ [ linux-3.10.108 ] ~ [ linux-3.9.11 ] ~ [ linux-3.8.13 ] ~ [ linux-3.7.10 ] ~ [ linux-3.6.11 ] ~ [ linux-3.5.7 ] ~ [ linux-3.4.113 ] ~ [ linux-3.3.8 ] ~ [ linux-3.2.102 ] ~ [ linux-3.1.10 ] ~ [ linux-3.0.101 ] ~ [ linux-2.6.32.71 ] ~ [ linux-2.6.0 ] ~ [ linux-2.4.37.11 ] ~ [ unix-v6-master ] ~ [ ccs-tools-1.8.5 ] ~ [ policy-sample ] ~
Architecture: ~ [ i386 ] ~ [ alpha ] ~ [ m68k ] ~ [ mips ] ~ [ ppc ] ~ [ sparc ] ~ [ sparc64 ] ~

  1 /* SPDX-License-Identifier: GPL-2.0 */
  2 #ifndef __ASM_ARM_DIV64
  3 #define __ASM_ARM_DIV64
  4 
  5 #include <linux/types.h>
  6 #include <asm/compiler.h>
  7 
  8 /*
  9  * The semantics of __div64_32() are:
 10  *
 11  * uint32_t __div64_32(uint64_t *n, uint32_t base)
 12  * {
 13  *      uint32_t remainder = *n % base;
 14  *      *n = *n / base;
 15  *      return remainder;
 16  * }
 17  *
 18  * In other words, a 64-bit dividend with a 32-bit divisor producing
 19  * a 64-bit result and a 32-bit remainder.  To accomplish this optimally
 20  * we override the generic version in lib/div64.c to call our __do_div64
 21  * assembly implementation with completely non standard calling convention
 22  * for arguments and results (beware).
 23  */
 24 
 25 #ifdef __ARMEB__
 26 #define __xh "r0"
 27 #define __xl "r1"
 28 #else
 29 #define __xl "r0"
 30 #define __xh "r1"
 31 #endif
 32 
 33 static inline uint32_t __div64_32(uint64_t *n, uint32_t base)
 34 {
 35         register unsigned int __base      asm("r4") = base;
 36         register unsigned long long __n   asm("r0") = *n;
 37         register unsigned long long __res asm("r2");
 38         register unsigned int __rem       asm(__xh);
 39         asm(    __asmeq("%0", __xh)
 40                 __asmeq("%1", "r2")
 41                 __asmeq("%2", "r0")
 42                 __asmeq("%3", "r4")
 43                 "bl     __do_div64"
 44                 : "=r" (__rem), "=r" (__res)
 45                 : "r" (__n), "r" (__base)
 46                 : "ip", "lr", "cc");
 47         *n = __res;
 48         return __rem;
 49 }
 50 #define __div64_32 __div64_32
 51 
 52 #if !defined(CONFIG_AEABI)
 53 
 54 /*
 55  * In OABI configurations, some uses of the do_div function
 56  * cause gcc to run out of registers. To work around that,
 57  * we can force the use of the out-of-line version for
 58  * configurations that build a OABI kernel.
 59  */
 60 #define do_div(n, base) __div64_32(&(n), base)
 61 
 62 #else
 63 
 64 /*
 65  * gcc versions earlier than 4.0 are simply too problematic for the
 66  * __div64_const32() code in asm-generic/div64.h. First there is
 67  * gcc PR 15089 that tend to trig on more complex constructs, spurious
 68  * .global __udivsi3 are inserted even if none of those symbols are
 69  * referenced in the generated code, and those gcc versions are not able
 70  * to do constant propagation on long long values anyway.
 71  */
 72 
 73 #define __div64_const32_is_OK (__GNUC__ >= 4)
 74 
 75 static inline uint64_t __arch_xprod_64(uint64_t m, uint64_t n, bool bias)
 76 {
 77         unsigned long long res;
 78         register unsigned int tmp asm("ip") = 0;
 79 
 80         if (!bias) {
 81                 asm (   "umull  %Q0, %R0, %Q1, %Q2\n\t"
 82                         "mov    %Q0, #0"
 83                         : "=&r" (res)
 84                         : "r" (m), "r" (n)
 85                         : "cc");
 86         } else if (!(m & ((1ULL << 63) | (1ULL << 31)))) {
 87                 res = m;
 88                 asm (   "umlal  %Q0, %R0, %Q1, %Q2\n\t"
 89                         "mov    %Q0, #0"
 90                         : "+&r" (res)
 91                         : "r" (m), "r" (n)
 92                         : "cc");
 93         } else {
 94                 asm (   "umull  %Q0, %R0, %Q2, %Q3\n\t"
 95                         "cmn    %Q0, %Q2\n\t"
 96                         "adcs   %R0, %R0, %R2\n\t"
 97                         "adc    %Q0, %1, #0"
 98                         : "=&r" (res), "+&r" (tmp)
 99                         : "r" (m), "r" (n)
100                         : "cc");
101         }
102 
103         if (!(m & ((1ULL << 63) | (1ULL << 31)))) {
104                 asm (   "umlal  %R0, %Q0, %R1, %Q2\n\t"
105                         "umlal  %R0, %Q0, %Q1, %R2\n\t"
106                         "mov    %R0, #0\n\t"
107                         "umlal  %Q0, %R0, %R1, %R2"
108                         : "+&r" (res)
109                         : "r" (m), "r" (n)
110                         : "cc");
111         } else {
112                 asm (   "umlal  %R0, %Q0, %R2, %Q3\n\t"
113                         "umlal  %R0, %1, %Q2, %R3\n\t"
114                         "mov    %R0, #0\n\t"
115                         "adds   %Q0, %1, %Q0\n\t"
116                         "adc    %R0, %R0, #0\n\t"
117                         "umlal  %Q0, %R0, %R2, %R3"
118                         : "+&r" (res), "+&r" (tmp)
119                         : "r" (m), "r" (n)
120                         : "cc");
121         }
122 
123         return res;
124 }
125 #define __arch_xprod_64 __arch_xprod_64
126 
127 #include <asm-generic/div64.h>
128 
129 #endif
130 
131 #endif
132 

~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~

kernel.org | git.kernel.org | LWN.net | Project Home | Wiki (Japanese) | Wiki (English) | SVN repository | Mail admin

Linux® is a registered trademark of Linus Torvalds in the United States and other countries.
TOMOYO® is a registered trademark of NTT DATA CORPORATION.

osdn.jp