OpenCores
URL https://opencores.org/ocsvn/openrisc/openrisc/trunk

Subversion Repositories openrisc

[/] [openrisc/] [trunk/] [gnu-dev/] [or1k-gcc/] [libgcc/] [config/] [xtensa/] [ieee754-sf.S] - Rev 734

Compare with Previous | Blame | View Log

/* IEEE-754 single-precision functions for Xtensa
   Copyright (C) 2006, 2007, 2009 Free Software Foundation, Inc.
   Contributed by Bob Wilson (bwilson@tensilica.com) at Tensilica.

   This file is part of GCC.

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

   GCC 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/>.  */

#ifdef __XTENSA_EB__
#define xh a2
#define xl a3
#define yh a4
#define yl a5
#else
#define xh a3
#define xl a2
#define yh a5
#define yl a4
#endif

/*  Warning!  The branch displacements for some Xtensa branch instructions
    are quite small, and this code has been carefully laid out to keep
    branch targets in range.  If you change anything, be sure to check that
    the assembler is not relaxing anything to branch over a jump.  */

#ifdef L_negsf2

        .align  4
        .global __negsf2
        .type   __negsf2, @function
__negsf2:
        leaf_entry sp, 16
        movi    a4, 0x80000000
        xor     a2, a2, a4
        leaf_return

#endif /* L_negsf2 */

#ifdef L_addsubsf3

        /* Addition */
__addsf3_aux:

        /* Handle NaNs and Infinities.  (This code is placed before the
           start of the function just to keep it in range of the limited
           branch displacements.)  */

.Ladd_xnan_or_inf:
        /* If y is neither Infinity nor NaN, return x.  */
        bnall   a3, a6, 1f
        /* If x is a NaN, return it.  Otherwise, return y.  */
        slli    a7, a2, 9
        beqz    a7, .Ladd_ynan_or_inf
1:      leaf_return

.Ladd_ynan_or_inf:
        /* Return y.  */
        mov     a2, a3
        leaf_return

.Ladd_opposite_signs:
        /* Operand signs differ.  Do a subtraction.  */
        slli    a7, a6, 8
        xor     a3, a3, a7
        j       .Lsub_same_sign

        .align  4
        .global __addsf3
        .type   __addsf3, @function
__addsf3:
        leaf_entry sp, 16
        movi    a6, 0x7f800000

        /* Check if the two operands have the same sign.  */
        xor     a7, a2, a3
        bltz    a7, .Ladd_opposite_signs

.Ladd_same_sign:        
        /* Check if either exponent == 0x7f8 (i.e., NaN or Infinity).  */
        ball    a2, a6, .Ladd_xnan_or_inf
        ball    a3, a6, .Ladd_ynan_or_inf

        /* Compare the exponents.  The smaller operand will be shifted
           right by the exponent difference and added to the larger
           one.  */
        extui   a7, a2, 23, 9
        extui   a8, a3, 23, 9
        bltu    a7, a8, .Ladd_shiftx

.Ladd_shifty:
        /* Check if the smaller (or equal) exponent is zero.  */
        bnone   a3, a6, .Ladd_yexpzero

        /* Replace y sign/exponent with 0x008.  */
        or      a3, a3, a6
        slli    a3, a3, 8
        srli    a3, a3, 8

.Ladd_yexpdiff:
        /* Compute the exponent difference.  */
        sub     a10, a7, a8

        /* Exponent difference > 32 -- just return the bigger value.  */
        bgeui   a10, 32, 1f
        
        /* Shift y right by the exponent difference.  Any bits that are
           shifted out of y are saved in a9 for rounding the result.  */
        ssr     a10
        movi    a9, 0
        src     a9, a3, a9
        srl     a3, a3

        /* Do the addition.  */
        add     a2, a2, a3

        /* Check if the add overflowed into the exponent.  */
        extui   a10, a2, 23, 9
        beq     a10, a7, .Ladd_round
        mov     a8, a7
        j       .Ladd_carry

.Ladd_yexpzero:
        /* y is a subnormal value.  Replace its sign/exponent with zero,
           i.e., no implicit "1.0", and increment the apparent exponent
           because subnormals behave as if they had the minimum (nonzero)
           exponent.  Test for the case when both exponents are zero.  */
        slli    a3, a3, 9
        srli    a3, a3, 9
        bnone   a2, a6, .Ladd_bothexpzero
        addi    a8, a8, 1
        j       .Ladd_yexpdiff

.Ladd_bothexpzero:
        /* Both exponents are zero.  Handle this as a special case.  There
           is no need to shift or round, and the normal code for handling
           a carry into the exponent field will not work because it
           assumes there is an implicit "1.0" that needs to be added.  */
        add     a2, a2, a3
1:      leaf_return

.Ladd_xexpzero:
        /* Same as "yexpzero" except skip handling the case when both
           exponents are zero.  */
        slli    a2, a2, 9
        srli    a2, a2, 9
        addi    a7, a7, 1
        j       .Ladd_xexpdiff

.Ladd_shiftx:
        /* Same thing as the "shifty" code, but with x and y swapped.  Also,
           because the exponent difference is always nonzero in this version,
           the shift sequence can use SLL and skip loading a constant zero.  */
        bnone   a2, a6, .Ladd_xexpzero

        or      a2, a2, a6
        slli    a2, a2, 8
        srli    a2, a2, 8

.Ladd_xexpdiff:
        sub     a10, a8, a7
        bgeui   a10, 32, .Ladd_returny
        
        ssr     a10
        sll     a9, a2
        srl     a2, a2

        add     a2, a2, a3

        /* Check if the add overflowed into the exponent.  */
        extui   a10, a2, 23, 9
        bne     a10, a8, .Ladd_carry

.Ladd_round:
        /* Round up if the leftover fraction is >= 1/2.  */
        bgez    a9, 1f
        addi    a2, a2, 1

        /* Check if the leftover fraction is exactly 1/2.  */
        slli    a9, a9, 1
        beqz    a9, .Ladd_exactlyhalf
1:      leaf_return

.Ladd_returny:
        mov     a2, a3
        leaf_return

