45b86625d7
gcc: * Makefile.in (LIB1ASMSRC): Don't export. (libgcc.mvars): Don't emit LIB1ASMFUNCS, LIB1ASMSRC. * config/arm/arm.c: Update lib1funcs.asm filename. * config/arm/linux-eabi.h: Likewise. * config/arm/bpabi-v6m.S, config/arm/bpabi.S, config/arm/ieee754-df.S, config/arm/ieee754-sf.S: Move to ../libgcc/config/arm. * config/arm/lib1funcs.asm: Move to ../libgcc/config/arm/lib1funcs.S. * config/arm/t-arm (LIB1ASMSRC, LIB1ASMFUNCS): Remove. * config/arm/t-arm-elf (LIB1ASMFUNCS): Remove. * config/arm/t-bpabi: Likewise. * config/arm/t-linux (LIB1ASMSRC, LIB1ASMFUNCS): Remove. * config/arm/t-linux-eabi (LIB1ASMFUNCS): Remove. * config/arm/t-strongarm-elf: Likewise. * config/arm/t-symbian: Likewise. * config/arm/t-vxworks: Likewise. * config/arm/t-wince-pe: Likewise. * config/avr/libgcc.S: Move to ../libgcc/config/avr. * config/avr/t-avr (LIB1ASMSRC, LIB1ASMFUNCS): Remove. * config/bfin/lib1funcs.asm: Move to ../libgcc/config/bfin/lib1funcs.S. * config/bfin/t-bfin: Remove. * config/bfin/t-bfin-elf (LIB1ASMSRC, LIB1ASMFUNCS): Remove. * config/bfin/t-bfin-linux: Likewise. * config/bfin/t-bfin-uclinux: Likewise. * config/c6x/lib1funcs.asm: Move to ../libgcc/config/c6x/lib1funcs.S. * config/c6x/t-c6x-elf (LIB1ASMSRC, LIB1ASMFUNCS): Remove. * config/fr30/lib1funcs.asm: Move to ../libgcc/config/fr30/lib1funcs.S. * config/fr30/t-fr30 (LIB1ASMSRC, LIB1ASMFUNCS): Remove. * config/frv/lib1funcs.asm: Move to ../libgcc/config/frv/lib1funcs.S. * config/frv/t-frv (CROSS_LIBGCC1, LIB1ASMSRC, LIB1ASMFUNCS): Remove. * config/h8300/fixunssfsi.c: Update lib1funcs.asm filename. * config/h8300/lib1funcs.asm: Move to ../libgcc/config/h8300/lib1funcs.S. * config/h8300/t-h8300 (LIB1ASMSRC, LIB1ASMFUNCS): Remove. * config/i386/cygwin.asm: Move to ../libgcc/config/i386/cygwin.S. * config/i386/t-cygming (LIB1ASMSRC, LIB1ASMFUNCS): Remove. * config/i386/t-interix: Likewise. * config/ia64/lib1funcs.asm: Move to ../libgcc/config/ia64/lib1funcs.S. * config/ia64/t-hpux (LIB1ASMFUNCS, LIBGCC1_TEST): Remove. * config/ia64/t-ia64 (LIB1ASMSRC, LIB1ASMFUNCS): Remove. * config/iq2000/t-iq2000 (LIBGCC1, CROSS_LIBGCC1): Remove. * config/m32c/m32c.c: Update m32c-lib1.S filename. * config/m32c/m32c-lib1.S: Move to ../libgcc/config/m32c/lib1funcs.S. * config/m32c/t-m32c (LIB1ASMSRC, LIB1ASMFUNCS): Remove. * config/m32r/t-linux (CROSS_LIBGCC1, LIBGCC1, LIBGCC1_TEST): Remove. * config/m68k/lb1sf68.asm: Move to ../libgcc/config/m68k/lb1sf68.S. * config/m68k/t-floatlib (LIB1ASMSRC, LIB1ASMFUNCS): New file. * config/mcore/lib1.asm: Move to ../libgcc/config/mcore/lib1funcs.S. * config/mcore/t-mcore (LIB1ASMSRC, LIB1ASMFUNCS): Remove. * config/mep/mep-lib1.asm: Move to ../libgcc/config/mep/lib1funcs.S. * config/mep/t-mep (LIB1ASMSRC, LIB1ASMFUNCS): Remove. * config/mips/mips16.S: Move to ../libgcc/config/mips. * config/mips/t-libgcc-mips16: Remove. * config/mips/t-sr71k (LIBGCC1, CROSS_LIBGCC1): Remove. * config/pa/milli64.S: Move to ../libgcc/config/pa. * config/pa/t-linux (LIB1ASMFUNCS, LIB1ASMSRC): Remove. * config/pa/t-linux64: Likewise. * config/picochip/libgccExtras/fake_libgcc.asm: Move to ../libgcc/config/picochip/lib1funcs.S. * config/picochip/t-picochip (LIB1ASMFUNCS, LIB1ASMSRC): Remove. * config/sh/lib1funcs.asm: Move to ../libgcc/config/sh/lib1funcs.S. * config/sh/lib1funcs.h: Move to ../libgcc/config/sh. * config/sh/sh.h: Update lib1funcs.asm filename. * config/sh/t-linux (LIB1ASMFUNCS_CACHE): Remove. * config/sh/t-netbsd: Likewise. * config/sh/t-sh (LIB1ASMSRC, LIB1ASMFUNCS, LIB1ASMFUNCS_CACHE): Remove. * config/sh/t-sh64 (LIB1ASMFUNCS): Remove. * config/sparc/lb1spc.asm: Move to ../libgcc/config/sparc/lb1spc.S. * config/sparc/lb1spl.asm: Remove. * config/sparc/t-elf (LIB1ASMSRC, LIB1ASMFUNCS): Remove. * config/sparc/t-leon: Likewise. * config/spu/t-spu-elf (LIBGCC1, CROSS_LIBGCC1): Remove. * config/v850/lib1funcs.asm: Move to ../libgcc/config/v850/lib1funcs.S. * config/v850/t-v850 (LIB1ASMSRC, LIB1ASMFUNCS): Remove * config/vax/lib1funcs.asm: Move to ../libgcc/config/vax/lib1funcs.S. * config/vax/t-linux: Remove. * config/xtensa/ieee754-df.S, config/xtensa/ieee754-sf.S: Move to ../libgcc/config/xtensa. * config/xtensa/lib1funcs.asm: Move to ../libgcc/config/xtensa/lib1funcs.S. * config/xtensa/t-xtensa (LIB1ASMSRC, LIB1ASMFUNCS): Remove. * config.gcc (bfin*-rtems*): Remove bfin/t-bfin from tmake_file. (bfin*-*): Likewise. (mips64*-*-linux*, mipsisa64*-*-linux*): Remove mips/t-libgcc-mips16 from tmake_file. (mips*-*-linux*): Likewise. (mips*-sde-elf*): Likewise. (mipsisa32-*-elf*, mipsisa32el-*-elf*, mipsisa32r2-*-elf*) (mipsisa32r2el-*-elf*, mipsisa64-*-elf*, mipsisa64el-*-elf*) (mipsisa64r2-*-elf*, mipsisa64r2el-*-elf*): Likewise. (mipsisa64sb1-*-elf*, mipsisa64sb1el-*-elf*): Likewise. (mips-*-elf*, mipsel-*-elf*): Likewise. (mips64-*-elf*, mips64el-*-elf*): Likewise. (mips64orion-*-elf*, mips64orionel-*-elf*): Likewise. (mips*-*-rtems*): Likewise. (mipstx39-*-elf*, mipstx39el-*-elf*): Likewise. (vax-*-linux*): Remove vax/t-linux from tmake_file. libgcc: * Makefile.in ($(lib1asmfuncs-o), $(lib1asmfuncs-s-o)): Use $(srcdir) to refer to $(LIB1ASMSRC). Use $<. * config/arm/bpabi-v6m.S, config/arm/bpabi.S, config/arm/ieee754-df.S, config/arm/ieee754-sf.S, config/arm/lib1funcs.S: New files. * config/arm/libunwind.S [!__symbian__]: Use lib1funcs.S. * config/arm/t-arm: New file. * config/arm/t-bpabi (LIB1ASMFUNCS): Set. * config/arm/t-elf, config/arm/t-linux, config/arm/t-linux-eabi, config/arm/t-strongarm-elf: New files. * config/arm/t-symbian (LIB1ASMFUNCS): Set. * config/arm/t-vxworks, config/arm/t-wince-pe: New files. * config/avr/lib1funcs.S: New file. * config/avr/t-avr (LIB1ASMSRC, LIB1ASMFUNCS): Set. * config/bfin/lib1funcs.S, config/bfin/t-bfin: New files. * config/c6x/lib1funcs.S: New file. * config/c6x/t-elf (LIB1ASMSRC, LIB1ASMFUNCS): Set. * config/fr30/lib1funcs.S, config/fr30/t-fr30: New files. * config/frv/lib1funcs.S: New file. * config/frv/t-frv (LIB1ASMSRC, LIB1ASMFUNCS): Set. * config/h8300/lib1funcs.S, config/h8300/t-h8300: New files. * config/i386/cygwin.S, config/i386/t-chkstk: New files. * config/ia64/__divxf3.asm: Rename to ... * config/ia64/__divxf3.S: ... this. Adapt lib1funcs.asm filename. * config/ia64/_fixtfdi.asm: Rename to ... * config/ia64/_fixtfdi.S: ... this. Adapt lib1funcs.asm filename. * config/ia64/_fixunstfdi.asm: Rename to ... * config/ia64/_fixunstfdi.S: ... this. Adapt lib1funcs.asm filename. * config/ia64/_floatditf.asm: Rename to ... * config/ia64/_floatditf.S: ... this. Adapt lib1funcs.asm filename. * config/ia64/lib1funcs.S: New file. * config/ia64/t-hpux (LIB1ASMFUNCS): Set. * config/ia64/t-ia64 (LIB1ASMSRC, LIB1ASMFUNCS): Set. * config/ia64/t-softfp-compat (libgcc1-tf-compats): Adapt suffix. * config/m32c/lib1funcs.S, config/m32c/t-m32c: New files. * config/m68k/lb1sf68.S, config/m68k/t-floatlib: New files. * config/mcore/lib1funcs.S, config/mcore/t-mcore: New files. * config/mep/lib1funcs.S: New file. * config/mep/t-mep (LIB1ASMSRC, LIB1ASMFUNCS): Set. * config/mips/mips16.S: New file. * config/mips/t-mips16 (LIB1ASMSRC, LIB1ASMFUNCS): Set. * config/pa/milli64.S: New file. * config/pa/t-linux, config/pa/t-linux64: New files. * config/picochip/lib1funcs.S: New file. * config/picochip/t-picochip (LIB1ASMSRC, LIB1ASMFUNCS): Set. * config/sh/lib1funcs.S, config/sh/lib1funcs.h: New files. * config/sh/t-linux (LIB1ASMFUNCS_CACHE): Set. * config/sh/t-netbsd: New file. * config/sh/t-sh (LIB1ASMSRC, LIB1ASMFUNCS, LIB1ASMFUNCS_CACHE): Set. Use $(srcdir) to refer to lib1funcs.S, adapt filename. * config/sh/t-sh64: New file. * config/sparc/lb1spc.S: New file. * config/sparc/t-softmul (LIB1ASMSRC): Adapt sparc/lb1spc.asm filename. * config/v850/lib1funcs.S, config/v850/t-v850: New files. * config/vax/lib1funcs.S, config/vax/t-linux: New files. * config/xtensa/ieee754-df.S, config/xtensa/ieee754-sf.S, config/xtensa/lib1funcs.S: New files. * config/xtensa/t-xtensa (LIB1ASMSRC, LIB1ASMFUNCS): Set. * config.host (arm-wrs-vxworks): Add arm/t-arm, arm/t-vxworks to tmake_file. (arm*-*-freebsd*): Add arm/t-arm, arm/t-strongarm-elf to tmake_file. (arm*-*-netbsdelf*): Add arm/t-arm to tmake_file. (arm*-*-linux*): Likewise. Add arm/t-elf, arm/t-bpabi, arm/t-linux-eabi to tmake_file for arm*-*-linux-*eabi, add arm/t-linux otherwise. (arm*-*-uclinux*): Add arm/t-arm, arm/t-elf to tmake_file. (arm*-*-ecos-elf): Likewise. (arm*-*-eabi*, arm*-*-symbianelf*): Likewise. (arm*-*-rtems*): Likewise. (arm*-*-elf): Likewise. (arm*-wince-pe*): Add arm/t-arm, arm/t-wince-pe to tmake_file. (avr-*-rtems*): Add to tmake_file, add avr/t-avr. (bfin*-elf*): Add bfin/t-bfin to tmake_file. (bfin*-uclinux*): Likewise. (bfin*-linux-uclibc*): Likewise. (bfin*-rtems*): Likewise. (bfin*-*): Likewise. (fido-*-elf): Merge into m68k-*-elf*. (fr30-*-elf)): Add fr30/t-fr30 to tmake_file. (frv-*-*linux*): Add frv/t-frv to tmake_file. (h8300-*-rtems*): Add h8300/t-h8300 to tmake_file. (h8300-*-elf*): Likewise. (hppa*64*-*-linux*): Add pa/t-linux, pa/t-linux64 to tmake_file. (hppa*-*-linux*): Add pa/t-linux to tmake_file. (i[34567]86-*-cygwin*): Add i386/t-chkstk to tmake_file. (i[34567]86-*-mingw*): Likewise. (x86_64-*-mingw*): Likewise. (i[34567]86-*-interix3*): Likewise. (ia64*-*-hpux*): Add ia64/t-ia64, ia64/t-hpux to tmake_file. (ia64-hp-*vms*): Add ia64/t-ia64 to tmake_file. (m68k-*-elf*): Also handle fido-*-elf. Add m68k/t-floatlib to tmake_file. (m68k-*-uclinux*): Add m68k/t-floatlib to tmake_file. (m68k-*-linux*): Likewise. (m68k-*-rtems*): Likewise. (mcore-*-elf): Add mcore/t-mcore to tmake_file. (sh-*-elf*, sh[12346l]*-*-elf*): Add sh/t-sh64 to tmake_file for sh64*-*-*. (sh-*-linux*, sh[2346lbe]*-*-linux*): Add sh/t-sh to tmake_file. Add sh/t-sh64 to tmake_file for sh64*-*-linux*. (sh-*-netbsdelf*, shl*-*-netbsdelf*, sh5-*-netbsd*) (sh5l*-*-netbsd*, sh64-*-netbsd*, sh64l*-*-netbsd*): Add sh/t-sh, sh/t-netbsd to tmake_file. Add sh/t-sh64 to tmake_file for sh5*-*-netbsd*, sh64*-netbsd*. (sh-*-rtems*): Add sh/t-sh to tmake_file. (sh-wrs-vxworks): Likewise. (sparc-*-linux*): Add sparc/t-softmul to tmake_file except for *-leon[3-9]*. (v850*-*-*): Add v850/t-v850 to tmake_file. (vax-*-linux*): Add vax/t-linux to tmake_file. (m32c-*-elf*, m32c-*-rtems*): Add m32c/t-m32c to tmake_file. From-SVN: r180773
1448 lines
29 KiB
ArmAsm
1448 lines
29 KiB
ArmAsm
/* ieee754-df.S double-precision floating point support for ARM
|
|
|
|
Copyright (C) 2003, 2004, 2005, 2007, 2008, 2009 Free Software Foundation, Inc.
|
|
Contributed by Nicolas Pitre (nico@cam.org)
|
|
|
|
This file is free software; you can redistribute it and/or modify it
|
|
under the terms of the GNU General Public License as published by the
|
|
Free Software Foundation; either version 3, or (at your option) any
|
|
later version.
|
|
|
|
This file is distributed in the hope that it will be useful, but
|
|
WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
General Public License for more details.
|
|
|
|
Under Section 7 of GPL version 3, you are granted additional
|
|
permissions described in the GCC Runtime Library Exception, version
|
|
3.1, as published by the Free Software Foundation.
|
|
|
|
You should have received a copy of the GNU General Public License and
|
|
a copy of the GCC Runtime Library Exception along with this program;
|
|
see the files COPYING3 and COPYING.RUNTIME respectively. If not, see
|
|
<http://www.gnu.org/licenses/>. */
|
|
|
|
/*
|
|
* Notes:
|
|
*
|
|
* The goal of this code is to be as fast as possible. This is
|
|
* not meant to be easy to understand for the casual reader.
|
|
* For slightly simpler code please see the single precision version
|
|
* of this file.
|
|
*
|
|
* Only the default rounding mode is intended for best performances.
|
|
* Exceptions aren't supported yet, but that can be added quite easily
|
|
* if necessary without impacting performances.
|
|
*/
|
|
|
|
|
|
@ For FPA, float words are always big-endian.
|
|
@ For VFP, floats words follow the memory system mode.
|
|
#if defined(__VFP_FP__) && !defined(__ARMEB__)
|
|
#define xl r0
|
|
#define xh r1
|
|
#define yl r2
|
|
#define yh r3
|
|
#else
|
|
#define xh r0
|
|
#define xl r1
|
|
#define yh r2
|
|
#define yl r3
|
|
#endif
|
|
|
|
|
|
#ifdef L_arm_negdf2
|
|
|
|
ARM_FUNC_START negdf2
|
|
ARM_FUNC_ALIAS aeabi_dneg negdf2
|
|
|
|
@ flip sign bit
|
|
eor xh, xh, #0x80000000
|
|
RET
|
|
|
|
FUNC_END aeabi_dneg
|
|
FUNC_END negdf2
|
|
|
|
#endif
|
|
|
|
#ifdef L_arm_addsubdf3
|
|
|
|
ARM_FUNC_START aeabi_drsub
|
|
|
|
eor xh, xh, #0x80000000 @ flip sign bit of first arg
|
|
b 1f
|
|
|
|
ARM_FUNC_START subdf3
|
|
ARM_FUNC_ALIAS aeabi_dsub subdf3
|
|
|
|
eor yh, yh, #0x80000000 @ flip sign bit of second arg
|
|
#if defined(__INTERWORKING_STUBS__)
|
|
b 1f @ Skip Thumb-code prologue
|
|
#endif
|
|
|
|
ARM_FUNC_START adddf3
|
|
ARM_FUNC_ALIAS aeabi_dadd adddf3
|
|
|
|
1: do_push {r4, r5, lr}
|
|
|
|
@ Look for zeroes, equal values, INF, or NAN.
|
|
shift1 lsl, r4, xh, #1
|
|
shift1 lsl, r5, yh, #1
|
|
teq r4, r5
|
|
do_it eq
|
|
teqeq xl, yl
|
|
do_it ne, ttt
|
|
COND(orr,s,ne) ip, r4, xl
|
|
COND(orr,s,ne) ip, r5, yl
|
|
COND(mvn,s,ne) ip, r4, asr #21
|
|
COND(mvn,s,ne) ip, r5, asr #21
|
|
beq LSYM(Lad_s)
|
|
|
|
@ Compute exponent difference. Make largest exponent in r4,
|
|
@ corresponding arg in xh-xl, and positive exponent difference in r5.
|
|
shift1 lsr, r4, r4, #21
|
|
rsbs r5, r4, r5, lsr #21
|
|
do_it lt
|
|
rsblt r5, r5, #0
|
|
ble 1f
|
|
add r4, r4, r5
|
|
eor yl, xl, yl
|
|
eor yh, xh, yh
|
|
eor xl, yl, xl
|
|
eor xh, yh, xh
|
|
eor yl, xl, yl
|
|
eor yh, xh, yh
|
|
1:
|
|
@ If exponent difference is too large, return largest argument
|
|
@ already in xh-xl. We need up to 54 bit to handle proper rounding
|
|
@ of 0x1p54 - 1.1.
|
|
cmp r5, #54
|
|
do_it hi
|
|
RETLDM "r4, r5" hi
|
|
|
|
@ Convert mantissa to signed integer.
|
|
tst xh, #0x80000000
|
|
mov xh, xh, lsl #12
|
|
mov ip, #0x00100000
|
|
orr xh, ip, xh, lsr #12
|
|
beq 1f
|
|
#if defined(__thumb2__)
|
|
negs xl, xl
|
|
sbc xh, xh, xh, lsl #1
|
|
#else
|
|
rsbs xl, xl, #0
|
|
rsc xh, xh, #0
|
|
#endif
|
|
1:
|
|
tst yh, #0x80000000
|
|
mov yh, yh, lsl #12
|
|
orr yh, ip, yh, lsr #12
|
|
beq 1f
|
|
#if defined(__thumb2__)
|
|
negs yl, yl
|
|
sbc yh, yh, yh, lsl #1
|
|
#else
|
|
rsbs yl, yl, #0
|
|
rsc yh, yh, #0
|
|
#endif
|
|
1:
|
|
@ If exponent == difference, one or both args were denormalized.
|
|
@ Since this is not common case, rescale them off line.
|
|
teq r4, r5
|
|
beq LSYM(Lad_d)
|
|
LSYM(Lad_x):
|
|
|
|
@ Compensate for the exponent overlapping the mantissa MSB added later
|
|
sub r4, r4, #1
|
|
|
|
@ Shift yh-yl right per r5, add to xh-xl, keep leftover bits into ip.
|
|
rsbs lr, r5, #32
|
|
blt 1f
|
|
shift1 lsl, ip, yl, lr
|
|
shiftop adds xl xl yl lsr r5 yl
|
|
adc xh, xh, #0
|
|
shiftop adds xl xl yh lsl lr yl
|
|
shiftop adcs xh xh yh asr r5 yh
|
|
b 2f
|
|
1: sub r5, r5, #32
|
|
add lr, lr, #32
|
|
cmp yl, #1
|
|
shift1 lsl,ip, yh, lr
|
|
do_it cs
|
|
orrcs ip, ip, #2 @ 2 not 1, to allow lsr #1 later
|
|
shiftop adds xl xl yh asr r5 yh
|
|
adcs xh, xh, yh, asr #31
|
|
2:
|
|
@ We now have a result in xh-xl-ip.
|
|
@ Keep absolute value in xh-xl-ip, sign in r5 (the n bit was set above)
|
|
and r5, xh, #0x80000000
|
|
bpl LSYM(Lad_p)
|
|
#if defined(__thumb2__)
|
|
mov lr, #0
|
|
negs ip, ip
|
|
sbcs xl, lr, xl
|
|
sbc xh, lr, xh
|
|
#else
|
|
rsbs ip, ip, #0
|
|
rscs xl, xl, #0
|
|
rsc xh, xh, #0
|
|
#endif
|
|
|
|
@ Determine how to normalize the result.
|
|
LSYM(Lad_p):
|
|
cmp xh, #0x00100000
|
|
bcc LSYM(Lad_a)
|
|
cmp xh, #0x00200000
|
|
bcc LSYM(Lad_e)
|
|
|
|
@ Result needs to be shifted right.
|
|
movs xh, xh, lsr #1
|
|
movs xl, xl, rrx
|
|
mov ip, ip, rrx
|
|
add r4, r4, #1
|
|
|
|
@ Make sure we did not bust our exponent.
|
|
mov r2, r4, lsl #21
|
|
cmn r2, #(2 << 21)
|
|
bcs LSYM(Lad_o)
|
|
|
|
@ Our result is now properly aligned into xh-xl, remaining bits in ip.
|
|
@ Round with MSB of ip. If halfway between two numbers, round towards
|
|
@ LSB of xl = 0.
|
|
@ Pack final result together.
|
|
LSYM(Lad_e):
|
|
cmp ip, #0x80000000
|
|
do_it eq
|
|
COND(mov,s,eq) ip, xl, lsr #1
|
|
adcs xl, xl, #0
|
|
adc xh, xh, r4, lsl #20
|
|
orr xh, xh, r5
|
|
RETLDM "r4, r5"
|
|
|
|
@ Result must be shifted left and exponent adjusted.
|
|
LSYM(Lad_a):
|
|
movs ip, ip, lsl #1
|
|
adcs xl, xl, xl
|
|
adc xh, xh, xh
|
|
tst xh, #0x00100000
|
|
sub r4, r4, #1
|
|
bne LSYM(Lad_e)
|
|
|
|
@ No rounding necessary since ip will always be 0 at this point.
|
|
LSYM(Lad_l):
|
|
|
|
#if __ARM_ARCH__ < 5
|
|
|
|
teq xh, #0
|
|
movne r3, #20
|
|
moveq r3, #52
|
|
moveq xh, xl
|
|
moveq xl, #0
|
|
mov r2, xh
|
|
cmp r2, #(1 << 16)
|
|
movhs r2, r2, lsr #16
|
|
subhs r3, r3, #16
|
|
cmp r2, #(1 << 8)
|
|
movhs r2, r2, lsr #8
|
|
subhs r3, r3, #8
|
|
cmp r2, #(1 << 4)
|
|
movhs r2, r2, lsr #4
|
|
subhs r3, r3, #4
|
|
cmp r2, #(1 << 2)
|
|
subhs r3, r3, #2
|
|
sublo r3, r3, r2, lsr #1
|
|
sub r3, r3, r2, lsr #3
|
|
|
|
#else
|
|
|
|
teq xh, #0
|
|
do_it eq, t
|
|
moveq xh, xl
|
|
moveq xl, #0
|
|
clz r3, xh
|
|
do_it eq
|
|
addeq r3, r3, #32
|
|
sub r3, r3, #11
|
|
|
|
#endif
|
|
|
|
@ determine how to shift the value.
|
|
subs r2, r3, #32
|
|
bge 2f
|
|
adds r2, r2, #12
|
|
ble 1f
|
|
|
|
@ shift value left 21 to 31 bits, or actually right 11 to 1 bits
|
|
@ since a register switch happened above.
|
|
add ip, r2, #20
|
|
rsb r2, r2, #12
|
|
shift1 lsl, xl, xh, ip
|
|
shift1 lsr, xh, xh, r2
|
|
b 3f
|
|
|
|
@ actually shift value left 1 to 20 bits, which might also represent
|
|
@ 32 to 52 bits if counting the register switch that happened earlier.
|
|
1: add r2, r2, #20
|
|
2: do_it le
|
|
rsble ip, r2, #32
|
|
shift1 lsl, xh, xh, r2
|
|
#if defined(__thumb2__)
|
|
lsr ip, xl, ip
|
|
itt le
|
|
orrle xh, xh, ip
|
|
lslle xl, xl, r2
|
|
#else
|
|
orrle xh, xh, xl, lsr ip
|
|
movle xl, xl, lsl r2
|
|
#endif
|
|
|
|
@ adjust exponent accordingly.
|
|
3: subs r4, r4, r3
|
|
do_it ge, tt
|
|
addge xh, xh, r4, lsl #20
|
|
orrge xh, xh, r5
|
|
RETLDM "r4, r5" ge
|
|
|
|
@ Exponent too small, denormalize result.
|
|
@ Find out proper shift value.
|
|
mvn r4, r4
|
|
subs r4, r4, #31
|
|
bge 2f
|
|
adds r4, r4, #12
|
|
bgt 1f
|
|
|
|
@ shift result right of 1 to 20 bits, sign is in r5.
|
|
add r4, r4, #20
|
|
rsb r2, r4, #32
|
|
shift1 lsr, xl, xl, r4
|
|
shiftop orr xl xl xh lsl r2 yh
|
|
shiftop orr xh r5 xh lsr r4 yh
|
|
RETLDM "r4, r5"
|
|
|
|
@ shift result right of 21 to 31 bits, or left 11 to 1 bits after
|
|
@ a register switch from xh to xl.
|
|
1: rsb r4, r4, #12
|
|
rsb r2, r4, #32
|
|
shift1 lsr, xl, xl, r2
|
|
shiftop orr xl xl xh lsl r4 yh
|
|
mov xh, r5
|
|
RETLDM "r4, r5"
|
|
|
|
@ Shift value right of 32 to 64 bits, or 0 to 32 bits after a switch
|
|
@ from xh to xl.
|
|
2: shift1 lsr, xl, xh, r4
|
|
mov xh, r5
|
|
RETLDM "r4, r5"
|
|
|
|
@ Adjust exponents for denormalized arguments.
|
|
@ Note that r4 must not remain equal to 0.
|
|
LSYM(Lad_d):
|
|
teq r4, #0
|
|
eor yh, yh, #0x00100000
|
|
do_it eq, te
|
|
eoreq xh, xh, #0x00100000
|
|
addeq r4, r4, #1
|
|
subne r5, r5, #1
|
|
b LSYM(Lad_x)
|
|
|
|
|
|
LSYM(Lad_s):
|
|
mvns ip, r4, asr #21
|
|
do_it ne
|
|
COND(mvn,s,ne) ip, r5, asr #21
|
|
beq LSYM(Lad_i)
|
|
|
|
teq r4, r5
|
|
do_it eq
|
|
teqeq xl, yl
|
|
beq 1f
|
|
|
|
@ Result is x + 0.0 = x or 0.0 + y = y.
|
|
orrs ip, r4, xl
|
|
do_it eq, t
|
|
moveq xh, yh
|
|
moveq xl, yl
|
|
RETLDM "r4, r5"
|
|
|
|
1: teq xh, yh
|
|
|
|
@ Result is x - x = 0.
|
|
do_it ne, tt
|
|
movne xh, #0
|
|
movne xl, #0
|
|
RETLDM "r4, r5" ne
|
|
|
|
@ Result is x + x = 2x.
|
|
movs ip, r4, lsr #21
|
|
bne 2f
|
|
movs xl, xl, lsl #1
|
|
adcs xh, xh, xh
|
|
do_it cs
|
|
orrcs xh, xh, #0x80000000
|
|
RETLDM "r4, r5"
|
|
2: adds r4, r4, #(2 << 21)
|
|
do_it cc, t
|
|
addcc xh, xh, #(1 << 20)
|
|
RETLDM "r4, r5" cc
|
|
and r5, xh, #0x80000000
|
|
|
|
@ Overflow: return INF.
|
|
LSYM(Lad_o):
|
|
orr xh, r5, #0x7f000000
|
|
orr xh, xh, #0x00f00000
|
|
mov xl, #0
|
|
RETLDM "r4, r5"
|
|
|
|
@ At least one of x or y is INF/NAN.
|
|
@ if xh-xl != INF/NAN: return yh-yl (which is INF/NAN)
|
|
@ if yh-yl != INF/NAN: return xh-xl (which is INF/NAN)
|
|
@ if either is NAN: return NAN
|
|
@ if opposite sign: return NAN
|
|
@ otherwise return xh-xl (which is INF or -INF)
|
|
LSYM(Lad_i):
|
|
mvns ip, r4, asr #21
|
|
do_it ne, te
|
|
movne xh, yh
|
|
movne xl, yl
|
|
COND(mvn,s,eq) ip, r5, asr #21
|
|
do_it ne, t
|
|
movne yh, xh
|
|
movne yl, xl
|
|
orrs r4, xl, xh, lsl #12
|
|
do_it eq, te
|
|
COND(orr,s,eq) r5, yl, yh, lsl #12
|
|
teqeq xh, yh
|
|
orrne xh, xh, #0x00080000 @ quiet NAN
|
|
RETLDM "r4, r5"
|
|
|
|
FUNC_END aeabi_dsub
|
|
FUNC_END subdf3
|
|
FUNC_END aeabi_dadd
|
|
FUNC_END adddf3
|
|
|
|
ARM_FUNC_START floatunsidf
|
|
ARM_FUNC_ALIAS aeabi_ui2d floatunsidf
|
|
|
|
teq r0, #0
|
|
do_it eq, t
|
|
moveq r1, #0
|
|
RETc(eq)
|
|
do_push {r4, r5, lr}
|
|
mov r4, #0x400 @ initial exponent
|
|
add r4, r4, #(52-1 - 1)
|
|
mov r5, #0 @ sign bit is 0
|
|
.ifnc xl, r0
|
|
mov xl, r0
|
|
.endif
|
|
mov xh, #0
|
|
b LSYM(Lad_l)
|
|
|
|
FUNC_END aeabi_ui2d
|
|
FUNC_END floatunsidf
|
|
|
|
ARM_FUNC_START floatsidf
|
|
ARM_FUNC_ALIAS aeabi_i2d floatsidf
|
|
|
|
teq r0, #0
|
|
do_it eq, t
|
|
moveq r1, #0
|
|
RETc(eq)
|
|
do_push {r4, r5, lr}
|
|
mov r4, #0x400 @ initial exponent
|
|
add r4, r4, #(52-1 - 1)
|
|
ands r5, r0, #0x80000000 @ sign bit in r5
|
|
do_it mi
|
|
rsbmi r0, r0, #0 @ absolute value
|
|
.ifnc xl, r0
|
|
mov xl, r0
|
|
.endif
|
|
mov xh, #0
|
|
b LSYM(Lad_l)
|
|
|
|
FUNC_END aeabi_i2d
|
|
FUNC_END floatsidf
|
|
|
|
ARM_FUNC_START extendsfdf2
|
|
ARM_FUNC_ALIAS aeabi_f2d extendsfdf2
|
|
|
|
movs r2, r0, lsl #1 @ toss sign bit
|
|
mov xh, r2, asr #3 @ stretch exponent
|
|
mov xh, xh, rrx @ retrieve sign bit
|
|
mov xl, r2, lsl #28 @ retrieve remaining bits
|
|
do_it ne, ttt
|
|
COND(and,s,ne) r3, r2, #0xff000000 @ isolate exponent
|
|
teqne r3, #0xff000000 @ if not 0, check if INF or NAN
|
|
eorne xh, xh, #0x38000000 @ fixup exponent otherwise.
|
|
RETc(ne) @ and return it.
|
|
|
|
teq r2, #0 @ if actually 0
|
|
do_it ne, e
|
|
teqne r3, #0xff000000 @ or INF or NAN
|
|
RETc(eq) @ we are done already.
|
|
|
|
@ value was denormalized. We can normalize it now.
|
|
do_push {r4, r5, lr}
|
|
mov r4, #0x380 @ setup corresponding exponent
|
|
and r5, xh, #0x80000000 @ move sign bit in r5
|
|
bic xh, xh, #0x80000000
|
|
b LSYM(Lad_l)
|
|
|
|
FUNC_END aeabi_f2d
|
|
FUNC_END extendsfdf2
|
|
|
|
ARM_FUNC_START floatundidf
|
|
ARM_FUNC_ALIAS aeabi_ul2d floatundidf
|
|
|
|
orrs r2, r0, r1
|
|
#if !defined (__VFP_FP__) && !defined(__SOFTFP__)
|
|
do_it eq, t
|
|
mvfeqd f0, #0.0
|
|
#else
|
|
do_it eq
|
|
#endif
|
|
RETc(eq)
|
|
|
|
#if !defined (__VFP_FP__) && !defined(__SOFTFP__)
|
|
@ For hard FPA code we want to return via the tail below so that
|
|
@ we can return the result in f0 as well as in r0/r1 for backwards
|
|
@ compatibility.
|
|
adr ip, LSYM(f0_ret)
|
|
@ Push pc as well so that RETLDM works correctly.
|
|
do_push {r4, r5, ip, lr, pc}
|
|
#else
|
|
do_push {r4, r5, lr}
|
|
#endif
|
|
|
|
mov r5, #0
|
|
b 2f
|
|
|
|
ARM_FUNC_START floatdidf
|
|
ARM_FUNC_ALIAS aeabi_l2d floatdidf
|
|
|
|
orrs r2, r0, r1
|
|
#if !defined (__VFP_FP__) && !defined(__SOFTFP__)
|
|
do_it eq, t
|
|
mvfeqd f0, #0.0
|
|
#else
|
|
do_it eq
|
|
#endif
|
|
RETc(eq)
|
|
|
|
#if !defined (__VFP_FP__) && !defined(__SOFTFP__)
|
|
@ For hard FPA code we want to return via the tail below so that
|
|
@ we can return the result in f0 as well as in r0/r1 for backwards
|
|
@ compatibility.
|
|
adr ip, LSYM(f0_ret)
|
|
@ Push pc as well so that RETLDM works correctly.
|
|
do_push {r4, r5, ip, lr, pc}
|
|
#else
|
|
do_push {r4, r5, lr}
|
|
#endif
|
|
|
|
ands r5, ah, #0x80000000 @ sign bit in r5
|
|
bpl 2f
|
|
#if defined(__thumb2__)
|
|
negs al, al
|
|
sbc ah, ah, ah, lsl #1
|
|
#else
|
|
rsbs al, al, #0
|
|
rsc ah, ah, #0
|
|
#endif
|
|
2:
|
|
mov r4, #0x400 @ initial exponent
|
|
add r4, r4, #(52-1 - 1)
|
|
|
|
@ FPA little-endian: must swap the word order.
|
|
.ifnc xh, ah
|
|
mov ip, al
|
|
mov xh, ah
|
|
mov xl, ip
|
|
.endif
|
|
|
|
movs ip, xh, lsr #22
|
|
beq LSYM(Lad_p)
|
|
|
|
@ The value is too big. Scale it down a bit...
|
|
mov r2, #3
|
|
movs ip, ip, lsr #3
|
|
do_it ne
|
|
addne r2, r2, #3
|
|
movs ip, ip, lsr #3
|
|
do_it ne
|
|
addne r2, r2, #3
|
|
add r2, r2, ip, lsr #3
|
|
|
|
rsb r3, r2, #32
|
|
shift1 lsl, ip, xl, r3
|
|
shift1 lsr, xl, xl, r2
|
|
shiftop orr xl xl xh lsl r3 lr
|
|
shift1 lsr, xh, xh, r2
|
|
add r4, r4, r2
|
|
b LSYM(Lad_p)
|
|
|
|
#if !defined (__VFP_FP__) && !defined(__SOFTFP__)
|
|
|
|
@ Legacy code expects the result to be returned in f0. Copy it
|
|
@ there as well.
|
|
LSYM(f0_ret):
|
|
do_push {r0, r1}
|
|
ldfd f0, [sp], #8
|
|
RETLDM
|
|
|
|
#endif
|
|
|
|
FUNC_END floatdidf
|
|
FUNC_END aeabi_l2d
|
|
FUNC_END floatundidf
|
|
FUNC_END aeabi_ul2d
|
|
|
|
#endif /* L_addsubdf3 */
|
|
|
|
#ifdef L_arm_muldivdf3
|
|
|
|
ARM_FUNC_START muldf3
|
|
ARM_FUNC_ALIAS aeabi_dmul muldf3
|
|
do_push {r4, r5, r6, lr}
|
|
|
|
@ Mask out exponents, trap any zero/denormal/INF/NAN.
|
|
mov ip, #0xff
|
|
orr ip, ip, #0x700
|
|
ands r4, ip, xh, lsr #20
|
|
do_it ne, tte
|
|
COND(and,s,ne) r5, ip, yh, lsr #20
|
|
teqne r4, ip
|
|
teqne r5, ip
|
|
bleq LSYM(Lml_s)
|
|
|
|
@ Add exponents together
|
|
add r4, r4, r5
|
|
|
|
@ Determine final sign.
|
|
eor r6, xh, yh
|
|
|
|
@ Convert mantissa to unsigned integer.
|
|
@ If power of two, branch to a separate path.
|
|
bic xh, xh, ip, lsl #21
|
|
bic yh, yh, ip, lsl #21
|
|
orrs r5, xl, xh, lsl #12
|
|
do_it ne
|
|
COND(orr,s,ne) r5, yl, yh, lsl #12
|
|
orr xh, xh, #0x00100000
|
|
orr yh, yh, #0x00100000
|
|
beq LSYM(Lml_1)
|
|
|
|
#if __ARM_ARCH__ < 4
|
|
|
|
@ Put sign bit in r6, which will be restored in yl later.
|
|
and r6, r6, #0x80000000
|
|
|
|
@ Well, no way to make it shorter without the umull instruction.
|
|
stmfd sp!, {r6, r7, r8, r9, sl, fp}
|
|
mov r7, xl, lsr #16
|
|
mov r8, yl, lsr #16
|
|
mov r9, xh, lsr #16
|
|
mov sl, yh, lsr #16
|
|
bic xl, xl, r7, lsl #16
|
|
bic yl, yl, r8, lsl #16
|
|
bic xh, xh, r9, lsl #16
|
|
bic yh, yh, sl, lsl #16
|
|
mul ip, xl, yl
|
|
mul fp, xl, r8
|
|
mov lr, #0
|
|
adds ip, ip, fp, lsl #16
|
|
adc lr, lr, fp, lsr #16
|
|
mul fp, r7, yl
|
|
adds ip, ip, fp, lsl #16
|
|
adc lr, lr, fp, lsr #16
|
|
mul fp, xl, sl
|
|
mov r5, #0
|
|
adds lr, lr, fp, lsl #16
|
|
adc r5, r5, fp, lsr #16
|
|
mul fp, r7, yh
|
|
adds lr, lr, fp, lsl #16
|
|
adc r5, r5, fp, lsr #16
|
|
mul fp, xh, r8
|
|
adds lr, lr, fp, lsl #16
|
|
adc r5, r5, fp, lsr #16
|
|
mul fp, r9, yl
|
|
adds lr, lr, fp, lsl #16
|
|
adc r5, r5, fp, lsr #16
|
|
mul fp, xh, sl
|
|
mul r6, r9, sl
|
|
adds r5, r5, fp, lsl #16
|
|
adc r6, r6, fp, lsr #16
|
|
mul fp, r9, yh
|
|
adds r5, r5, fp, lsl #16
|
|
adc r6, r6, fp, lsr #16
|
|
mul fp, xl, yh
|
|
adds lr, lr, fp
|
|
mul fp, r7, sl
|
|
adcs r5, r5, fp
|
|
mul fp, xh, yl
|
|
adc r6, r6, #0
|
|
adds lr, lr, fp
|
|
mul fp, r9, r8
|
|
adcs r5, r5, fp
|
|
mul fp, r7, r8
|
|
adc r6, r6, #0
|
|
adds lr, lr, fp
|
|
mul fp, xh, yh
|
|
adcs r5, r5, fp
|
|
adc r6, r6, #0
|
|
ldmfd sp!, {yl, r7, r8, r9, sl, fp}
|
|
|
|
#else
|
|
|
|
@ Here is the actual multiplication.
|
|
umull ip, lr, xl, yl
|
|
mov r5, #0
|
|
umlal lr, r5, xh, yl
|
|
and yl, r6, #0x80000000
|
|
umlal lr, r5, xl, yh
|
|
mov r6, #0
|
|
umlal r5, r6, xh, yh
|
|
|
|
#endif
|
|
|
|
@ The LSBs in ip are only significant for the final rounding.
|
|
@ Fold them into lr.
|
|
teq ip, #0
|
|
do_it ne
|
|
orrne lr, lr, #1
|
|
|
|
@ Adjust result upon the MSB position.
|
|
sub r4, r4, #0xff
|
|
cmp r6, #(1 << (20-11))
|
|
sbc r4, r4, #0x300
|
|
bcs 1f
|
|
movs lr, lr, lsl #1
|
|
adcs r5, r5, r5
|
|
adc r6, r6, r6
|
|
1:
|
|
@ Shift to final position, add sign to result.
|
|
orr xh, yl, r6, lsl #11
|
|
orr xh, xh, r5, lsr #21
|
|
mov xl, r5, lsl #11
|
|
orr xl, xl, lr, lsr #21
|
|
mov lr, lr, lsl #11
|
|
|
|
@ Check exponent range for under/overflow.
|
|
subs ip, r4, #(254 - 1)
|
|
do_it hi
|
|
cmphi ip, #0x700
|
|
bhi LSYM(Lml_u)
|
|
|
|
@ Round the result, merge final exponent.
|
|
cmp lr, #0x80000000
|
|
do_it eq
|
|
COND(mov,s,eq) lr, xl, lsr #1
|
|
adcs xl, xl, #0
|
|
adc xh, xh, r4, lsl #20
|
|
RETLDM "r4, r5, r6"
|
|
|
|
@ Multiplication by 0x1p*: let''s shortcut a lot of code.
|
|
LSYM(Lml_1):
|
|
and r6, r6, #0x80000000
|
|
orr xh, r6, xh
|
|
orr xl, xl, yl
|
|
eor xh, xh, yh
|
|
subs r4, r4, ip, lsr #1
|
|
do_it gt, tt
|
|
COND(rsb,s,gt) r5, r4, ip
|
|
orrgt xh, xh, r4, lsl #20
|
|
RETLDM "r4, r5, r6" gt
|
|
|
|
@ Under/overflow: fix things up for the code below.
|
|
orr xh, xh, #0x00100000
|
|
mov lr, #0
|
|
subs r4, r4, #1
|
|
|
|
LSYM(Lml_u):
|
|
@ Overflow?
|
|
bgt LSYM(Lml_o)
|
|
|
|
@ Check if denormalized result is possible, otherwise return signed 0.
|
|
cmn r4, #(53 + 1)
|
|
do_it le, tt
|
|
movle xl, #0
|
|
bicle xh, xh, #0x7fffffff
|
|
RETLDM "r4, r5, r6" le
|
|
|
|
@ Find out proper shift value.
|
|
rsb r4, r4, #0
|
|
subs r4, r4, #32
|
|
bge 2f
|
|
adds r4, r4, #12
|
|
bgt 1f
|
|
|
|
@ shift result right of 1 to 20 bits, preserve sign bit, round, etc.
|
|
add r4, r4, #20
|
|
rsb r5, r4, #32
|
|
shift1 lsl, r3, xl, r5
|
|
shift1 lsr, xl, xl, r4
|
|
shiftop orr xl xl xh lsl r5 r2
|
|
and r2, xh, #0x80000000
|
|
bic xh, xh, #0x80000000
|
|
adds xl, xl, r3, lsr #31
|
|
shiftop adc xh r2 xh lsr r4 r6
|
|
orrs lr, lr, r3, lsl #1
|
|
do_it eq
|
|
biceq xl, xl, r3, lsr #31
|
|
RETLDM "r4, r5, r6"
|
|
|
|
@ shift result right of 21 to 31 bits, or left 11 to 1 bits after
|
|
@ a register switch from xh to xl. Then round.
|
|
1: rsb r4, r4, #12
|
|
rsb r5, r4, #32
|
|
shift1 lsl, r3, xl, r4
|
|
shift1 lsr, xl, xl, r5
|
|
shiftop orr xl xl xh lsl r4 r2
|
|
bic xh, xh, #0x7fffffff
|
|
adds xl, xl, r3, lsr #31
|
|
adc xh, xh, #0
|
|
orrs lr, lr, r3, lsl #1
|
|
do_it eq
|
|
biceq xl, xl, r3, lsr #31
|
|
RETLDM "r4, r5, r6"
|
|
|
|
@ Shift value right of 32 to 64 bits, or 0 to 32 bits after a switch
|
|
@ from xh to xl. Leftover bits are in r3-r6-lr for rounding.
|
|
2: rsb r5, r4, #32
|
|
shiftop orr lr lr xl lsl r5 r2
|
|
shift1 lsr, r3, xl, r4
|
|
shiftop orr r3 r3 xh lsl r5 r2
|
|
shift1 lsr, xl, xh, r4
|
|
bic xh, xh, #0x7fffffff
|
|
shiftop bic xl xl xh lsr r4 r2
|
|
add xl, xl, r3, lsr #31
|
|
orrs lr, lr, r3, lsl #1
|
|
do_it eq
|
|
biceq xl, xl, r3, lsr #31
|
|
RETLDM "r4, r5, r6"
|
|
|
|
@ One or both arguments are denormalized.
|
|
@ Scale them leftwards and preserve sign bit.
|
|
LSYM(Lml_d):
|
|
teq r4, #0
|
|
bne 2f
|
|
and r6, xh, #0x80000000
|
|
1: movs xl, xl, lsl #1
|
|
adc xh, xh, xh
|
|
tst xh, #0x00100000
|
|
do_it eq
|
|
subeq r4, r4, #1
|
|
beq 1b
|
|
orr xh, xh, r6
|
|
teq r5, #0
|
|
do_it ne
|
|
RETc(ne)
|
|
2: and r6, yh, #0x80000000
|
|
3: movs yl, yl, lsl #1
|
|
adc yh, yh, yh
|
|
tst yh, #0x00100000
|
|
do_it eq
|
|
subeq r5, r5, #1
|
|
beq 3b
|
|
orr yh, yh, r6
|
|
RET
|
|
|
|
LSYM(Lml_s):
|
|
@ Isolate the INF and NAN cases away
|
|
teq r4, ip
|
|
and r5, ip, yh, lsr #20
|
|
do_it ne
|
|
teqne r5, ip
|
|
beq 1f
|
|
|
|
@ Here, one or more arguments are either denormalized or zero.
|
|
orrs r6, xl, xh, lsl #1
|
|
do_it ne
|
|
COND(orr,s,ne) r6, yl, yh, lsl #1
|
|
bne LSYM(Lml_d)
|
|
|
|
@ Result is 0, but determine sign anyway.
|
|
LSYM(Lml_z):
|
|
eor xh, xh, yh
|
|
and xh, xh, #0x80000000
|
|
mov xl, #0
|
|
RETLDM "r4, r5, r6"
|
|
|
|
1: @ One or both args are INF or NAN.
|
|
orrs r6, xl, xh, lsl #1
|
|
do_it eq, te
|
|
moveq xl, yl
|
|
moveq xh, yh
|
|
COND(orr,s,ne) r6, yl, yh, lsl #1
|
|
beq LSYM(Lml_n) @ 0 * INF or INF * 0 -> NAN
|
|
teq r4, ip
|
|
bne 1f
|
|
orrs r6, xl, xh, lsl #12
|
|
bne LSYM(Lml_n) @ NAN * <anything> -> NAN
|
|
1: teq r5, ip
|
|
bne LSYM(Lml_i)
|
|
orrs r6, yl, yh, lsl #12
|
|
do_it ne, t
|
|
movne xl, yl
|
|
movne xh, yh
|
|
bne LSYM(Lml_n) @ <anything> * NAN -> NAN
|
|
|
|
@ Result is INF, but we need to determine its sign.
|
|
LSYM(Lml_i):
|
|
eor xh, xh, yh
|
|
|
|
@ Overflow: return INF (sign already in xh).
|
|
LSYM(Lml_o):
|
|
and xh, xh, #0x80000000
|
|
orr xh, xh, #0x7f000000
|
|
orr xh, xh, #0x00f00000
|
|
mov xl, #0
|
|
RETLDM "r4, r5, r6"
|
|
|
|
@ Return a quiet NAN.
|
|
LSYM(Lml_n):
|
|
orr xh, xh, #0x7f000000
|
|
orr xh, xh, #0x00f80000
|
|
RETLDM "r4, r5, r6"
|
|
|
|
FUNC_END aeabi_dmul
|
|
FUNC_END muldf3
|
|
|
|
ARM_FUNC_START divdf3
|
|
ARM_FUNC_ALIAS aeabi_ddiv divdf3
|
|
|
|
do_push {r4, r5, r6, lr}
|
|
|
|
@ Mask out exponents, trap any zero/denormal/INF/NAN.
|
|
mov ip, #0xff
|
|
orr ip, ip, #0x700
|
|
ands r4, ip, xh, lsr #20
|
|
do_it ne, tte
|
|
COND(and,s,ne) r5, ip, yh, lsr #20
|
|
teqne r4, ip
|
|
teqne r5, ip
|
|
bleq LSYM(Ldv_s)
|
|
|
|
@ Substract divisor exponent from dividend''s.
|
|
sub r4, r4, r5
|
|
|
|
@ Preserve final sign into lr.
|
|
eor lr, xh, yh
|
|
|
|
@ Convert mantissa to unsigned integer.
|
|
@ Dividend -> r5-r6, divisor -> yh-yl.
|
|
orrs r5, yl, yh, lsl #12
|
|
mov xh, xh, lsl #12
|
|
beq LSYM(Ldv_1)
|
|
mov yh, yh, lsl #12
|
|
mov r5, #0x10000000
|
|
orr yh, r5, yh, lsr #4
|
|
orr yh, yh, yl, lsr #24
|
|
mov yl, yl, lsl #8
|
|
orr r5, r5, xh, lsr #4
|
|
orr r5, r5, xl, lsr #24
|
|
mov r6, xl, lsl #8
|
|
|
|
@ Initialize xh with final sign bit.
|
|
and xh, lr, #0x80000000
|
|
|
|
@ Ensure result will land to known bit position.
|
|
@ Apply exponent bias accordingly.
|
|
cmp r5, yh
|
|
do_it eq
|
|
cmpeq r6, yl
|
|
adc r4, r4, #(255 - 2)
|
|
add r4, r4, #0x300
|
|
bcs 1f
|
|
movs yh, yh, lsr #1
|
|
mov yl, yl, rrx
|
|
1:
|
|
@ Perform first substraction to align result to a nibble.
|
|
subs r6, r6, yl
|
|
sbc r5, r5, yh
|
|
movs yh, yh, lsr #1
|
|
mov yl, yl, rrx
|
|
mov xl, #0x00100000
|
|
mov ip, #0x00080000
|
|
|
|
@ The actual division loop.
|
|
1: subs lr, r6, yl
|
|
sbcs lr, r5, yh
|
|
do_it cs, tt
|
|
subcs r6, r6, yl
|
|
movcs r5, lr
|
|
orrcs xl, xl, ip
|
|
movs yh, yh, lsr #1
|
|
mov yl, yl, rrx
|
|
subs lr, r6, yl
|
|
sbcs lr, r5, yh
|
|
do_it cs, tt
|
|
subcs r6, r6, yl
|
|
movcs r5, lr
|
|
orrcs xl, xl, ip, lsr #1
|
|
movs yh, yh, lsr #1
|
|
mov yl, yl, rrx
|
|
subs lr, r6, yl
|
|
sbcs lr, r5, yh
|
|
do_it cs, tt
|
|
subcs r6, r6, yl
|
|
movcs r5, lr
|
|
orrcs xl, xl, ip, lsr #2
|
|
movs yh, yh, lsr #1
|
|
mov yl, yl, rrx
|
|
subs lr, r6, yl
|
|
sbcs lr, r5, yh
|
|
do_it cs, tt
|
|
subcs r6, r6, yl
|
|
movcs r5, lr
|
|
orrcs xl, xl, ip, lsr #3
|
|
|
|
orrs lr, r5, r6
|
|
beq 2f
|
|
mov r5, r5, lsl #4
|
|
orr r5, r5, r6, lsr #28
|
|
mov r6, r6, lsl #4
|
|
mov yh, yh, lsl #3
|
|
orr yh, yh, yl, lsr #29
|
|
mov yl, yl, lsl #3
|
|
movs ip, ip, lsr #4
|
|
bne 1b
|
|
|
|
@ We are done with a word of the result.
|
|
@ Loop again for the low word if this pass was for the high word.
|
|
tst xh, #0x00100000
|
|
bne 3f
|
|
orr xh, xh, xl
|
|
mov xl, #0
|
|
mov ip, #0x80000000
|
|
b 1b
|
|
2:
|
|
@ Be sure result starts in the high word.
|
|
tst xh, #0x00100000
|
|
do_it eq, t
|
|
orreq xh, xh, xl
|
|
moveq xl, #0
|
|
3:
|
|
@ Check exponent range for under/overflow.
|
|
subs ip, r4, #(254 - 1)
|
|
do_it hi
|
|
cmphi ip, #0x700
|
|
bhi LSYM(Lml_u)
|
|
|
|
@ Round the result, merge final exponent.
|
|
subs ip, r5, yh
|
|
do_it eq, t
|
|
COND(sub,s,eq) ip, r6, yl
|
|
COND(mov,s,eq) ip, xl, lsr #1
|
|
adcs xl, xl, #0
|
|
adc xh, xh, r4, lsl #20
|
|
RETLDM "r4, r5, r6"
|
|
|
|
@ Division by 0x1p*: shortcut a lot of code.
|
|
LSYM(Ldv_1):
|
|
and lr, lr, #0x80000000
|
|
orr xh, lr, xh, lsr #12
|
|
adds r4, r4, ip, lsr #1
|
|
do_it gt, tt
|
|
COND(rsb,s,gt) r5, r4, ip
|
|
orrgt xh, xh, r4, lsl #20
|
|
RETLDM "r4, r5, r6" gt
|
|
|
|
orr xh, xh, #0x00100000
|
|
mov lr, #0
|
|
subs r4, r4, #1
|
|
b LSYM(Lml_u)
|
|
|
|
@ Result mightt need to be denormalized: put remainder bits
|
|
@ in lr for rounding considerations.
|
|
LSYM(Ldv_u):
|
|
orr lr, r5, r6
|
|
b LSYM(Lml_u)
|
|
|
|
@ One or both arguments is either INF, NAN or zero.
|
|
LSYM(Ldv_s):
|
|
and r5, ip, yh, lsr #20
|
|
teq r4, ip
|
|
do_it eq
|
|
teqeq r5, ip
|
|
beq LSYM(Lml_n) @ INF/NAN / INF/NAN -> NAN
|
|
teq r4, ip
|
|
bne 1f
|
|
orrs r4, xl, xh, lsl #12
|
|
bne LSYM(Lml_n) @ NAN / <anything> -> NAN
|
|
teq r5, ip
|
|
bne LSYM(Lml_i) @ INF / <anything> -> INF
|
|
mov xl, yl
|
|
mov xh, yh
|
|
b LSYM(Lml_n) @ INF / (INF or NAN) -> NAN
|
|
1: teq r5, ip
|
|
bne 2f
|
|
orrs r5, yl, yh, lsl #12
|
|
beq LSYM(Lml_z) @ <anything> / INF -> 0
|
|
mov xl, yl
|
|
mov xh, yh
|
|
b LSYM(Lml_n) @ <anything> / NAN -> NAN
|
|
2: @ If both are nonzero, we need to normalize and resume above.
|
|
orrs r6, xl, xh, lsl #1
|
|
do_it ne
|
|
COND(orr,s,ne) r6, yl, yh, lsl #1
|
|
bne LSYM(Lml_d)
|
|
@ One or both arguments are 0.
|
|
orrs r4, xl, xh, lsl #1
|
|
bne LSYM(Lml_i) @ <non_zero> / 0 -> INF
|
|
orrs r5, yl, yh, lsl #1
|
|
bne LSYM(Lml_z) @ 0 / <non_zero> -> 0
|
|
b LSYM(Lml_n) @ 0 / 0 -> NAN
|
|
|
|
FUNC_END aeabi_ddiv
|
|
FUNC_END divdf3
|
|
|
|
#endif /* L_muldivdf3 */
|
|
|
|
#ifdef L_arm_cmpdf2
|
|
|
|
@ Note: only r0 (return value) and ip are clobbered here.
|
|
|
|
ARM_FUNC_START gtdf2
|
|
ARM_FUNC_ALIAS gedf2 gtdf2
|
|
mov ip, #-1
|
|
b 1f
|
|
|
|
ARM_FUNC_START ltdf2
|
|
ARM_FUNC_ALIAS ledf2 ltdf2
|
|
mov ip, #1
|
|
b 1f
|
|
|
|
ARM_FUNC_START cmpdf2
|
|
ARM_FUNC_ALIAS nedf2 cmpdf2
|
|
ARM_FUNC_ALIAS eqdf2 cmpdf2
|
|
mov ip, #1 @ how should we specify unordered here?
|
|
|
|
1: str ip, [sp, #-4]!
|
|
|
|
@ Trap any INF/NAN first.
|
|
mov ip, xh, lsl #1
|
|
mvns ip, ip, asr #21
|
|
mov ip, yh, lsl #1
|
|
do_it ne
|
|
COND(mvn,s,ne) ip, ip, asr #21
|
|
beq 3f
|
|
|
|
@ Test for equality.
|
|
@ Note that 0.0 is equal to -0.0.
|
|
2: add sp, sp, #4
|
|
orrs ip, xl, xh, lsl #1 @ if x == 0.0 or -0.0
|
|
do_it eq, e
|
|
COND(orr,s,eq) ip, yl, yh, lsl #1 @ and y == 0.0 or -0.0
|
|
teqne xh, yh @ or xh == yh
|
|
do_it eq, tt
|
|
teqeq xl, yl @ and xl == yl
|
|
moveq r0, #0 @ then equal.
|
|
RETc(eq)
|
|
|
|
@ Clear C flag
|
|
cmn r0, #0
|
|
|
|
@ Compare sign,
|
|
teq xh, yh
|
|
|
|
@ Compare values if same sign
|
|
do_it pl
|
|
cmppl xh, yh
|
|
do_it eq
|
|
cmpeq xl, yl
|
|
|
|
@ Result:
|
|
do_it cs, e
|
|
movcs r0, yh, asr #31
|
|
mvncc r0, yh, asr #31
|
|
orr r0, r0, #1
|
|
RET
|
|
|
|
@ Look for a NAN.
|
|
3: mov ip, xh, lsl #1
|
|
mvns ip, ip, asr #21
|
|
bne 4f
|
|
orrs ip, xl, xh, lsl #12
|
|
bne 5f @ x is NAN
|
|
4: mov ip, yh, lsl #1
|
|
mvns ip, ip, asr #21
|
|
bne 2b
|
|
orrs ip, yl, yh, lsl #12
|
|
beq 2b @ y is not NAN
|
|
5: ldr r0, [sp], #4 @ unordered return code
|
|
RET
|
|
|
|
FUNC_END gedf2
|
|
FUNC_END gtdf2
|
|
FUNC_END ledf2
|
|
FUNC_END ltdf2
|
|
FUNC_END nedf2
|
|
FUNC_END eqdf2
|
|
FUNC_END cmpdf2
|
|
|
|
ARM_FUNC_START aeabi_cdrcmple
|
|
|
|
mov ip, r0
|
|
mov r0, r2
|
|
mov r2, ip
|
|
mov ip, r1
|
|
mov r1, r3
|
|
mov r3, ip
|
|
b 6f
|
|
|
|
ARM_FUNC_START aeabi_cdcmpeq
|
|
ARM_FUNC_ALIAS aeabi_cdcmple aeabi_cdcmpeq
|
|
|
|
@ The status-returning routines are required to preserve all
|
|
@ registers except ip, lr, and cpsr.
|
|
6: do_push {r0, lr}
|
|
ARM_CALL cmpdf2
|
|
@ Set the Z flag correctly, and the C flag unconditionally.
|
|
cmp r0, #0
|
|
@ Clear the C flag if the return value was -1, indicating
|
|
@ that the first operand was smaller than the second.
|
|
do_it mi
|
|
cmnmi r0, #0
|
|
RETLDM "r0"
|
|
|
|
FUNC_END aeabi_cdcmple
|
|
FUNC_END aeabi_cdcmpeq
|
|
FUNC_END aeabi_cdrcmple
|
|
|
|
ARM_FUNC_START aeabi_dcmpeq
|
|
|
|
str lr, [sp, #-8]!
|
|
ARM_CALL aeabi_cdcmple
|
|
do_it eq, e
|
|
moveq r0, #1 @ Equal to.
|
|
movne r0, #0 @ Less than, greater than, or unordered.
|
|
RETLDM
|
|
|
|
FUNC_END aeabi_dcmpeq
|
|
|
|
ARM_FUNC_START aeabi_dcmplt
|
|
|
|
str lr, [sp, #-8]!
|
|
ARM_CALL aeabi_cdcmple
|
|
do_it cc, e
|
|
movcc r0, #1 @ Less than.
|
|
movcs r0, #0 @ Equal to, greater than, or unordered.
|
|
RETLDM
|
|
|
|
FUNC_END aeabi_dcmplt
|
|
|
|
ARM_FUNC_START aeabi_dcmple
|
|
|
|
str lr, [sp, #-8]!
|
|
ARM_CALL aeabi_cdcmple
|
|
do_it ls, e
|
|
movls r0, #1 @ Less than or equal to.
|
|
movhi r0, #0 @ Greater than or unordered.
|
|
RETLDM
|
|
|
|
FUNC_END aeabi_dcmple
|
|
|
|
ARM_FUNC_START aeabi_dcmpge
|
|
|
|
str lr, [sp, #-8]!
|
|
ARM_CALL aeabi_cdrcmple
|
|
do_it ls, e
|
|
movls r0, #1 @ Operand 2 is less than or equal to operand 1.
|
|
movhi r0, #0 @ Operand 2 greater than operand 1, or unordered.
|
|
RETLDM
|
|
|
|
FUNC_END aeabi_dcmpge
|
|
|
|
ARM_FUNC_START aeabi_dcmpgt
|
|
|
|
str lr, [sp, #-8]!
|
|
ARM_CALL aeabi_cdrcmple
|
|
do_it cc, e
|
|
movcc r0, #1 @ Operand 2 is less than operand 1.
|
|
movcs r0, #0 @ Operand 2 is greater than or equal to operand 1,
|
|
@ or they are unordered.
|
|
RETLDM
|
|
|
|
FUNC_END aeabi_dcmpgt
|
|
|
|
#endif /* L_cmpdf2 */
|
|
|
|
#ifdef L_arm_unorddf2
|
|
|
|
ARM_FUNC_START unorddf2
|
|
ARM_FUNC_ALIAS aeabi_dcmpun unorddf2
|
|
|
|
mov ip, xh, lsl #1
|
|
mvns ip, ip, asr #21
|
|
bne 1f
|
|
orrs ip, xl, xh, lsl #12
|
|
bne 3f @ x is NAN
|
|
1: mov ip, yh, lsl #1
|
|
mvns ip, ip, asr #21
|
|
bne 2f
|
|
orrs ip, yl, yh, lsl #12
|
|
bne 3f @ y is NAN
|
|
2: mov r0, #0 @ arguments are ordered.
|
|
RET
|
|
|
|
3: mov r0, #1 @ arguments are unordered.
|
|
RET
|
|
|
|
FUNC_END aeabi_dcmpun
|
|
FUNC_END unorddf2
|
|
|
|
#endif /* L_unorddf2 */
|
|
|
|
#ifdef L_arm_fixdfsi
|
|
|
|
ARM_FUNC_START fixdfsi
|
|
ARM_FUNC_ALIAS aeabi_d2iz fixdfsi
|
|
|
|
@ check exponent range.
|
|
mov r2, xh, lsl #1
|
|
adds r2, r2, #(1 << 21)
|
|
bcs 2f @ value is INF or NAN
|
|
bpl 1f @ value is too small
|
|
mov r3, #(0xfffffc00 + 31)
|
|
subs r2, r3, r2, asr #21
|
|
bls 3f @ value is too large
|
|
|
|
@ scale value
|
|
mov r3, xh, lsl #11
|
|
orr r3, r3, #0x80000000
|
|
orr r3, r3, xl, lsr #21
|
|
tst xh, #0x80000000 @ the sign bit
|
|
shift1 lsr, r0, r3, r2
|
|
do_it ne
|
|
rsbne r0, r0, #0
|
|
RET
|
|
|
|
1: mov r0, #0
|
|
RET
|
|
|
|
2: orrs xl, xl, xh, lsl #12
|
|
bne 4f @ x is NAN.
|
|
3: ands r0, xh, #0x80000000 @ the sign bit
|
|
do_it eq
|
|
moveq r0, #0x7fffffff @ maximum signed positive si
|
|
RET
|
|
|
|
4: mov r0, #0 @ How should we convert NAN?
|
|
RET
|
|
|
|
FUNC_END aeabi_d2iz
|
|
FUNC_END fixdfsi
|
|
|
|
#endif /* L_fixdfsi */
|
|
|
|
#ifdef L_arm_fixunsdfsi
|
|
|
|
ARM_FUNC_START fixunsdfsi
|
|
ARM_FUNC_ALIAS aeabi_d2uiz fixunsdfsi
|
|
|
|
@ check exponent range.
|
|
movs r2, xh, lsl #1
|
|
bcs 1f @ value is negative
|
|
adds r2, r2, #(1 << 21)
|
|
bcs 2f @ value is INF or NAN
|
|
bpl 1f @ value is too small
|
|
mov r3, #(0xfffffc00 + 31)
|
|
subs r2, r3, r2, asr #21
|
|
bmi 3f @ value is too large
|
|
|
|
@ scale value
|
|
mov r3, xh, lsl #11
|
|
orr r3, r3, #0x80000000
|
|
orr r3, r3, xl, lsr #21
|
|
shift1 lsr, r0, r3, r2
|
|
RET
|
|
|
|
1: mov r0, #0
|
|
RET
|
|
|
|
2: orrs xl, xl, xh, lsl #12
|
|
bne 4f @ value is NAN.
|
|
3: mov r0, #0xffffffff @ maximum unsigned si
|
|
RET
|
|
|
|
4: mov r0, #0 @ How should we convert NAN?
|
|
RET
|
|
|
|
FUNC_END aeabi_d2uiz
|
|
FUNC_END fixunsdfsi
|
|
|
|
#endif /* L_fixunsdfsi */
|
|
|
|
#ifdef L_arm_truncdfsf2
|
|
|
|
ARM_FUNC_START truncdfsf2
|
|
ARM_FUNC_ALIAS aeabi_d2f truncdfsf2
|
|
|
|
@ check exponent range.
|
|
mov r2, xh, lsl #1
|
|
subs r3, r2, #((1023 - 127) << 21)
|
|
do_it cs, t
|
|
COND(sub,s,cs) ip, r3, #(1 << 21)
|
|
COND(rsb,s,cs) ip, ip, #(254 << 21)
|
|
bls 2f @ value is out of range
|
|
|
|
1: @ shift and round mantissa
|
|
and ip, xh, #0x80000000
|
|
mov r2, xl, lsl #3
|
|
orr xl, ip, xl, lsr #29
|
|
cmp r2, #0x80000000
|
|
adc r0, xl, r3, lsl #2
|
|
do_it eq
|
|
biceq r0, r0, #1
|
|
RET
|
|
|
|
2: @ either overflow or underflow
|
|
tst xh, #0x40000000
|
|
bne 3f @ overflow
|
|
|
|
@ check if denormalized value is possible
|
|
adds r2, r3, #(23 << 21)
|
|
do_it lt, t
|
|
andlt r0, xh, #0x80000000 @ too small, return signed 0.
|
|
RETc(lt)
|
|
|
|
@ denormalize value so we can resume with the code above afterwards.
|
|
orr xh, xh, #0x00100000
|
|
mov r2, r2, lsr #21
|
|
rsb r2, r2, #24
|
|
rsb ip, r2, #32
|
|
#if defined(__thumb2__)
|
|
lsls r3, xl, ip
|
|
#else
|
|
movs r3, xl, lsl ip
|
|
#endif
|
|
shift1 lsr, xl, xl, r2
|
|
do_it ne
|
|
orrne xl, xl, #1 @ fold r3 for rounding considerations.
|
|
mov r3, xh, lsl #11
|
|
mov r3, r3, lsr #11
|
|
shiftop orr xl xl r3 lsl ip ip
|
|
shift1 lsr, r3, r3, r2
|
|
mov r3, r3, lsl #1
|
|
b 1b
|
|
|
|
3: @ chech for NAN
|
|
mvns r3, r2, asr #21
|
|
bne 5f @ simple overflow
|
|
orrs r3, xl, xh, lsl #12
|
|
do_it ne, tt
|
|
movne r0, #0x7f000000
|
|
orrne r0, r0, #0x00c00000
|
|
RETc(ne) @ return NAN
|
|
|
|
5: @ return INF with sign
|
|
and r0, xh, #0x80000000
|
|
orr r0, r0, #0x7f000000
|
|
orr r0, r0, #0x00800000
|
|
RET
|
|
|
|
FUNC_END aeabi_d2f
|
|
FUNC_END truncdfsf2
|
|
|
|
#endif /* L_truncdfsf2 */
|