| |

| .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 |