.Ladd_carry:    
        /* The addition has overflowed into the exponent field, so the
           value needs to be renormalized.  The mantissa of the result
           can be recovered by subtracting the original exponent and
           adding 0x800000 (which is the explicit "1.0" for the
           mantissa of the non-shifted operand -- the "1.0" for the
           shifted operand was already added).  The mantissa can then
           be shifted right by one bit.  The explicit "1.0" of the
           shifted mantissa then needs to be replaced by the exponent,
           incremented by one to account for the normalizing shift.
           It is faster to combine these operations: do the shift first
           and combine the additions and subtractions.  If x is the
           original exponent, the result is:
               shifted mantissa - (x << 22) + (1 << 22) + (x << 23)
           or:
               shifted mantissa + ((x + 1) << 22)
           Note that the exponent is incremented here by leaving the
           explicit "1.0" of the mantissa in the exponent field.  */

        /* Shift x right by one bit.  Save the lsb.  */
        mov     a10, a2
        srli    a2, a2, 1

        /* See explanation above.  The original exponent is in a8.  */
        addi    a8, a8, 1
        slli    a8, a8, 22
        add     a2, a2, a8

        /* Return an Infinity if the exponent overflowed.  */
        ball    a2, a6, .Ladd_infinity
        
        /* Same thing as the "round" code except the msb of the leftover
           fraction is bit 0 of a10, with the rest of the fraction in a9.  */
        bbci.l  a10, 0, 1f
        addi    a2, a2, 1
        beqz    a9, .Ladd_exactlyhalf
1:      leaf_return

.Ladd_infinity:
        /* Clear the mantissa.  */
        srli    a2, a2, 23
        slli    a2, a2, 23

        /* The sign bit may have been lost in a carry-out.  Put it back.  */
        slli    a8, a8, 1
        or      a2, a2, a8
        leaf_return

.Ladd_exactlyhalf:
        /* Round down to the nearest even value.  */
        srli    a2, a2, 1
        slli    a2, a2, 1
        leaf_return


        /* Subtraction */
__subsf3_aux:
        
        /* Handle NaNs and Infinities.  (This code is placed before the
           start of the function just to keep it in range of the limited
           branch displacements.)  */

.Lsub_xnan_or_inf:
        /* If y is neither Infinity nor NaN, return x.  */
        bnall   a3, a6, 1f
        /* Both x and y are either NaN or Inf, so the result is NaN.  */
        movi    a4, 0x400000    /* make it a quiet NaN */
        or      a2, a2, a4
1:      leaf_return

.Lsub_ynan_or_inf:
        /* Negate y and return it.  */
        slli    a7, a6, 8
        xor     a2, a3, a7
        leaf_return

.Lsub_opposite_signs:
        /* Operand signs differ.  Do an addition.  */
        slli    a7, a6, 8
        xor     a3, a3, a7
        j       .Ladd_same_sign

        .align  4
        .global __subsf3
        .type   __subsf3, @function
__subsf3:
        leaf_entry sp, 16
        movi    a6, 0x7f800000

        /* Check if the two operands have the same sign.  */
        xor     a7, a2, a3
        bltz    a7, .Lsub_opposite_signs

.Lsub_same_sign:        
        /* Check if either exponent == 0x7f8 (i.e., NaN or Infinity).  */
        ball    a2, a6, .Lsub_xnan_or_inf
        ball    a3, a6, .Lsub_ynan_or_inf

        /* Compare the operands.  In contrast to addition, the entire
           value matters here.  */
        extui   a7, a2, 23, 8
        extui   a8, a3, 23, 8
        bltu    a2, a3, .Lsub_xsmaller

.Lsub_ysmaller:
        /* Check if the smaller (or equal) exponent is zero.  */
        bnone   a3, a6, .Lsub_yexpzero

        /* Replace y sign/exponent with 0x008.  */
        or      a3, a3, a6
        slli    a3, a3, 8
        srli    a3, a3, 8

.Lsub_yexpdiff:
        /* Compute the exponent difference.  */
        sub     a10, a7, a8

        /* Exponent difference > 32 -- just return the bigger value.  */
        bgeui   a10, 32, 1f
        
        /* Shift y right by the exponent difference.  Any bits that are
           shifted out of y are saved in a9 for rounding the result.  */
        ssr     a10
        movi    a9, 0
        src     a9, a3, a9
        srl     a3, a3

        sub     a2, a2, a3

        /* Subtract the leftover bits in a9 from zero and propagate any
           borrow from a2.  */
        neg     a9, a9
        addi    a10, a2, -1
        movnez  a2, a10, a9

        /* Check if the subtract underflowed into the exponent.  */
        extui   a10, a2, 23, 8
        beq     a10, a7, .Lsub_round
        j       .Lsub_borrow

.Lsub_yexpzero:
        /* Return zero if the inputs are equal.  (For the non-subnormal
           case, subtracting the "1.0" will cause a borrow from the exponent
           and this case can be detected when handling the borrow.)  */
        beq     a2, a3, .Lsub_return_zero

        /* y is a subnormal value.  Replace its sign/exponent with zero,
           i.e., no implicit "1.0".  Unless x is also a subnormal, increment
           y's apparent exponent because subnormals behave as if they had
           the minimum (nonzero) exponent.  */
        slli    a3, a3, 9
        srli    a3, a3, 9
        bnone   a2, a6, .Lsub_yexpdiff
        addi    a8, a8, 1
        j       .Lsub_yexpdiff

.Lsub_returny:
        /* Negate and return y.  */
        slli    a7, a6, 8
        xor     a2, a3, a7
1:      leaf_return

.Lsub_xsmaller:
        /* Same thing as the "ysmaller" code, but with x and y swapped and
           with y negated.  */
        bnone   a2, a6, .Lsub_xexpzero

        or      a2, a2, a6
        slli    a2, a2, 8
        srli    a2, a2, 8

.Lsub_xexpdiff:
        sub     a10, a8, a7
        bgeui   a10, 32, .Lsub_returny
        
        ssr     a10
        movi    a9, 0
        src     a9, a2, a9
        srl     a2, a2

        /* Negate y.  */
        slli    a11, a6, 8
        xor     a3, a3, a11

        sub     a2, a3, a2

        neg     a9, a9
        addi    a10, a2, -1
        movnez  a2, a10, a9

        /* Check if the subtract underflowed into the exponent.  */
        extui   a10, a2, 23, 8
        bne     a10, a8, .Lsub_borrow

.Lsub_round:
        /* Round up if the leftover fraction is >= 1/2.  */
        bgez    a9, 1f
        addi    a2, a2, 1

        /* Check if the leftover fraction is exactly 1/2.  */
        slli    a9, a9, 1
        beqz    a9, .Lsub_exactlyhalf
1:      leaf_return

.Lsub_xexpzero:
        /* Same as "yexpzero".  */
        beq     a2, a3, .Lsub_return_zero
        slli    a2, a2, 9
        srli    a2, a2, 9
        bnone   a3, a6, .Lsub_xexpdiff
        addi    a7, a7, 1
        j       .Lsub_xexpdiff

.Lsub_return_zero:
        movi    a2, 0
        leaf_return

.Lsub_borrow:   
        /* The subtraction has underflowed into the exponent field, so the
           value needs to be renormalized.  Shift the mantissa left as
           needed to remove any leading zeros and adjust the exponent
           accordingly.  If the exponent is not large enough to remove
           all the leading zeros, the result will be a subnormal value.  */

        slli    a8, a2, 9
        beqz    a8, .Lsub_xzero
        do_nsau a6, a8, a7, a11
        srli    a8, a8, 9
        bge     a6, a10, .Lsub_subnormal
        addi    a6, a6, 1

