2015-06-02 17:08:20 +00:00
|
|
|
#include <linux/linkage.h>
|
|
|
|
|
2006-05-30 13:56:48 +00:00
|
|
|
.macro ARM_MOD_BODY dividend, divisor, order, spare
|
|
|
|
|
|
|
|
#if __LINUX_ARM_ARCH__ >= 5
|
|
|
|
|
|
|
|
clz \order, \divisor
|
|
|
|
clz \spare, \dividend
|
|
|
|
sub \order, \order, \spare
|
|
|
|
mov \divisor, \divisor, lsl \order
|
|
|
|
|
|
|
|
#else
|
|
|
|
|
|
|
|
mov \order, #0
|
|
|
|
|
|
|
|
@ Unless the divisor is very big, shift it up in multiples of
|
|
|
|
@ four bits, since this is the amount of unwinding in the main
|
|
|
|
@ division loop. Continue shifting until the divisor is
|
|
|
|
@ larger than the dividend.
|
|
|
|
1: cmp \divisor, #0x10000000
|
|
|
|
cmplo \divisor, \dividend
|
|
|
|
movlo \divisor, \divisor, lsl #4
|
|
|
|
addlo \order, \order, #4
|
|
|
|
blo 1b
|
|
|
|
|
|
|
|
@ For very big divisors, we must shift it a bit at a time, or
|
|
|
|
@ we will be in danger of overflowing.
|
|
|
|
1: cmp \divisor, #0x80000000
|
|
|
|
cmplo \divisor, \dividend
|
|
|
|
movlo \divisor, \divisor, lsl #1
|
|
|
|
addlo \order, \order, #1
|
|
|
|
blo 1b
|
|
|
|
|
|
|
|
#endif
|
|
|
|
|
|
|
|
@ Perform all needed substractions to keep only the reminder.
|
|
|
|
@ Do comparisons in batch of 4 first.
|
|
|
|
subs \order, \order, #3 @ yes, 3 is intended here
|
|
|
|
blt 2f
|
|
|
|
|
|
|
|
1: cmp \dividend, \divisor
|
|
|
|
subhs \dividend, \dividend, \divisor
|
|
|
|
cmp \dividend, \divisor, lsr #1
|
|
|
|
subhs \dividend, \dividend, \divisor, lsr #1
|
|
|
|
cmp \dividend, \divisor, lsr #2
|
|
|
|
subhs \dividend, \dividend, \divisor, lsr #2
|
|
|
|
cmp \dividend, \divisor, lsr #3
|
|
|
|
subhs \dividend, \dividend, \divisor, lsr #3
|
|
|
|
cmp \dividend, #1
|
|
|
|
mov \divisor, \divisor, lsr #4
|
|
|
|
subges \order, \order, #4
|
|
|
|
bge 1b
|
|
|
|
|
|
|
|
tst \order, #3
|
|
|
|
teqne \dividend, #0
|
|
|
|
beq 5f
|
|
|
|
|
|
|
|
@ Either 1, 2 or 3 comparison/substractions are left.
|
|
|
|
2: cmn \order, #2
|
|
|
|
blt 4f
|
|
|
|
beq 3f
|
|
|
|
cmp \dividend, \divisor
|
|
|
|
subhs \dividend, \dividend, \divisor
|
|
|
|
mov \divisor, \divisor, lsr #1
|
|
|
|
3: cmp \dividend, \divisor
|
|
|
|
subhs \dividend, \dividend, \divisor
|
|
|
|
mov \divisor, \divisor, lsr #1
|
|
|
|
4: cmp \dividend, \divisor
|
|
|
|
subhs \dividend, \dividend, \divisor
|
|
|
|
5:
|
|
|
|
.endm
|
|
|
|
|
|
|
|
.align 5
|
2015-06-02 17:08:20 +00:00
|
|
|
ENTRY(__modsi3)
|
2006-05-30 13:56:48 +00:00
|
|
|
cmp r1, #0
|
|
|
|
beq Ldiv0
|
|
|
|
rsbmi r1, r1, #0 @ loops below use unsigned.
|
|
|
|
movs ip, r0 @ preserve sign of dividend
|
|
|
|
rsbmi r0, r0, #0 @ if negative make positive
|
|
|
|
subs r2, r1, #1 @ compare divisor with 1
|
|
|
|
cmpne r0, r1 @ compare dividend with divisor
|
|
|
|
moveq r0, #0
|
|
|
|
tsthi r1, r2 @ see if divisor is power of 2
|
|
|
|
andeq r0, r0, r2
|
|
|
|
bls 10f
|
|
|
|
|
|
|
|
ARM_MOD_BODY r0, r1, r2, r3
|
|
|
|
|
|
|
|
10: cmp ip, #0
|
|
|
|
rsbmi r0, r0, #0
|
|
|
|
mov pc, lr
|
2015-06-02 17:08:20 +00:00
|
|
|
ENDPROC(__modsi3)
|
2006-05-30 13:56:48 +00:00
|
|
|
|
|
|
|
Ldiv0:
|
|
|
|
|
|
|
|
str lr, [sp, #-4]!
|
|
|
|
bl __div0
|
|
|
|
mov r0, #0 @ About as wrong as it could be.
|
|
|
|
ldr pc, [sp], #4
|