mirror of
https://github.com/Rockbox/rockbox.git
synced 2025-11-19 10:02:45 -05:00
Invert divisor earlier in udiv32_arm, allowing the div0 test to be done before entering the 32-bit divide portion of the code, and making the handling of div0 simpler.
git-svn-id: svn://svn.rockbox.org/rockbox/trunk@24166 a1c6a512-1295-4272-9138-f99709370657
This commit is contained in:
parent
6fef14bd16
commit
5313bf52b5
1 changed files with 24 additions and 36 deletions
|
|
@ -44,23 +44,21 @@
|
||||||
has the high bit set, this is fine, everything inside .rept will be
|
has the high bit set, this is fine, everything inside .rept will be
|
||||||
skipped, and the add before and adcs after will set the one-bit result
|
skipped, and the add before and adcs after will set the one-bit result
|
||||||
to zero. */
|
to zero. */
|
||||||
cmp \divisor, \dividend, lsr #16
|
cmn \divisor, \dividend, lsr #16
|
||||||
movls \divisor, \divisor, lsl #16
|
movcs \divisor, \divisor, lsl #16
|
||||||
addls \bits, \bits, #16
|
addcs \bits, \bits, #16
|
||||||
cmp \divisor, \dividend, lsr #8
|
cmn \divisor, \dividend, lsr #8
|
||||||
movls \divisor, \divisor, lsl #8
|
movcs \divisor, \divisor, lsl #8
|
||||||
addls \bits, \bits, #8
|
addcs \bits, \bits, #8
|
||||||
cmp \divisor, \dividend, lsr #4
|
cmn \divisor, \dividend, lsr #4
|
||||||
movls \divisor, \divisor, lsl #4
|
movcs \divisor, \divisor, lsl #4
|
||||||
addls \bits, \bits, #4
|
addcs \bits, \bits, #4
|
||||||
cmp \divisor, \dividend, lsr #2
|
cmn \divisor, \dividend, lsr #2
|
||||||
movls \divisor, \divisor, lsl #2
|
movcs \divisor, \divisor, lsl #2
|
||||||
addls \bits, \bits, #2
|
addcs \bits, \bits, #2
|
||||||
cmp \divisor, \dividend, lsr #1
|
cmn \divisor, \dividend, lsr #1
|
||||||
movls \divisor, \divisor, lsl #1
|
movcs \divisor, \divisor, lsl #1
|
||||||
addls \bits, \bits, #1
|
addcs \bits, \bits, #1
|
||||||
rsbs \divisor, \divisor, #0
|
|
||||||
bcs .L_div0
|
|
||||||
adds \result, \dividend, \divisor
|
adds \result, \dividend, \divisor
|
||||||
subcc \result, \result, \divisor
|
subcc \result, \result, \divisor
|
||||||
rsb \curbit, \bits, #31
|
rsb \curbit, \bits, #31
|
||||||
|
|
@ -88,6 +86,13 @@
|
||||||
.type udiv32_arm,%function
|
.type udiv32_arm,%function
|
||||||
|
|
||||||
udiv32_arm:
|
udiv32_arm:
|
||||||
|
/* Invert divisor. ARM_DIV_31_BODY uses adc to both subtract the divisor
|
||||||
|
and add the next bit of the result. The correction code at .L_udiv32
|
||||||
|
does not need the divisor inverted, but can be modified to work with it,
|
||||||
|
and this allows the zero divisor test to be done early and without an
|
||||||
|
explicit comparison. */
|
||||||
|
rsbs r1, r1, #0
|
||||||
|
beq .L_div0
|
||||||
tst r0, r0
|
tst r0, r0
|
||||||
/* High bit must be unset, otherwise shift numerator right, calculate,
|
/* High bit must be unset, otherwise shift numerator right, calculate,
|
||||||
and correct results. As this case is very uncommon we want to avoid
|
and correct results. As this case is very uncommon we want to avoid
|
||||||
|
|
@ -106,9 +111,6 @@ udiv32_arm:
|
||||||
address. */
|
address. */
|
||||||
mov r0, r0, lsr #1
|
mov r0, r0, lsr #1
|
||||||
bl .L_udiv31
|
bl .L_udiv31
|
||||||
/* This address is never a branch target, but is used to test lr before
|
|
||||||
calling __div0. */
|
|
||||||
.L_udiv32_div0_trap:
|
|
||||||
ldmdb sp, { r2, r3, lr }
|
ldmdb sp, { r2, r3, lr }
|
||||||
/* Move the low bit of the original numerator to the carry bit */
|
/* Move the low bit of the original numerator to the carry bit */
|
||||||
movs r2, r2, lsr #1
|
movs r2, r2, lsr #1
|
||||||
|
|
@ -116,26 +118,12 @@ udiv32_arm:
|
||||||
adc r1, r1, r1
|
adc r1, r1, r1
|
||||||
/* Subtract the original divisor from the remainder, setting carry if the
|
/* Subtract the original divisor from the remainder, setting carry if the
|
||||||
result is non-negative */
|
result is non-negative */
|
||||||
subs r1, r1, r3
|
adds r1, r1, r3
|
||||||
/* Shift quotient left one and add carry bit */
|
/* Shift quotient left one and add carry bit */
|
||||||
adc r0, r0, r0
|
adc r0, r0, r0
|
||||||
bx lr
|
bx lr
|
||||||
.L_div0:
|
.L_div0:
|
||||||
/* Check the return address, since .L_udiv32 uses bl to wrap the 31-bit
|
/* __div0 expects the calling address on the top of the stack */
|
||||||
divider. If the return address is at .L_udiv32_div0_trap, then the
|
|
||||||
the return address of the original caller is at sp - 4
|
|
||||||
*/
|
|
||||||
adr r2, .L_udiv32_div0_trap
|
|
||||||
cmp r2, lr
|
|
||||||
subeq sp, sp, #4
|
|
||||||
#if defined(__ARM_EABI__) || !defined(USE_IRAM)
|
|
||||||
bleq __div0
|
|
||||||
#else
|
|
||||||
ldr r3, =__div0
|
|
||||||
moveq lr, pc
|
|
||||||
bxeq r3
|
|
||||||
#endif
|
|
||||||
/* Otherwise, push lr to the stack before calling __div0 */
|
|
||||||
stmdb sp!, { lr }
|
stmdb sp!, { lr }
|
||||||
#if defined(__ARM_EABI__) || !defined(USE_IRAM)
|
#if defined(__ARM_EABI__) || !defined(USE_IRAM)
|
||||||
bl __div0
|
bl __div0
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue