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

TOMOYO Linux Cross Reference
Linux/arch/arm/lib/div64.S

Version: ~ [ linux-6.11-rc3 ] ~ [ linux-6.10.4 ] ~ [ linux-6.9.12 ] ~ [ linux-6.8.12 ] ~ [ linux-6.7.12 ] ~ [ linux-6.6.45 ] ~ [ linux-6.5.13 ] ~ [ linux-6.4.16 ] ~ [ linux-6.3.13 ] ~ [ linux-6.2.16 ] ~ [ linux-6.1.104 ] ~ [ linux-6.0.19 ] ~ [ linux-5.19.17 ] ~ [ linux-5.18.19 ] ~ [ linux-5.17.15 ] ~ [ linux-5.16.20 ] ~ [ linux-5.15.164 ] ~ [ linux-5.14.21 ] ~ [ linux-5.13.19 ] ~ [ linux-5.12.19 ] ~ [ linux-5.11.22 ] ~ [ linux-5.10.223 ] ~ [ linux-5.9.16 ] ~ [ linux-5.8.18 ] ~ [ linux-5.7.19 ] ~ [ linux-5.6.19 ] ~ [ linux-5.5.19 ] ~ [ linux-5.4.281 ] ~ [ linux-5.3.18 ] ~ [ linux-5.2.21 ] ~ [ linux-5.1.21 ] ~ [ linux-5.0.21 ] ~ [ linux-4.20.17 ] ~ [ linux-4.19.319 ] ~ [ linux-4.18.20 ] ~ [ linux-4.17.19 ] ~ [ linux-4.16.18 ] ~ [ linux-4.15.18 ] ~ [ linux-4.14.336 ] ~ [ linux-4.13.16 ] ~ [ linux-4.12.14 ] ~ [ linux-4.11.12 ] ~ [ linux-4.10.17 ] ~ [ linux-4.9.337 ] ~ [ linux-4.4.302 ] ~ [ linux-3.10.108 ] ~ [ linux-2.6.32.71 ] ~ [ linux-2.6.0 ] ~ [ linux-2.4.37.11 ] ~ [ unix-v6-master ] ~ [ ccs-tools-1.8.9 ] ~ [ policy-sample ] ~
Architecture: ~ [ i386 ] ~ [ alpha ] ~ [ m68k ] ~ [ mips ] ~ [ ppc ] ~ [ sparc ] ~ [ sparc64 ] ~

  1 /* SPDX-License-Identifier: GPL-2.0-only */
  2 /*
  3  *  linux/arch/arm/lib/div64.S
  4  *
  5  *  Optimized computation of 64-bit dividend / 32-bit divisor
  6  *
  7  *  Author:     Nicolas Pitre
  8  *  Created:    Oct 5, 2003
  9  *  Copyright:  Monta Vista Software, Inc.
 10  */
 11 
 12 #include <linux/linkage.h>
 13 #include <asm/assembler.h>
 14 #include <asm/unwind.h>
 15 
 16 #ifdef __ARMEB__
 17 #define xh r0
 18 #define xl r1
 19 #define yh r2
 20 #define yl r3
 21 #else
 22 #define xl r0
 23 #define xh r1
 24 #define yl r2
 25 #define yh r3
 26 #endif
 27 
 28 /*
 29  * __do_div64: perform a division with 64-bit dividend and 32-bit divisor.
 30  *
 31  * Note: Calling convention is totally non standard for optimal code.
 32  *       This is meant to be used by do_div() from include/asm/div64.h only.
 33  *
 34  * Input parameters:
 35  *      xh-xl   = dividend (clobbered)
 36  *      r4      = divisor (preserved)
 37  *
 38  * Output values:
 39  *      yh-yl   = result
 40  *      xh      = remainder
 41  *
 42  * Clobbered regs: xl, ip
 43  */
 44 
 45 ENTRY(__do_div64)
 46 UNWIND(.fnstart)
 47 
 48         @ Test for easy paths first.
 49         subs    ip, r4, #1
 50         bls     9f                      @ divisor is 0 or 1
 51         tst     ip, r4
 52         beq     8f                      @ divisor is power of 2
 53 
 54         @ See if we need to handle upper 32-bit result.
 55         cmp     xh, r4
 56         mov     yh, #0
 57         blo     3f
 58 
 59         @ Align divisor with upper part of dividend.
 60         @ The aligned divisor is stored in yl preserving the original.
 61         @ The bit position is stored in ip.
 62 
 63 #if __LINUX_ARM_ARCH__ >= 5
 64 
 65         clz     yl, r4
 66         clz     ip, xh
 67         sub     yl, yl, ip
 68         mov     ip, #1
 69         mov     ip, ip, lsl yl
 70         mov     yl, r4, lsl yl
 71 
 72 #else
 73 
 74         mov     yl, r4
 75         mov     ip, #1
 76 1:      cmp     yl, #0x80000000
 77         cmpcc   yl, xh
 78         movcc   yl, yl, lsl #1
 79         movcc   ip, ip, lsl #1
 80         bcc     1b
 81 
 82 #endif
 83 
 84         @ The division loop for needed upper bit positions.
 85         @ Break out early if dividend reaches 0.
 86 2:      cmp     xh, yl
 87         orrcs   yh, yh, ip
 88         subscs  xh, xh, yl
 89         movsne  ip, ip, lsr #1
 90         mov     yl, yl, lsr #1
 91         bne     2b
 92 
 93         @ See if we need to handle lower 32-bit result.
 94 3:      cmp     xh, #0
 95         mov     yl, #0
 96         cmpeq   xl, r4
 97         movlo   xh, xl
 98         retlo   lr
 99 
