| #include <linux/linkage.h> |
| |
| .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 |
| ENTRY(__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 |
| ENDPROC(__modsi3) |
| |
| Ldiv0: |
| |
| str lr, [sp, #-4]! |
| bl __div0 |
| mov r0, #0 @ About as wrong as it could be. |
| ldr pc, [sp], #4 |