.Lsub_normalize_shift:
        /* Shift the mantissa (a8/a9) left by a6.  */
        ssl     a6
        src     a8, a8, a9
        sll     a9, a9

        /* Combine the shifted mantissa with the sign and exponent,
           decrementing the exponent by a6.  (The exponent has already
           been decremented by one due to the borrow from the subtraction,
           but adding the mantissa will increment the exponent by one.)  */
        srli    a2, a2, 23
        sub     a2, a2, a6
        slli    a2, a2, 23
        add     a2, a2, a8
        j       .Lsub_round

.Lsub_exactlyhalf:
        /* Round down to the nearest even value.  */
        srli    a2, a2, 1
        slli    a2, a2, 1
        leaf_return

.Lsub_xzero:
        /* If there was a borrow from the exponent, and the mantissa and
           guard digits are all zero, then the inputs were equal and the
           result should be zero.  */
        beqz    a9, .Lsub_return_zero

        /* Only the guard digit is nonzero.  Shift by min(24, a10).  */
        addi    a11, a10, -24
        movi    a6, 24
        movltz  a6, a10, a11
        j       .Lsub_normalize_shift

.Lsub_subnormal:
        /* The exponent is too small to shift away all the leading zeros.
           Set a6 to the current exponent (which has already been
           decremented by the borrow) so that the exponent of the result
           will be zero.  Do not add 1 to a6 in this case, because: (1)
           adding the mantissa will not increment the exponent, so there is
           no need to subtract anything extra from the exponent to
           compensate, and (2) the effective exponent of a subnormal is 1
           not 0 so the shift amount must be 1 smaller than normal. */
        mov     a6, a10
        j       .Lsub_normalize_shift

#endif /* L_addsubsf3 */

#ifdef L_mulsf3

        /* Multiplication */
#if !XCHAL_HAVE_MUL16 && !XCHAL_HAVE_MUL32 && !XCHAL_HAVE_MAC16
#define XCHAL_NO_MUL 1
#endif

__mulsf3_aux:

        /* Handle unusual cases (zeros, subnormals, NaNs and Infinities).
           (This code is placed before the start of the function just to
           keep it in range of the limited branch displacements.)  */

.Lmul_xexpzero:
        /* Clear the sign bit of x.  */
        slli    a2, a2, 1
        srli    a2, a2, 1

        /* If x is zero, return zero.  */
        beqz    a2, .Lmul_return_zero

        /* Normalize x.  Adjust the exponent in a8.  */
        do_nsau a10, a2, a11, a12
        addi    a10, a10, -8
        ssl     a10
        sll     a2, a2 
        movi    a8, 1
        sub     a8, a8, a10
        j       .Lmul_xnormalized       
        
.Lmul_yexpzero:
        /* Clear the sign bit of y.  */
        slli    a3, a3, 1
        srli    a3, a3, 1

        /* If y is zero, return zero.  */
        beqz    a3, .Lmul_return_zero

        /* Normalize y.  Adjust the exponent in a9.  */
        do_nsau a10, a3, a11, a12
        addi    a10, a10, -8
        ssl     a10
        sll     a3, a3
        movi    a9, 1
        sub     a9, a9, a10
        j       .Lmul_ynormalized       

.Lmul_return_zero:
        /* Return zero with the appropriate sign bit.  */
        srli    a2, a7, 31
        slli    a2, a2, 31
        j       .Lmul_done

.Lmul_xnan_or_inf:
        /* If y is zero, return NaN.  */
        slli    a8, a3, 1
        bnez    a8, 1f
        movi    a4, 0x400000    /* make it a quiet NaN */
        or      a2, a2, a4
        j       .Lmul_done
1:
        /* If y is NaN, return y.  */
        bnall   a3, a6, .Lmul_returnx
        slli    a8, a3, 9
        beqz    a8, .Lmul_returnx

.Lmul_returny:
        mov     a2, a3

.Lmul_returnx:
        /* Set the sign bit and return.  */
        extui   a7, a7, 31, 1
        slli    a2, a2, 1
        ssai    1
        src     a2, a7, a2
        j       .Lmul_done

.Lmul_ynan_or_inf:
        /* If x is zero, return NaN.  */
        slli    a8, a2, 1
        bnez    a8, .Lmul_returny
        movi    a7, 0x400000    /* make it a quiet NaN */
        or      a2, a3, a7
        j       .Lmul_done

        .align  4
        .global __mulsf3
        .type   __mulsf3, @function
__mulsf3:
#if __XTENSA_CALL0_ABI__
        leaf_entry sp, 32
        addi    sp, sp, -32
        s32i    a12, sp, 16
        s32i    a13, sp, 20
        s32i    a14, sp, 24
        s32i    a15, sp, 28
#elif XCHAL_NO_MUL
        /* This is not really a leaf function; allocate enough stack space
           to allow CALL12s to a helper function.  */
        leaf_entry sp, 64
#else
        leaf_entry sp, 32
#endif
        movi    a6, 0x7f800000

        /* Get the sign of the result.  */
        xor     a7, a2, a3

        /* Check for NaN and infinity.  */
        ball    a2, a6, .Lmul_xnan_or_inf
        ball    a3, a6, .Lmul_ynan_or_inf

        /* Extract the exponents.  */
        extui   a8, a2, 23, 8
        extui   a9, a3, 23, 8

        beqz    a8, .Lmul_xexpzero
.Lmul_xnormalized:      
        beqz    a9, .Lmul_yexpzero
.Lmul_ynormalized:      

        /* Add the exponents.  */
        add     a8, a8, a9

        /* Replace sign/exponent fields with explicit "1.0".  */
        movi    a10, 0xffffff
        or      a2, a2, a6
        and     a2, a2, a10
        or      a3, a3, a6
        and     a3, a3, a10

        /* Multiply 32x32 to 64 bits.  The result ends up in a2/a6.  */

#if XCHAL_HAVE_MUL32_HIGH

        mull    a6, a2, a3
        muluh   a2, a2, a3

#else

        /* Break the inputs into 16-bit chunks and compute 4 32-bit partial
           products.  These partial products are:

                0 xl * yl

                1 xl * yh
                2 xh * yl

                3 xh * yh

           If using the Mul16 or Mul32 multiplier options, these input
           chunks must be stored in separate registers.  For Mac16, the
           UMUL.AA.* opcodes can specify that the inputs come from either
           half of the registers, so there is no need to shift them out
           ahead of time.  If there is no multiply hardware, the 16-bit
           chunks can be extracted when setting up the arguments to the
           separate multiply function.  */

