| .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 | |
| .globl __modsi3 | |
| __modsi3: | |
| 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 | |
| Ldiv0: | |
| str lr, [sp, #-4]! | |
| bl __div0 | |
| mov r0, #0 @ About as wrong as it could be. | |
| ldr pc, [sp], #4 |