100         @ The division loop for lower bit positions.
101         @ Here we shift remainer bits leftwards rather than moving the
102         @ divisor for comparisons, considering the carry-out bit as well.
103         mov     ip, #0x80000000
104 4:      movs    xl, xl, lsl #1
105         adcs    xh, xh, xh
106         beq     6f
107         cmpcc   xh, r4
108 5:      orrcs   yl, yl, ip
109         subcs   xh, xh, r4
110         movs    ip, ip, lsr #1
111         bne     4b
112         ret     lr
113 
114         @ The top part of remainder became zero.  If carry is set
115         @ (the 33th bit) this is a false positive so resume the loop.
116         @ Otherwise, if lower part is also null then we are done.
117 6:      bcs     5b
118         cmp     xl, #0
119         reteq   lr
120 
121         @ We still have remainer bits in the low part.  Bring them up.
122 
123 #if __LINUX_ARM_ARCH__ >= 5
124 
125         clz     xh, xl                  @ we know xh is zero here so...
126         add     xh, xh, #1
127         mov     xl, xl, lsl xh
128         mov     ip, ip, lsr xh
129 
130 #else
131 
132 7:      movs    xl, xl, lsl #1
133         mov     ip, ip, lsr #1
134         bcc     7b
135 
136 #endif
137 
138         @ Current remainder is now 1.  It is worthless to compare with
139         @ divisor at this point since divisor can not be smaller than 3 here.
140         @ If possible, branch for another shift in the division loop.
141         @ If no bit position left then we are done.
142         movs    ip, ip, lsr #1
143         mov     xh, #1
144         bne     4b
145         ret     lr
146 
147 8:      @ Division by a power of 2: determine what that divisor order is
148         @ then simply shift values around
149 
150 #if __LINUX_ARM_ARCH__ >= 5
151 
152         clz     ip, r4
153         rsb     ip, ip, #31
154 
155 #else
156 
157         mov     yl, r4
158         cmp     r4, #(1 << 16)
159         mov     ip, #0
160         movhs   yl, yl, lsr #16
161         movhs   ip, #16
162 
163         cmp     yl, #(1 << 8)
164         movhs   yl, yl, lsr #8
165         addhs   ip, ip, #8
166 
167         cmp     yl, #(1 << 4)
168         movhs   yl, yl, lsr #4
169         addhs   ip, ip, #4
170 
171         cmp     yl, #(1 << 2)
172         addhi   ip, ip, #3
173         addls   ip, ip, yl, lsr #1
174 
175 #endif
176 
177         mov     yh, xh, lsr ip
178         mov     yl, xl, lsr ip
179         rsb     ip, ip, #32
180  ARM(   orr     yl, yl, xh, lsl ip      )
181  THUMB( lsl     xh, xh, ip              )
182  THUMB( orr     yl, yl, xh              )
183         mov     xh, xl, lsl ip
184         mov     xh, xh, lsr ip
185         ret     lr
186 
187         @ eq -> division by 1: obvious enough...
188 9:      moveq   yl, xl
189         moveq   yh, xh
190         moveq   xh, #0
191         reteq   lr
192 UNWIND(.fnend)
193 
194 UNWIND(.fnstart)
195 UNWIND(.pad #4)
196 UNWIND(.save {lr})
197 Ldiv0_64:
198         @ Division by 0:
199         str     lr, [sp, #-8]!
200         bl      __div0
201 
202         @ as wrong as it could be...
203         mov     yl, #0
204         mov     yh, #0
205         mov     xh, #0
206         ldr     pc, [sp], #8
207 
208 UNWIND(.fnend)
209 ENDPROC(__do_div64)

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

kernel.org | git.kernel.org | LWN.net | Project Home | 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.

sflogo.php