#if __XTENSA_CALL0_ABI__ && XCHAL_NO_MUL
        /* Calling a separate multiply function will clobber a0 and requires
           use of a8 as a temporary, so save those values now.  (The function
           uses a custom ABI so nothing else needs to be saved.)  */
        s32i    a0, sp, 0
        s32i    a8, sp, 4
#endif

#if XCHAL_HAVE_MUL16 || XCHAL_HAVE_MUL32

#define a2h a4
#define a3h a5

        /* Get the high halves of the inputs into registers.  */
        srli    a2h, a2, 16
        srli    a3h, a3, 16

#define a2l a2
#define a3l a3

#if XCHAL_HAVE_MUL32 && !XCHAL_HAVE_MUL16
        /* Clear the high halves of the inputs.  This does not matter
           for MUL16 because the high bits are ignored.  */
        extui   a2, a2, 0, 16
        extui   a3, a3, 0, 16
#endif
#endif /* MUL16 || MUL32 */


#if XCHAL_HAVE_MUL16

#define do_mul(dst, xreg, xhalf, yreg, yhalf) \
        mul16u  dst, xreg ## xhalf, yreg ## yhalf

#elif XCHAL_HAVE_MUL32

#define do_mul(dst, xreg, xhalf, yreg, yhalf) \
        mull    dst, xreg ## xhalf, yreg ## yhalf

#elif XCHAL_HAVE_MAC16

/* The preprocessor insists on inserting a space when concatenating after
   a period in the definition of do_mul below.  These macros are a workaround
   using underscores instead of periods when doing the concatenation.  */
#define umul_aa_ll umul.aa.ll
#define umul_aa_lh umul.aa.lh
#define umul_aa_hl umul.aa.hl
#define umul_aa_hh umul.aa.hh

#define do_mul(dst, xreg, xhalf, yreg, yhalf) \
        umul_aa_ ## xhalf ## yhalf      xreg, yreg; \
        rsr     dst, ACCLO

#else /* no multiply hardware */
        
#define set_arg_l(dst, src) \
        extui   dst, src, 0, 16
#define set_arg_h(dst, src) \
        srli    dst, src, 16

#if __XTENSA_CALL0_ABI__
#define do_mul(dst, xreg, xhalf, yreg, yhalf) \
        set_arg_ ## xhalf (a13, xreg); \
        set_arg_ ## yhalf (a14, yreg); \
        call0   .Lmul_mulsi3; \
        mov     dst, a12
#else
#define do_mul(dst, xreg, xhalf, yreg, yhalf) \
        set_arg_ ## xhalf (a14, xreg); \
        set_arg_ ## yhalf (a15, yreg); \
        call12  .Lmul_mulsi3; \
        mov     dst, a14
#endif /* __XTENSA_CALL0_ABI__ */

#endif /* no multiply hardware */

        /* Add pp1 and pp2 into a6 with carry-out in a9.  */
        do_mul(a6, a2, l, a3, h)        /* pp 1 */
        do_mul(a11, a2, h, a3, l)       /* pp 2 */
        movi    a9, 0
        add     a6, a6, a11
        bgeu    a6, a11, 1f
        addi    a9, a9, 1
1:
        /* Shift the high half of a9/a6 into position in a9.  Note that
           this value can be safely incremented without any carry-outs.  */
        ssai    16
        src     a9, a9, a6

        /* Compute the low word into a6.  */
        do_mul(a11, a2, l, a3, l)       /* pp 0 */
        sll     a6, a6
        add     a6, a6, a11
        bgeu    a6, a11, 1f
        addi    a9, a9, 1
1:
        /* Compute the high word into a2.  */
        do_mul(a2, a2, h, a3, h)        /* pp 3 */
        add     a2, a2, a9
        
#if __XTENSA_CALL0_ABI__ && XCHAL_NO_MUL
        /* Restore values saved on the stack during the multiplication.  */
        l32i    a0, sp, 0
        l32i    a8, sp, 4
#endif
#endif /* ! XCHAL_HAVE_MUL32_HIGH */

        /* Shift left by 9 bits, unless there was a carry-out from the
           multiply, in which case, shift by 8 bits and increment the
           exponent.  */
        movi    a4, 9
        srli    a5, a2, 24 - 9
        beqz    a5, 1f
        addi    a4, a4, -1
        addi    a8, a8, 1
1:      ssl     a4
        src     a2, a2, a6
        sll     a6, a6

        /* Subtract the extra bias from the exponent sum (plus one to account
           for the explicit "1.0" of the mantissa that will be added to the
           exponent in the final result).  */
        movi    a4, 0x80
        sub     a8, a8, a4
        
        /* Check for over/underflow.  The value in a8 is one less than the
           final exponent, so values in the range 0..fd are OK here.  */
        movi    a4, 0xfe
        bgeu    a8, a4, .Lmul_overflow
        
.Lmul_round:
        /* Round.  */
        bgez    a6, .Lmul_rounded
        addi    a2, a2, 1
        slli    a6, a6, 1
        beqz    a6, .Lmul_exactlyhalf

.Lmul_rounded:
        /* Add the exponent to the mantissa.  */
        slli    a8, a8, 23
        add     a2, a2, a8

.Lmul_addsign:
        /* Add the sign bit.  */
        srli    a7, a7, 31
        slli    a7, a7, 31
        or      a2, a2, a7

.Lmul_done:
#if __XTENSA_CALL0_ABI__
        l32i    a12, sp, 16
        l32i    a13, sp, 20
        l32i    a14, sp, 24
        l32i    a15, sp, 28
        addi    sp, sp, 32
#endif
        leaf_return

.Lmul_exactlyhalf:
        /* Round down to the nearest even value.  */
        srli    a2, a2, 1
        slli    a2, a2, 1
        j       .Lmul_rounded

.Lmul_overflow:
        bltz    a8, .Lmul_underflow
        /* Return +/- Infinity.  */
        movi    a8, 0xff
        slli    a2, a8, 23
        j       .Lmul_addsign

.Lmul_underflow:
        /* Create a subnormal value, where the exponent field contains zero,
           but the effective exponent is 1.  The value of a8 is one less than
           the actual exponent, so just negate it to get the shift amount.  */
        neg     a8, a8
        mov     a9, a6
        ssr     a8
        bgeui   a8, 32, .Lmul_flush_to_zero
        
        /* Shift a2 right.  Any bits that are shifted out of a2 are saved
           in a6 (combined with the shifted-out bits currently in a6) for
           rounding the result.  */
        sll     a6, a2
        srl     a2, a2

        /* Set the exponent to zero.  */
        movi    a8, 0

        /* Pack any nonzero bits shifted out into a6.  */
        beqz    a9, .Lmul_round
        movi    a9, 1
        or      a6, a6, a9
        j       .Lmul_round
        
