summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAndrew Mahone <andrew.mahone@gmail.com>2010-01-03 15:57:03 +0000
committerAndrew Mahone <andrew.mahone@gmail.com>2010-01-03 15:57:03 +0000
commit5313bf52b54c7a02222b1787f8432f43a76e0056 (patch)
treedbebcc790b1d0b9a3f34fed48b41e1d0fddb2d7e
parent6fef14bd16a8ca6e9edf4a16a401a8153282f809 (diff)
downloadrockbox-5313bf52b54c7a02222b1787f8432f43a76e0056.tar.gz
rockbox-5313bf52b54c7a02222b1787f8432f43a76e0056.tar.bz2
rockbox-5313bf52b54c7a02222b1787f8432f43a76e0056.zip
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
-rw-r--r--apps/codecs/lib/udiv32_armv4.S60
1 files changed, 24 insertions, 36 deletions
diff --git a/apps/codecs/lib/udiv32_armv4.S b/apps/codecs/lib/udiv32_armv4.S
index ae2bddb20e..c4aea14093 100644
--- a/apps/codecs/lib/udiv32_armv4.S
+++ b/apps/codecs/lib/udiv32_armv4.S
@@ -44,23 +44,21 @@
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
to zero. */
- cmp \divisor, \dividend, lsr #16
- movls \divisor, \divisor, lsl #16
- addls \bits, \bits, #16
- cmp \divisor, \dividend, lsr #8
- movls \divisor, \divisor, lsl #8
- addls \bits, \bits, #8
- cmp \divisor, \dividend, lsr #4
- movls \divisor, \divisor, lsl #4
- addls \bits, \bits, #4
- cmp \divisor, \dividend, lsr #2
- movls \divisor, \divisor, lsl #2
- addls \bits, \bits, #2
- cmp \divisor, \dividend, lsr #1
- movls \divisor, \divisor, lsl #1
- addls \bits, \bits, #1
- rsbs \divisor, \divisor, #0
- bcs .L_div0
+ cmn \divisor, \dividend, lsr #16
+ movcs \divisor, \divisor, lsl #16
+ addcs \bits, \bits, #16
+ cmn \divisor, \dividend, lsr #8
+ movcs \divisor, \divisor, lsl #8
+ addcs \bits, \bits, #8
+ cmn \divisor, \dividend, lsr #4
+ movcs \divisor, \divisor, lsl #4
+ addcs \bits, \bits, #4
+ cmn \divisor, \dividend, lsr #2
+ movcs \divisor, \divisor, lsl #2
+ addcs \bits, \bits, #2
+ cmn \divisor, \dividend, lsr #1
+ movcs \divisor, \divisor, lsl #1
+ addcs \bits, \bits, #1
adds \result, \dividend, \divisor
subcc \result, \result, \divisor
rsb \curbit, \bits, #31
@@ -88,6 +86,13 @@
.type udiv32_arm,%function
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
/* High bit must be unset, otherwise shift numerator right, calculate,
and correct results. As this case is very uncommon we want to avoid
@@ -106,9 +111,6 @@ udiv32_arm:
address. */
mov r0, r0, lsr #1
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 }
/* Move the low bit of the original numerator to the carry bit */
movs r2, r2, lsr #1
@@ -116,26 +118,12 @@ udiv32_arm:
adc r1, r1, r1
/* Subtract the original divisor from the remainder, setting carry if the
result is non-negative */
- subs r1, r1, r3
+ adds r1, r1, r3
/* Shift quotient left one and add carry bit */
adc r0, r0, r0
bx lr
.L_div0:
- /* Check the return address, since .L_udiv32 uses bl to wrap the 31-bit
- 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 */
+ /* __div0 expects the calling address on the top of the stack */
stmdb sp!, { lr }
#if defined(__ARM_EABI__) || !defined(USE_IRAM)
bl __div0