| @include "arm/unopWide.S" {"instr":"bl __aeabi_d2lz"} |
| %include "arm/unopWide.S" {"instr":"bl d2l_doconv"} |
| |
| %break |
| /* |
| * Convert the double in r0/r1 to a long in r0/r1. |
| * |
| * We have to clip values to long min/max per the specification. The |
| * expected common case is a "reasonable" value that converts directly |
| * to modest integer. The EABI convert function isn't doing this for us. |
| */ |
| d2l_doconv: |
| stmfd sp!, {r4, r5, lr} @ save regs |
| mov r3, #0x43000000 @ maxlong, as a double (high word) |
| add r3, #0x00e00000 @ 0x43e00000 |
| mov r2, #0 @ maxlong, as a double (low word) |
| sub sp, sp, #4 @ align for EABI |
| mov r4, r0 @ save a copy of r0 |
| mov r5, r1 @ and r1 |
| bl __aeabi_dcmpge @ is arg >= maxlong? |
| cmp r0, #0 @ nonzero == yes |
| mvnne r0, #0 @ return maxlong (7fffffffffffffff) |
| mvnne r1, #0x80000000 |
| bne 1f |
| |
| mov r0, r4 @ recover arg |
| mov r1, r5 |
| mov r3, #0xc3000000 @ minlong, as a double (high word) |
| add r3, #0x00e00000 @ 0xc3e00000 |
| mov r2, #0 @ minlong, as a double (low word) |
| bl __aeabi_dcmple @ is arg <= minlong? |
| cmp r0, #0 @ nonzero == yes |
| movne r0, #0 @ return minlong (8000000000000000) |
| movne r1, #0x80000000 |
| bne 1f |
| |
| mov r0, r4 @ recover arg |
| mov r1, r5 |
| mov r2, r4 @ compare against self |
| mov r3, r5 |
| bl __aeabi_dcmpeq @ is arg == self? |
| cmp r0, #0 @ zero == no |
| moveq r1, #0 @ return zero for NaN |
| beq 1f |
| |
| mov r0, r4 @ recover arg |
| mov r1, r5 |
| bl __aeabi_d2lz @ convert double to long |
| |
| 1: |
| add sp, sp, #4 |
| ldmfd sp!, {r4, r5, pc} |