.Lmul_flush_to_zero:
        /* Return zero with the appropriate sign bit.  */
        srli    a2, a7, 31
        slli    a2, a2, 31
        j       .Lmul_done

#if XCHAL_NO_MUL
        
        /* For Xtensa processors with no multiply hardware, this simplified
           version of _mulsi3 is used for multiplying 16-bit chunks of
           the floating-point mantissas.  When using CALL0, this function
           uses a custom ABI: the inputs are passed in a13 and a14, the
           result is returned in a12, and a8 and a15 are clobbered.  */
        .align  4
.Lmul_mulsi3:
        leaf_entry sp, 16
        .macro mul_mulsi3_body dst, src1, src2, tmp1, tmp2
        movi    \dst, 0
1:      add     \tmp1, \src2, \dst
        extui   \tmp2, \src1, 0, 1
        movnez  \dst, \tmp1, \tmp2

        do_addx2 \tmp1, \src2, \dst, \tmp1
        extui   \tmp2, \src1, 1, 1
        movnez  \dst, \tmp1, \tmp2

        do_addx4 \tmp1, \src2, \dst, \tmp1
        extui   \tmp2, \src1, 2, 1
        movnez  \dst, \tmp1, \tmp2

        do_addx8 \tmp1, \src2, \dst, \tmp1
        extui   \tmp2, \src1, 3, 1
        movnez  \dst, \tmp1, \tmp2

        srli    \src1, \src1, 4
        slli    \src2, \src2, 4
        bnez    \src1, 1b
        .endm
#if __XTENSA_CALL0_ABI__
        mul_mulsi3_body a12, a13, a14, a15, a8
#else
        /* The result will be written into a2, so save that argument in a4.  */
        mov     a4, a2
        mul_mulsi3_body a2, a4, a3, a5, a6
#endif
        leaf_return
#endif /* XCHAL_NO_MUL */
#endif /* L_mulsf3 */

#ifdef L_divsf3

        /* Division */
__divsf3_aux:

        /* Handle unusual cases (zeros, subnormals, NaNs and Infinities).
           (This code is placed before the start of the function just to
           keep it in range of the limited branch displacements.)  */

.Ldiv_yexpzero:
        /* Clear the sign bit of y.  */
        slli    a3, a3, 1
        srli    a3, a3, 1

        /* Check for division by zero.  */
        beqz    a3, .Ldiv_yzero

        /* Normalize y.  Adjust the exponent in a9.  */
        do_nsau a10, a3, a4, a5
        addi    a10, a10, -8
        ssl     a10
        sll     a3, a3
        movi    a9, 1
        sub     a9, a9, a10
        j       .Ldiv_ynormalized       

.Ldiv_yzero:
        /* y is zero.  Return NaN if x is also zero; otherwise, infinity.  */
        slli    a4, a2, 1
        srli    a4, a4, 1
        srli    a2, a7, 31
        slli    a2, a2, 31
        or      a2, a2, a6
        bnez    a4, 1f
        movi    a4, 0x400000    /* make it a quiet NaN */
        or      a2, a2, a4
1:      leaf_return

.Ldiv_xexpzero:
        /* Clear the sign bit of x.  */
        slli    a2, a2, 1
        srli    a2, a2, 1

        /* If x is zero, return zero.  */
        beqz    a2, .Ldiv_return_zero

        /* Normalize x.  Adjust the exponent in a8.  */
        do_nsau a10, a2, a4, a5
        addi    a10, a10, -8
        ssl     a10
        sll     a2, a2
        movi    a8, 1
        sub     a8, a8, a10
        j       .Ldiv_xnormalized       
        
.Ldiv_return_zero:
        /* Return zero with the appropriate sign bit.  */
        srli    a2, a7, 31
        slli    a2, a2, 31
        leaf_return

.Ldiv_xnan_or_inf:
        /* Set the sign bit of the result.  */
        srli    a7, a3, 31
        slli    a7, a7, 31
        xor     a2, a2, a7
        /* If y is NaN or Inf, return NaN.  */
        bnall   a3, a6, 1f
        movi    a4, 0x400000    /* make it a quiet NaN */
        or      a2, a2, a4
1:      leaf_return

.Ldiv_ynan_or_inf:
        /* If y is Infinity, return zero.  */
        slli    a8, a3, 9
        beqz    a8, .Ldiv_return_zero
        /* y is NaN; return it.  */
        mov     a2, a3
        leaf_return

        .align  4
        .global __divsf3
        .type   __divsf3, @function
__divsf3:
        leaf_entry sp, 16
        movi    a6, 0x7f800000

        /* Get the sign of the result.  */
        xor     a7, a2, a3

        /* Check for NaN and infinity.  */
        ball    a2, a6, .Ldiv_xnan_or_inf
        ball    a3, a6, .Ldiv_ynan_or_inf

        /* Extract the exponents.  */
        extui   a8, a2, 23, 8
        extui   a9, a3, 23, 8

        beqz    a9, .Ldiv_yexpzero
.Ldiv_ynormalized:      
        beqz    a8, .Ldiv_xexpzero
.Ldiv_xnormalized:      

        /* Subtract the exponents.  */
        sub     a8, a8, a9

        /* Replace sign/exponent fields with explicit "1.0".  */
        movi    a10, 0xffffff
        or      a2, a2, a6
        and     a2, a2, a10
        or      a3, a3, a6
        and     a3, a3, a10

        /* The first digit of the mantissa division must be a one.
           Shift x (and adjust the exponent) as needed to make this true.  */
        bltu    a3, a2, 1f
        slli    a2, a2, 1
        addi    a8, a8, -1
1:
        /* Do the first subtraction and shift.  */
        sub     a2, a2, a3
        slli    a2, a2, 1

        /* Put the quotient into a10.  */
        movi    a10, 1

        /* Divide one bit at a time for 23 bits.  */
        movi    a9, 23
#if XCHAL_HAVE_LOOPS
        loop    a9, .Ldiv_loopend
#endif
.Ldiv_loop:
        /* Shift the quotient << 1.  */
        slli    a10, a10, 1

        /* Is this digit a 0 or 1?  */
        bltu    a2, a3, 1f

        /* Output a 1 and subtract.  */
        addi    a10, a10, 1
        sub     a2, a2, a3

        /* Shift the dividend << 1.  */
1:      slli    a2, a2, 1

#if !XCHAL_HAVE_LOOPS
        addi    a9, a9, -1
        bnez    a9, .Ldiv_loop
#endif
.Ldiv_loopend:

        /* Add the exponent bias (less one to account for the explicit "1.0"
           of the mantissa that will be added to the exponent in the final
           result).  */
        addi    a8, a8, 0x7e
        
        /* Check for over/underflow.  The value in a8 is one less than the
           final exponent, so values in the range 0..fd are OK here.  */
        movi    a4, 0xfe
        bgeu    a8, a4, .Ldiv_overflow
        
