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