Austin Schuh | dace2a6 | 2020-08-18 10:56:48 -0700 | [diff] [blame] | 1 | dnl ARM mpn_udiv_qrnnd -- divide a two limb dividend and a one limb divisor. |
| 2 | dnl Return quotient and store remainder through a supplied pointer. |
| 3 | |
| 4 | dnl Copyright 2001, 2012 Free Software Foundation, Inc. |
| 5 | |
| 6 | dnl This file is part of the GNU MP Library. |
| 7 | dnl |
| 8 | dnl The GNU MP Library is free software; you can redistribute it and/or modify |
| 9 | dnl it under the terms of either: |
| 10 | dnl |
| 11 | dnl * the GNU Lesser General Public License as published by the Free |
| 12 | dnl Software Foundation; either version 3 of the License, or (at your |
| 13 | dnl option) any later version. |
| 14 | dnl |
| 15 | dnl or |
| 16 | dnl |
| 17 | dnl * the GNU General Public License as published by the Free Software |
| 18 | dnl Foundation; either version 2 of the License, or (at your option) any |
| 19 | dnl later version. |
| 20 | dnl |
| 21 | dnl or both in parallel, as here. |
| 22 | dnl |
| 23 | dnl The GNU MP Library is distributed in the hope that it will be useful, but |
| 24 | dnl WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY |
| 25 | dnl or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License |
| 26 | dnl for more details. |
| 27 | dnl |
| 28 | dnl You should have received copies of the GNU General Public License and the |
| 29 | dnl GNU Lesser General Public License along with the GNU MP Library. If not, |
| 30 | dnl see https://www.gnu.org/licenses/. |
| 31 | |
| 32 | include(`../config.m4') |
| 33 | |
| 34 | C INPUT PARAMETERS |
| 35 | define(`rem_ptr',`r0') |
| 36 | define(`n1',`r1') |
| 37 | define(`n0',`r2') |
| 38 | define(`d',`r3') |
| 39 | |
| 40 | C divstep -- develop one quotient bit. Dividend in $1$2, divisor in $3. |
| 41 | C Quotient bit is shifted into $2. |
| 42 | define(`divstep', |
| 43 | `adcs $2, $2, $2 |
| 44 | adc $1, $1, $1 |
| 45 | cmp $1, $3 |
| 46 | subcs $1, $1, $3') |
| 47 | |
| 48 | ASM_START() |
| 49 | PROLOGUE(mpn_udiv_qrnnd) |
| 50 | mov r12, #8 C loop counter for both loops below |
| 51 | cmp d, #0x80000000 C check divisor msb and clear carry |
| 52 | bcs L(_large_divisor) |
| 53 | |
| 54 | L(oop): divstep(n1,n0,d) |
| 55 | divstep(n1,n0,d) |
| 56 | divstep(n1,n0,d) |
| 57 | divstep(n1,n0,d) |
| 58 | sub r12, r12, #1 |
| 59 | teq r12, #0 |
| 60 | bne L(oop) |
| 61 | |
| 62 | str n1, [rem_ptr] C store remainder |
| 63 | adc r0, n0, n0 C quotient: add last carry from divstep |
| 64 | return lr |
| 65 | |
| 66 | L(_large_divisor): |
| 67 | stmfd sp!, { r8, lr } |
| 68 | |
| 69 | and r8, n0, #1 C save lsb of dividend |
| 70 | mov lr, n1, lsl #31 |
| 71 | orrs n0, lr, n0, lsr #1 C n0 = lo(n1n0 >> 1) |
| 72 | mov n1, n1, lsr #1 C n1 = hi(n1n0 >> 1) |
| 73 | |
| 74 | and lr, d, #1 C save lsb of divisor |
| 75 | movs d, d, lsr #1 C d = floor(orig_d / 2) |
| 76 | adc d, d, #0 C d = ceil(orig_d / 2) |
| 77 | |
| 78 | L(oop2): |
| 79 | divstep(n1,n0,d) |
| 80 | divstep(n1,n0,d) |
| 81 | divstep(n1,n0,d) |
| 82 | divstep(n1,n0,d) |
| 83 | sub r12, r12, #1 |
| 84 | teq r12, #0 |
| 85 | bne L(oop2) |
| 86 | |
| 87 | adc n0, n0, n0 C shift and add last carry from divstep |
| 88 | add n1, r8, n1, lsl #1 C shift in omitted dividend lsb |
| 89 | tst lr, lr C test saved divisor lsb |
| 90 | beq L(_even_divisor) |
| 91 | |
| 92 | rsb d, lr, d, lsl #1 C restore orig d value |
| 93 | adds n1, n1, n0 C fix remainder for omitted divisor lsb |
| 94 | addcs n0, n0, #1 C adjust quotient if rem. fix carried |
| 95 | subcs n1, n1, d C adjust remainder accordingly |
| 96 | cmp n1, d C remainder >= divisor? |
| 97 | subcs n1, n1, d C adjust remainder |
| 98 | addcs n0, n0, #1 C adjust quotient |
| 99 | |
| 100 | L(_even_divisor): |
| 101 | str n1, [rem_ptr] C store remainder |
| 102 | mov r0, n0 C quotient |
| 103 | ldmfd sp!, { r8, pc } |
| 104 | EPILOGUE(mpn_udiv_qrnnd) |