.Ldiv_round:
        /* Round.  The remainder (<< 1) is in a2.  */
        bltu    a2, a3, .Ldiv_rounded
        addi    a10, a10, 1
        beq     a2, a3, .Ldiv_exactlyhalf

.Ldiv_rounded:
        /* Add the exponent to the mantissa.  */
        slli    a8, a8, 23
        add     a2, a10, a8

.Ldiv_addsign:
        /* Add the sign bit.  */
        srli    a7, a7, 31
        slli    a7, a7, 31
        or      a2, a2, a7
        leaf_return

.Ldiv_overflow:
        bltz    a8, .Ldiv_underflow
        /* Return +/- Infinity.  */
        addi    a8, a4, 1       /* 0xff */
        slli    a2, a8, 23
        j       .Ldiv_addsign

.Ldiv_exactlyhalf:
        /* Remainder is exactly half the divisor.  Round even.  */
        srli    a10, a10, 1
        slli    a10, a10, 1
        j       .Ldiv_rounded

.Ldiv_underflow:
        /* Create a subnormal value, where the exponent field contains zero,
           but the effective exponent is 1.  The value of a8 is one less than
           the actual exponent, so just negate it to get the shift amount.  */
        neg     a8, a8
        ssr     a8
        bgeui   a8, 32, .Ldiv_flush_to_zero
        
        /* Shift a10 right.  Any bits that are shifted out of a10 are
           saved in a6 for rounding the result.  */
        sll     a6, a10
        srl     a10, a10

        /* Set the exponent to zero.  */
        movi    a8, 0

        /* Pack any nonzero remainder (in a2) into a6.  */
        beqz    a2, 1f
        movi    a9, 1
        or      a6, a6, a9
        
        /* Round a10 based on the bits shifted out into a6.  */
1:      bgez    a6, .Ldiv_rounded
        addi    a10, a10, 1
        slli    a6, a6, 1
        bnez    a6, .Ldiv_rounded
        srli    a10, a10, 1
        slli    a10, a10, 1
        j       .Ldiv_rounded

.Ldiv_flush_to_zero:
        /* Return zero with the appropriate sign bit.  */
        srli    a2, a7, 31
        slli    a2, a2, 31
        leaf_return

#endif /* L_divsf3 */

#ifdef L_cmpsf2

        /* Equal and Not Equal */

        .align  4
        .global __eqsf2
        .global __nesf2
        .set    __nesf2, __eqsf2
        .type   __eqsf2, @function
__eqsf2:
        leaf_entry sp, 16
        bne     a2, a3, 4f

        /* The values are equal but NaN != NaN.  Check the exponent.  */
        movi    a6, 0x7f800000
        ball    a2, a6, 3f

        /* Equal.  */
        movi    a2, 0
        leaf_return

        /* Not equal.  */
2:      movi    a2, 1
        leaf_return

        /* Check if the mantissas are nonzero.  */
3:      slli    a7, a2, 9
        j       5f

        /* Check if x and y are zero with different signs.  */
4:      or      a7, a2, a3
        slli    a7, a7, 1

        /* Equal if a7 == 0, where a7 is either abs(x | y) or the mantissa
           or x when exponent(x) = 0x7f8 and x == y.  */
5:      movi    a2, 0
        movi    a3, 1
        movnez  a2, a3, a7      
        leaf_return


        /* Greater Than */

        .align  4
        .global __gtsf2
        .type   __gtsf2, @function
__gtsf2:
        leaf_entry sp, 16
        movi    a6, 0x7f800000
        ball    a2, a6, 2f
1:      bnall   a3, a6, .Lle_cmp

        /* Check if y is a NaN.  */
        slli    a7, a3, 9
        beqz    a7, .Lle_cmp
        movi    a2, 0
        leaf_return

        /* Check if x is a NaN.  */
2:      slli    a7, a2, 9
        beqz    a7, 1b
        movi    a2, 0
        leaf_return


        /* Less Than or Equal */

        .align  4
        .global __lesf2
        .type   __lesf2, @function
__lesf2:
        leaf_entry sp, 16
        movi    a6, 0x7f800000
        ball    a2, a6, 2f
1:      bnall   a3, a6, .Lle_cmp

        /* Check if y is a NaN.  */
        slli    a7, a3, 9
        beqz    a7, .Lle_cmp
        movi    a2, 1
        leaf_return

        /* Check if x is a NaN.  */
2:      slli    a7, a2, 9
        beqz    a7, 1b
        movi    a2, 1
        leaf_return

.Lle_cmp:
        /* Check if x and y have different signs.  */
        xor     a7, a2, a3
        bltz    a7, .Lle_diff_signs

        /* Check if x is negative.  */
        bltz    a2, .Lle_xneg

        /* Check if x <= y.  */
        bltu    a3, a2, 5f
4:      movi    a2, 0
        leaf_return

.Lle_xneg:
        /* Check if y <= x.  */
        bgeu    a2, a3, 4b
5:      movi    a2, 1
        leaf_return

.Lle_diff_signs:
        bltz    a2, 4b

        /* Check if both x and y are zero.  */
        or      a7, a2, a3
        slli    a7, a7, 1
        movi    a2, 1
        movi    a3, 0
        moveqz  a2, a3, a7
        leaf_return


        /* Greater Than or Equal */

        .align  4
        .global __gesf2
        .type   __gesf2, @function
__gesf2:
        leaf_entry sp, 16
        movi    a6, 0x7f800000
        ball    a2, a6, 2f
1:      bnall   a3, a6, .Llt_cmp

        /* Check if y is a NaN.  */
        slli    a7, a3, 9
        beqz    a7, .Llt_cmp
        movi    a2, -1
        leaf_return

        /* Check if x is a NaN.  */
2:      slli    a7, a2, 9
        beqz    a7, 1b
        movi    a2, -1
        leaf_return


        /* Less Than */

        .align  4
        .global __ltsf2
        .type   __ltsf2, @function
__ltsf2:
        leaf_entry sp, 16
        movi    a6, 0x7f800000
        ball    a2, a6, 2f
1:      bnall   a3, a6, .Llt_cmp

        /* Check if y is a NaN.  */
        slli    a7, a3, 9
        beqz    a7, .Llt_cmp
        movi    a2, 0
        leaf_return

        /* Check if x is a NaN.  */
2:      slli    a7, a2, 9
        beqz    a7, 1b
        movi    a2, 0
        leaf_return

.Llt_cmp:
        /* Check if x and y have different signs.  */
        xor     a7, a2, a3
        bltz    a7, .Llt_diff_signs

        /* Check if x is negative.  */
        bltz    a2, .Llt_xneg

        /* Check if x < y.  */
        bgeu    a2, a3, 5f
4:      movi    a2, -1
        leaf_return

