diff --git a/liba/Makefile b/liba/Makefile index 7907686c8..345c7692e 100644 --- a/liba/Makefile +++ b/liba/Makefile @@ -137,12 +137,13 @@ endif tests += $(addprefix liba/test/, \ aeabi.c \ + double.c \ ieee754.c \ + long.c \ setjmp.c \ stddef.c \ stdint.c \ strlcpy.c \ - double.c \ ) # The use of aeabi-rt could be made conditional to an AEABI target. @@ -152,6 +153,7 @@ objs += $(addprefix liba/src/aeabi-rt/, \ double.o \ llsl.o \ llsr.o \ + long.o \ memclr.o \ memcpy.o \ ) @@ -169,6 +171,7 @@ objs += $(addprefix liba/src/external/softfloat/src/, \ 8086/s_propagateNaNF64UI.o \ 8086/softfloat_raiseFlags.o \ f32_to_f64.o \ + f32_to_i64_r_minMag.o\ f64_add.o \ f64_div.o \ f64_eq.o \ @@ -177,8 +180,11 @@ objs += $(addprefix liba/src/external/softfloat/src/, \ f64_mul.o \ f64_sub.o \ f64_to_i32_r_minMag.o \ + f64_to_i64_r_minMag.o \ f64_to_f32.o \ i32_to_f64.o \ + i64_to_f32.o \ + i64_to_f64.o \ s_addMagsF64.o \ s_approxRecip32_1.o \ s_approxRecip_1Ks.o \ diff --git a/liba/include/stdint.h b/liba/include/stdint.h index db274d276..e62a69e96 100644 --- a/liba/include/stdint.h +++ b/liba/include/stdint.h @@ -27,5 +27,6 @@ typedef int64_t int_fast64_t; typedef uint8_t uint_least8_t; #define UINT64_C(c) c ## ULL +#define INT64_C(c) c ## LL #endif diff --git a/liba/src/aeabi-rt/double.c b/liba/src/aeabi-rt/double.c index e61e8f9ec..224f5427a 100644 --- a/liba/src/aeabi-rt/double.c +++ b/liba/src/aeabi-rt/double.c @@ -1,55 +1,6 @@ /* See the "Run-time ABI for the ARM Architecture", Section 4.1.2 */ -#include -#include "../external/softfloat/port/softfloat.h" - -/* To avoid any issue due to procedure call conventions, we convert softfloat - * double 'aeabi_double_t' (respectively 'aeabi_float_t') to float64_t (to - * respectively float32_t) before or/and after calling softfloat functions. */ - -typedef unsigned aeabi_float_t; -typedef unsigned long long aeabi_double_t; - -static inline float32_t f32(aeabi_float_t f) { - union { - aeabi_float_t in; - float32_t out; - } res = {.in = f}; - assert(sizeof(aeabi_float_t) == sizeof(float32_t)); - assert(sizeof(res) == sizeof(float32_t)); - return res.out; -} - -static inline aeabi_float_t f(float32_t f) { - union { - float32_t in; - aeabi_float_t out; - } res = {.in = f}; - assert(sizeof(aeabi_float_t) == sizeof(float32_t)); - assert(sizeof(res) == sizeof(aeabi_float_t)); - return res.out; -} - -static inline float64_t f64(aeabi_double_t d) { - union { - aeabi_double_t in; - float64_t out; - } res = {.in = d}; - assert(sizeof(aeabi_double_t) == sizeof(float64_t)); - assert(sizeof(res) == sizeof(float64_t)); - return res.out; -} - - -static inline aeabi_double_t d(float64_t d) { - union { - float64_t in; - aeabi_double_t out; - } res = {.in = d}; - assert(sizeof(aeabi_double_t) == sizeof(float64_t)); - assert(sizeof(res) == sizeof(aeabi_double_t)); - return res.out; -} +#include "float.h" // Conversions diff --git a/liba/src/aeabi-rt/float.h b/liba/src/aeabi-rt/float.h new file mode 100644 index 000000000..f8ccd7428 --- /dev/null +++ b/liba/src/aeabi-rt/float.h @@ -0,0 +1,55 @@ +#ifndef LIBA_AEABI_FLOAT_H +#define LIBA_AEABI_FLOAT_H + +#include +#include "../external/softfloat/port/softfloat.h" + +/* To avoid any issue due to procedure call conventions, we convert softfloat + * double 'aeabi_double_t' (respectively 'aeabi_float_t') to float64_t (to + * respectively float32_t) before or/and after calling softfloat functions. */ + +typedef unsigned aeabi_float_t; +typedef unsigned long long aeabi_double_t; + +static inline float32_t f32(aeabi_float_t f) { + union { + aeabi_float_t in; + float32_t out; + } res = {.in = f}; + assert(sizeof(aeabi_float_t) == sizeof(float32_t)); + assert(sizeof(res) == sizeof(float32_t)); + return res.out; +} + +static inline aeabi_float_t f(float32_t f) { + union { + float32_t in; + aeabi_float_t out; + } res = {.in = f}; + assert(sizeof(aeabi_float_t) == sizeof(float32_t)); + assert(sizeof(res) == sizeof(aeabi_float_t)); + return res.out; +} + +static inline float64_t f64(aeabi_double_t d) { + union { + aeabi_double_t in; + float64_t out; + } res = {.in = d}; + assert(sizeof(aeabi_double_t) == sizeof(float64_t)); + assert(sizeof(res) == sizeof(float64_t)); + return res.out; +} + + +static inline aeabi_double_t d(float64_t d) { + union { + float64_t in; + aeabi_double_t out; + } res = {.in = d}; + assert(sizeof(aeabi_double_t) == sizeof(float64_t)); + assert(sizeof(res) == sizeof(aeabi_double_t)); + return res.out; +} + +#endif diff --git a/liba/src/aeabi-rt/long.c b/liba/src/aeabi-rt/long.c new file mode 100644 index 000000000..2441d8c3c --- /dev/null +++ b/liba/src/aeabi-rt/long.c @@ -0,0 +1,21 @@ +/* See the "Run-time ABI for the ARM Architecture", Section 4.1.2 */ + +#include "float.h" + +// Conversions + +aeabi_float_t __aeabi_l2f(int64_t i) { + return f(i64_to_f32(i)); +} + +aeabi_double_t __aeabi_l2d(int64_t i) { + return d(i64_to_f64(i)); +} + +int64_t __aeabi_f2lz(aeabi_float_t x) { + return f32_to_i64_r_minMag(f32(x), 0); +} + +int64_t __aeabi_d2lz(aeabi_double_t x) { + return f64_to_i64_r_minMag(f64(x), 0); +} diff --git a/liba/src/external/softfloat/port/softfloat.h b/liba/src/external/softfloat/port/softfloat.h index df2db16ce..87fdfbbd9 100644 --- a/liba/src/external/softfloat/port/softfloat.h +++ b/liba/src/external/softfloat/port/softfloat.h @@ -22,4 +22,10 @@ float64_t f64_sub(float64_t x, float64_t y); float64_t f64_mul(float64_t x, float64_t y); float64_t f64_div(float64_t x, float64_t y); +float32_t i64_to_f32(int64_t i); +float64_t i64_to_f64(int64_t i); +int_fast64_t f32_to_i64_r_minMag(float32_t x, bool exact); +int_fast64_t f64_to_i64_r_minMag(float64_t x, bool exact); + + #endif diff --git a/liba/src/external/softfloat/src/f32_to_i64_r_minMag.c b/liba/src/external/softfloat/src/f32_to_i64_r_minMag.c new file mode 100644 index 000000000..8fc67f305 --- /dev/null +++ b/liba/src/external/softfloat/src/f32_to_i64_r_minMag.c @@ -0,0 +1,94 @@ + +/*============================================================================ + +This C source file is part of the SoftFloat IEEE Floating-Point Arithmetic +Package, Release 3d, by John R. Hauser. + +Copyright 2011, 2012, 2013, 2014, 2015, 2016 The Regents of the University of +California. All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + + 1. Redistributions of source code must retain the above copyright notice, + this list of conditions, and the following disclaimer. + + 2. Redistributions in binary form must reproduce the above copyright notice, + this list of conditions, and the following disclaimer in the documentation + and/or other materials provided with the distribution. + + 3. Neither the name of the University nor the names of its contributors may + be used to endorse or promote products derived from this software without + specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS "AS IS", AND ANY +EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ARE +DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY +DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND +ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +=============================================================================*/ + +#include +#include +#include "platform.h" +#include "internals.h" +#include "specialize.h" +#include "softfloat.h" + +int_fast64_t f32_to_i64_r_minMag( float32_t a, bool exact ) +{ + union ui32_f32 uA; + uint_fast32_t uiA; + int_fast16_t exp; + uint_fast32_t sig; + int_fast16_t shiftDist; + bool sign; + uint_fast64_t sig64; + int_fast64_t absZ; + + /*------------------------------------------------------------------------ + *------------------------------------------------------------------------*/ + uA.f = a; + uiA = uA.ui; + exp = expF32UI( uiA ); + sig = fracF32UI( uiA ); + /*------------------------------------------------------------------------ + *------------------------------------------------------------------------*/ + shiftDist = 0xBE - exp; + if ( 64 <= shiftDist ) { + if ( exact && (exp | sig) ) { + softfloat_exceptionFlags |= softfloat_flag_inexact; + } + return 0; + } + /*------------------------------------------------------------------------ + *------------------------------------------------------------------------*/ + sign = signF32UI( uiA ); + if ( shiftDist <= 0 ) { + if ( uiA == packToF32UI( 1, 0xBE, 0 ) ) { + return -INT64_C( 0x7FFFFFFFFFFFFFFF ) - 1; + } + softfloat_raiseFlags( softfloat_flag_invalid ); + return + (exp == 0xFF) && sig ? i64_fromNaN + : sign ? i64_fromNegOverflow : i64_fromPosOverflow; + } + /*------------------------------------------------------------------------ + *------------------------------------------------------------------------*/ + sig |= 0x00800000; + sig64 = (uint_fast64_t) sig<<40; + absZ = sig64>>shiftDist; + shiftDist = 40 - shiftDist; + if ( exact && (shiftDist < 0) && (uint32_t) (sig<<(shiftDist & 31)) ) { + softfloat_exceptionFlags |= softfloat_flag_inexact; + } + return sign ? -absZ : absZ; + +} + diff --git a/liba/src/external/softfloat/src/f64_to_i64_r_minMag.c b/liba/src/external/softfloat/src/f64_to_i64_r_minMag.c new file mode 100644 index 000000000..b8de0b504 --- /dev/null +++ b/liba/src/external/softfloat/src/f64_to_i64_r_minMag.c @@ -0,0 +1,100 @@ + +/*============================================================================ + +This C source file is part of the SoftFloat IEEE Floating-Point Arithmetic +Package, Release 3d, by John R. Hauser. + +Copyright 2011, 2012, 2013, 2014, 2015, 2016 The Regents of the University of +California. All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + + 1. Redistributions of source code must retain the above copyright notice, + this list of conditions, and the following disclaimer. + + 2. Redistributions in binary form must reproduce the above copyright notice, + this list of conditions, and the following disclaimer in the documentation + and/or other materials provided with the distribution. + + 3. Neither the name of the University nor the names of its contributors may + be used to endorse or promote products derived from this software without + specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS "AS IS", AND ANY +EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ARE +DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY +DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND +ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +=============================================================================*/ + +#include +#include +#include "platform.h" +#include "internals.h" +#include "specialize.h" +#include "softfloat.h" + +int_fast64_t f64_to_i64_r_minMag( float64_t a, bool exact ) +{ + union ui64_f64 uA; + uint_fast64_t uiA; + bool sign; + int_fast16_t exp; + uint_fast64_t sig; + int_fast16_t shiftDist; + int_fast64_t absZ; + + /*------------------------------------------------------------------------ + *------------------------------------------------------------------------*/ + uA.f = a; + uiA = uA.ui; + sign = signF64UI( uiA ); + exp = expF64UI( uiA ); + sig = fracF64UI( uiA ); + /*------------------------------------------------------------------------ + *------------------------------------------------------------------------*/ + shiftDist = 0x433 - exp; + if ( shiftDist <= 0 ) { + /*-------------------------------------------------------------------- + *--------------------------------------------------------------------*/ + if ( shiftDist < -10 ) { + if ( uiA == packToF64UI( 1, 0x43E, 0 ) ) { + return -INT64_C( 0x7FFFFFFFFFFFFFFF ) - 1; + } + softfloat_raiseFlags( softfloat_flag_invalid ); + return + (exp == 0x7FF) && sig ? i64_fromNaN + : sign ? i64_fromNegOverflow : i64_fromPosOverflow; + } + /*-------------------------------------------------------------------- + *--------------------------------------------------------------------*/ + sig |= UINT64_C( 0x0010000000000000 ); + absZ = sig<<-shiftDist; + } else { + /*-------------------------------------------------------------------- + *--------------------------------------------------------------------*/ + if ( 53 <= shiftDist ) { + if ( exact && (exp | sig) ) { + softfloat_exceptionFlags |= softfloat_flag_inexact; + } + return 0; + } + /*-------------------------------------------------------------------- + *--------------------------------------------------------------------*/ + sig |= UINT64_C( 0x0010000000000000 ); + absZ = sig>>shiftDist; + if ( exact && (absZ< +#include +#include "platform.h" +#include "internals.h" +#include "softfloat.h" + +float32_t i64_to_f32( int64_t a ) +{ + bool sign; + uint_fast64_t absA; + int_fast8_t shiftDist; + union ui32_f32 u; + uint_fast32_t sig; + + sign = (a < 0); + absA = sign ? -(uint_fast64_t) a : (uint_fast64_t) a; + shiftDist = softfloat_countLeadingZeros64( absA ) - 40; + if ( 0 <= shiftDist ) { + u.ui = + a ? packToF32UI( + sign, 0x95 - shiftDist, (uint_fast32_t) absA< +#include +#include "platform.h" +#include "internals.h" +#include "softfloat.h" + +float64_t i64_to_f64( int64_t a ) +{ + bool sign; + union ui64_f64 uZ; + uint_fast64_t absA; + + sign = (a < 0); + if ( ! (a & UINT64_C( 0x7FFFFFFFFFFFFFFF )) ) { + uZ.ui = sign ? packToF64UI( 1, 0x43E, 0 ) : 0; + return uZ.f; + } + absA = sign ? -(uint_fast64_t) a : (uint_fast64_t) a; + return softfloat_normRoundPackToF64( sign, 0x43C, absA ); + +} + diff --git a/liba/test/long.c b/liba/test/long.c new file mode 100644 index 000000000..fae92e421 --- /dev/null +++ b/liba/test/long.c @@ -0,0 +1,18 @@ +#include +#include +#include + +void assert_int64t_approximatively_equals_int64t(int64_t i, int64_t j) { + assert(i-j < 1000000); + assert(j-i < 1000000); +} + +QUIZ_CASE(long_arithmetic) { + int64_t i = 123456789101112; + assert((float)i == 1.23456789101112e14f); + assert((double)i == 1.23456789101112e14); + float f = 123456789101112.12345f; + assert_int64t_approximatively_equals_int64t((int64_t)f, 123456789101112); + double d = 123456789101112.12345f; + assert_int64t_approximatively_equals_int64t((int64_t)d, 123456789101112); +}