| 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 | |
| 13 | |
| 14 | |
| 15 |
|
| 16 | |
| 17 | |
| 18 | |
| 19 | |
| 20 | |
| 21 | |
| 22 | |
| 23 | |
| 24 | |
| 25 | |
| 26 | |
| 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, |
| 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, |
| 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 | |
| 64 |
|
| 65 | clz yl, r4
|
| 66 | clz ip, xh
|
| 67 | sub yl, yl, ip
|
| 68 | mov ip, |
| 69 | mov ip, ip, lsl yl
|
| 70 | mov yl, r4, lsl yl
|
| 71 |
|
| 72 | |
| 73 |
|
| 74 | mov yl, r4
|
| 75 | mov ip, |
| 76 | 1: cmp yl, |
| 77 | cmpcc yl, xh
|
| 78 | movcc yl, yl, lsl |
| 79 | movcc ip, ip, lsl |
| 80 | bcc 1b
|
| 81 |
|
| 82 | |
| 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 |
| 90 | mov yl, yl, lsr |
| 91 | bne 2b
|
| 92 |
|
| 93 | @ See if we need to handle lower 32-bit result.
|
| 94 | 3: cmp xh, |
| 95 | mov yl, |
| 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, |
| 104 | 4: movs xl, xl, lsl |
| 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 |
| 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, |
| 119 | reteq lr
|
| 120 |
|
| 121 | @ We still have remainer bits in the low part. Bring them up.
|
| 122 |
|
| 123 | |
| 124 |
|
| 125 | clz xh, xl @ we know xh is zero here so...
|
| 126 | add xh, xh, |
| 127 | mov xl, xl, lsl xh
|
| 128 | mov ip, ip, lsr xh
|
| 129 |
|
| 130 | |
| 131 |
|
| 132 | 7: movs xl, xl, lsl |
| 133 | mov ip, ip, lsr |
| 134 | bcc 7b
|
| 135 |
|
| 136 | |
| 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 |
| 143 | mov xh, |
| 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 | |
| 151 |
|
| 152 | clz ip, r4
|
| 153 | rsb ip, ip, |
| 154 |
|
| 155 | |
| 156 |
|
| 157 | mov yl, r4
|
| 158 | cmp r4, |
| 159 | mov ip, |
| 160 | movhs yl, yl, lsr |
| 161 | movhs ip, |
| 162 |
|
| 163 | cmp yl, |
| 164 | movhs yl, yl, lsr |
| 165 | addhs ip, ip, |
| 166 |
|
| 167 | cmp yl, |
| 168 | movhs yl, yl, lsr |
| 169 | addhs ip, ip, |
| 170 |
|
| 171 | cmp yl, |
| 172 | addhi ip, ip, |
| 173 | addls ip, ip, yl, lsr |
| 174 |
|
| 175 | |
| 176 |
|
| 177 | mov yh, xh, lsr ip
|
| 178 | mov yl, xl, lsr ip
|
| 179 | rsb ip, ip, |
| 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, |
| 191 | reteq lr
|
| 192 | UNWIND(.fnend)
|
| 193 |
|
| 194 | UNWIND(.fnstart)
|
| 195 | UNWIND(.pad |
| 196 | UNWIND(.save {lr})
|
| 197 | Ldiv0_64:
|
| 198 | @ Division by 0:
|
| 199 | str lr, [sp, |
| 200 | bl __div0
|
| 201 |
|
| 202 | @ as wrong as it could be...
|
| 203 | mov yl, |
| 204 | mov yh, |
| 205 | mov xh, |
| 206 | ldr pc, [sp], |
| 207 |
|
| 208 | UNWIND(.fnend)
|
| 209 | ENDPROC(__do_div64)
|