.Llt_xneg:
        /* Check if y < x.  */
        bltu    a3, a2, 4b
5:      movi    a2, 0
        leaf_return

.Llt_diff_signs:
        bgez    a2, 5b

        /* Check if both x and y are nonzero.  */
        or      a7, a2, a3
        slli    a7, a7, 1
        movi    a2, 0
        movi    a3, -1
        movnez  a2, a3, a7
        leaf_return


        /* Unordered */

        .align  4
        .global __unordsf2
        .type   __unordsf2, @function
__unordsf2:
        leaf_entry sp, 16
        movi    a6, 0x7f800000
        ball    a2, a6, 3f
1:      ball    a3, a6, 4f
2:      movi    a2, 0
        leaf_return

3:      slli    a7, a2, 9
        beqz    a7, 1b
        movi    a2, 1
        leaf_return

4:      slli    a7, a3, 9
        beqz    a7, 2b
        movi    a2, 1
        leaf_return

#endif /* L_cmpsf2 */

#ifdef L_fixsfsi

        .align  4
        .global __fixsfsi
        .type   __fixsfsi, @function
__fixsfsi:
        leaf_entry sp, 16

        /* Check for NaN and Infinity.  */
        movi    a6, 0x7f800000
        ball    a2, a6, .Lfixsfsi_nan_or_inf

        /* Extract the exponent and check if 0 < (exp - 0x7e) < 32.  */
        extui   a4, a2, 23, 8
        addi    a4, a4, -0x7e
        bgei    a4, 32, .Lfixsfsi_maxint
        blti    a4, 1, .Lfixsfsi_zero

        /* Add explicit "1.0" and shift << 8.  */
        or      a7, a2, a6
        slli    a5, a7, 8

        /* Shift back to the right, based on the exponent.  */
        ssl     a4              /* shift by 32 - a4 */
        srl     a5, a5

        /* Negate the result if sign != 0.  */
        neg     a2, a5
        movgez  a2, a5, a7
        leaf_return

.Lfixsfsi_nan_or_inf:
        /* Handle Infinity and NaN.  */
        slli    a4, a2, 9
        beqz    a4, .Lfixsfsi_maxint

        /* Translate NaN to +maxint.  */
        movi    a2, 0

.Lfixsfsi_maxint:
        slli    a4, a6, 8       /* 0x80000000 */
        addi    a5, a4, -1      /* 0x7fffffff */
        movgez  a4, a5, a2
        mov     a2, a4
        leaf_return

.Lfixsfsi_zero:
        movi    a2, 0
        leaf_return

#endif /* L_fixsfsi */

#ifdef L_fixsfdi

        .align  4
        .global __fixsfdi
        .type   __fixsfdi, @function
__fixsfdi:
        leaf_entry sp, 16

        /* Check for NaN and Infinity.  */
        movi    a6, 0x7f800000
        ball    a2, a6, .Lfixsfdi_nan_or_inf

        /* Extract the exponent and check if 0 < (exp - 0x7e) < 64.  */
        extui   a4, a2, 23, 8
        addi    a4, a4, -0x7e
        bgei    a4, 64, .Lfixsfdi_maxint
        blti    a4, 1, .Lfixsfdi_zero

        /* Add explicit "1.0" and shift << 8.  */
        or      a7, a2, a6
        slli    xh, a7, 8

        /* Shift back to the right, based on the exponent.  */
        ssl     a4              /* shift by 64 - a4 */
        bgei    a4, 32, .Lfixsfdi_smallshift
        srl     xl, xh
        movi    xh, 0

.Lfixsfdi_shifted:      
        /* Negate the result if sign != 0.  */
        bgez    a7, 1f
        neg     xl, xl
        neg     xh, xh
        beqz    xl, 1f
        addi    xh, xh, -1
1:      leaf_return

.Lfixsfdi_smallshift:
        movi    xl, 0
        sll     xl, xh
        srl     xh, xh
        j       .Lfixsfdi_shifted

.Lfixsfdi_nan_or_inf:
        /* Handle Infinity and NaN.  */
        slli    a4, a2, 9
        beqz    a4, .Lfixsfdi_maxint

        /* Translate NaN to +maxint.  */
        movi    a2, 0

.Lfixsfdi_maxint:
        slli    a7, a6, 8       /* 0x80000000 */
        bgez    a2, 1f
        mov     xh, a7
        movi    xl, 0
        leaf_return

1:      addi    xh, a7, -1      /* 0x7fffffff */
        movi    xl, -1
        leaf_return

.Lfixsfdi_zero:
        movi    xh, 0
        movi    xl, 0
        leaf_return

#endif /* L_fixsfdi */

#ifdef L_fixunssfsi

        .align  4
        .global __fixunssfsi
        .type   __fixunssfsi, @function
__fixunssfsi:
        leaf_entry sp, 16

        /* Check for NaN and Infinity.  */
        movi    a6, 0x7f800000
        ball    a2, a6, .Lfixunssfsi_nan_or_inf

        /* Extract the exponent and check if 0 <= (exp - 0x7f) < 32.  */
        extui   a4, a2, 23, 8
        addi    a4, a4, -0x7f
        bgei    a4, 32, .Lfixunssfsi_maxint
        bltz    a4, .Lfixunssfsi_zero

        /* Add explicit "1.0" and shift << 8.  */
        or      a7, a2, a6
        slli    a5, a7, 8

        /* Shift back to the right, based on the exponent.  */
        addi    a4, a4, 1
        beqi    a4, 32, .Lfixunssfsi_bigexp
        ssl     a4              /* shift by 32 - a4 */
        srl     a5, a5

        /* Negate the result if sign != 0.  */
        neg     a2, a5
        movgez  a2, a5, a7
        leaf_return

.Lfixunssfsi_nan_or_inf:
        /* Handle Infinity and NaN.  */
        slli    a4, a2, 9
        beqz    a4, .Lfixunssfsi_maxint

        /* Translate NaN to 0xffffffff.  */
        movi    a2, -1
        leaf_return

.Lfixunssfsi_maxint:
        slli    a4, a6, 8       /* 0x80000000 */
        movi    a5, -1          /* 0xffffffff */
        movgez  a4, a5, a2
        mov     a2, a4
        leaf_return

.Lfixunssfsi_zero:
        movi    a2, 0
        leaf_return

.Lfixunssfsi_bigexp:
        /* Handle unsigned maximum exponent case.  */
        bltz    a2, 1f
        mov     a2, a5          /* no shift needed */
        leaf_return

        /* Return 0x80000000 if negative.  */
1:      slli    a2, a6, 8
        leaf_return

#endif /* L_fixunssfsi */

#ifdef L_fixunssfdi

        .align  4
        .global __fixunssfdi
        .type   __fixunssfdi, @function
__fixunssfdi:
        leaf_entry sp, 16

        /* Check for NaN and Infinity.  */
        movi    a6, 0x7f800000
        ball    a2, a6, .Lfixunssfdi_nan_or_inf

        /* Extract the exponent and check if 0 <= (exp - 0x7f) < 64.  */
        extui   a4, a2, 23, 8
        addi    a4, a4, -0x7f
        bgei    a4, 64, .Lfixunssfdi_maxint
        bltz    a4, .Lfixunssfdi_zero

        /* Add explicit "1.0" and shift << 8.  */
        or      a7, a2, a6
        slli    xh, a7, 8

        /* Shift back to the right, based on the exponent.  */
        addi    a4, a4, 1
        beqi    a4, 64, .Lfixunssfdi_bigexp
        ssl     a4              /* shift by 64 - a4 */
        bgei    a4, 32, .Lfixunssfdi_smallshift
        srl     xl, xh
        movi    xh, 0

.Lfixunssfdi_shifted:
        /* Negate the result if sign != 0.  */
        bgez    a7, 1f
        neg     xl, xl
        neg     xh, xh
        beqz    xl, 1f
        addi    xh, xh, -1
1:      leaf_return

.Lfixunssfdi_smallshift:
        movi    xl, 0
        src     xl, xh, xl
        srl     xh, xh
        j       .Lfixunssfdi_shifted

.Lfixunssfdi_nan_or_inf:
        /* Handle Infinity and NaN.  */
        slli    a4, a2, 9
        beqz    a4, .Lfixunssfdi_maxint

        /* Translate NaN to 0xffffffff.... */
1:      movi    xh, -1
        movi    xl, -1
        leaf_return

.Lfixunssfdi_maxint:
        bgez    a2, 1b
2:      slli    xh, a6, 8       /* 0x80000000 */
        movi    xl, 0
        leaf_return

.Lfixunssfdi_zero:
        movi    xh, 0
        movi    xl, 0
        leaf_return

.Lfixunssfdi_bigexp:
        /* Handle unsigned maximum exponent case.  */
        bltz    a7, 2b
        movi    xl, 0
        leaf_return             /* no shift needed */

#endif /* L_fixunssfdi */

#ifdef L_floatsisf

        .align  4
        .global __floatunsisf
        .type   __floatunsisf, @function
__floatunsisf:
        leaf_entry sp, 16
        beqz    a2, .Lfloatsisf_return

        /* Set the sign to zero and jump to the floatsisf code.  */
        movi    a7, 0
        j       .Lfloatsisf_normalize

        .align  4
        .global __floatsisf
        .type   __floatsisf, @function
__floatsisf:
        leaf_entry sp, 16

        /* Check for zero.  */
        beqz    a2, .Lfloatsisf_return

        /* Save the sign.  */
        extui   a7, a2, 31, 1

        /* Get the absolute value.  */
#if XCHAL_HAVE_ABS
        abs     a2, a2
#else
        neg     a4, a2
        movltz  a2, a4, a2
#endif

.Lfloatsisf_normalize:
        /* Normalize with the first 1 bit in the msb.  */
        do_nsau a4, a2, a5, a6
        ssl     a4
        sll     a5, a2

        /* Shift the mantissa into position, with rounding bits in a6.  */
        srli    a2, a5, 8
        slli    a6, a5, (32 - 8)

        /* Set the exponent.  */
        movi    a5, 0x9d        /* 0x7e + 31 */
        sub     a5, a5, a4
        slli    a5, a5, 23
        add     a2, a2, a5

        /* Add the sign.  */
        slli    a7, a7, 31
        or      a2, a2, a7

        /* Round up if the leftover fraction is >= 1/2.  */
        bgez    a6, .Lfloatsisf_return
        addi    a2, a2, 1       /* Overflow to the exponent is OK.  */

        /* Check if the leftover fraction is exactly 1/2.  */
        slli    a6, a6, 1
        beqz    a6, .Lfloatsisf_exactlyhalf

.Lfloatsisf_return:
        leaf_return

.Lfloatsisf_exactlyhalf:
        /* Round down to the nearest even value.  */
        srli    a2, a2, 1
        slli    a2, a2, 1
        leaf_return

#endif /* L_floatsisf */

#ifdef L_floatdisf

        .align  4
        .global __floatundisf
        .type   __floatundisf, @function
__floatundisf:
        leaf_entry sp, 16

        /* Check for zero.  */
        or      a4, xh, xl
        beqz    a4, 2f

        /* Set the sign to zero and jump to the floatdisf code.  */
        movi    a7, 0
        j       .Lfloatdisf_normalize

        .align  4
        .global __floatdisf
        .type   __floatdisf, @function
__floatdisf:
        leaf_entry sp, 16

        /* Check for zero.  */
        or      a4, xh, xl
        beqz    a4, 2f

        /* Save the sign.  */
        extui   a7, xh, 31, 1

        /* Get the absolute value.  */
        bgez    xh, .Lfloatdisf_normalize
        neg     xl, xl
        neg     xh, xh
        beqz    xl, .Lfloatdisf_normalize
        addi    xh, xh, -1

.Lfloatdisf_normalize:
        /* Normalize with the first 1 bit in the msb of xh.  */
        beqz    xh, .Lfloatdisf_bigshift
        do_nsau a4, xh, a5, a6
        ssl     a4
        src     xh, xh, xl
        sll     xl, xl

.Lfloatdisf_shifted:
        /* Shift the mantissa into position, with rounding bits in a6.  */
        ssai    8
        sll     a5, xl
        src     a6, xh, xl
        srl     xh, xh
        beqz    a5, 1f
        movi    a5, 1
        or      a6, a6, a5
1:
        /* Set the exponent.  */
        movi    a5, 0xbd        /* 0x7e + 63 */
        sub     a5, a5, a4
        slli    a5, a5, 23
        add     a2, xh, a5

        /* Add the sign.  */
        slli    a7, a7, 31
        or      a2, a2, a7

        /* Round up if the leftover fraction is >= 1/2.  */
        bgez    a6, 2f
        addi    a2, a2, 1       /* Overflow to the exponent is OK.  */

        /* Check if the leftover fraction is exactly 1/2.  */
        slli    a6, a6, 1
        beqz    a6, .Lfloatdisf_exactlyhalf
2:      leaf_return

.Lfloatdisf_bigshift:
        /* xh is zero.  Normalize with first 1 bit of xl in the msb of xh.  */
        do_nsau a4, xl, a5, a6
        ssl     a4
        sll     xh, xl
        movi    xl, 0
        addi    a4, a4, 32
        j       .Lfloatdisf_shifted

.Lfloatdisf_exactlyhalf:
        /* Round down to the nearest even value.  */
        srli    a2, a2, 1
        slli    a2, a2, 1
        leaf_return

#endif /* L_floatdisf */

Compare with Previous | Blame | View Log

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.