From f2dbcf7594887ddfdec646ab2a85f4e2358ec209 Mon Sep 17 00:00:00 2001 From: Thomas Preud'homme Date: Sun, 7 Apr 2013 17:02:57 +0200 Subject: Add ARM aeabi functions needed to run tcctest Add implementation for float / integer conversion functions: __aeabi_d2lz, __aeabi_d2ulz, __aeabi_f2lz, __aeabi_f2ulz, __aeabi_l2d, __aeabi_l2f, __aeabi_ul2d, __aeabi_ul2f Add implementation for long long helper functions: __aeabi_ldivmod, __aeabi_uldivmod, __aeabi_llsl, __aeabi_llsr, __aeabi_lasr Add implementation for integer division functions: __aeabi_uidiv, __aeabi_uidivmod, __aeabi_idiv, __aeabi_idivmod, --- lib/armeabi.c | 441 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 441 insertions(+) create mode 100644 lib/armeabi.c (limited to 'lib/armeabi.c') diff --git a/lib/armeabi.c b/lib/armeabi.c new file mode 100644 index 0000000..c00ace6 --- /dev/null +++ b/lib/armeabi.c @@ -0,0 +1,441 @@ +#include + +/* We rely on the little endianness and EABI calling convention for this to + work */ + +typedef struct double_unsigned_struct { + unsigned low; + unsigned high; +} double_unsigned_struct; + +typedef struct unsigned_int_struct { + unsigned low; + int high; +} unsigned_int_struct; + +#define REGS_RETURN(name, type) \ + void name ## _return(type ret) {} + + +/* Float helper functions */ + +#define FLOAT_EXP_BITS 8 +#define FLOAT_FRAC_BITS 23 + +#define DOUBLE_EXP_BITS 11 +#define DOUBLE_FRAC_BITS 52 + +#define ONE_EXP(type) ((1 << (type ## _EXP_BITS - 1)) - 1) + +REGS_RETURN(unsigned_int_struct, unsigned_int_struct) +REGS_RETURN(double_unsigned_struct, double_unsigned_struct) + +/* float -> integer: (sign) 1.fraction x 2^(exponent - exp_for_one) */ + + +/* float to [unsigned] long long conversion */ +#define DEFINE__AEABIT_F2XLZ(name, with_sign) \ +void __aeabi_ ## name(unsigned val) \ +{ \ + int exp, high_shift, sign; \ + double_unsigned_struct ret; \ + \ + /* compute sign */ \ + sign = val >> 31; \ + \ + /* compute real exponent */ \ + exp = val >> FLOAT_FRAC_BITS; \ + exp &= (1 << FLOAT_EXP_BITS) - 1; \ + exp -= ONE_EXP(FLOAT); \ + \ + /* undefined behavior if truncated value cannot be represented */ \ + if (with_sign) { \ + if (exp > 62) /* |val| too big, double cannot represent LLONG_MAX */ \ + return; \ + } else { \ + if ((sign && exp >= 0) || exp > 63) /* if val < 0 || val too big */ \ + return; \ + } \ + \ + val &= (1 << FLOAT_FRAC_BITS) - 1; \ + if (exp >= 32) { \ + ret.high = 1 << (exp - 32); \ + if (exp - 32 >= FLOAT_FRAC_BITS) { \ + ret.high |= val << (exp - 32 - FLOAT_FRAC_BITS); \ + ret.low = 0; \ + } else { \ + high_shift = FLOAT_FRAC_BITS - (exp - 32); \ + ret.high |= val >> high_shift; \ + ret.low = val << (32 - high_shift); \ + } \ + } else { \ + ret.high = 0; \ + ret.low = 1 << exp; \ + if (exp > FLOAT_FRAC_BITS) \ + ret.low |= val << (exp - FLOAT_FRAC_BITS); \ + else \ + ret.low = val >> (FLOAT_FRAC_BITS - exp); \ + } \ + \ + /* encode negative integer using 2's complement */ \ + if (with_sign && sign) { \ + ret.low = ~ret.low; \ + ret.high = ~ret.high; \ + if (ret.low == UINT_MAX) { \ + ret.low = 0; \ + ret.high++; \ + } else \ + ret.low++; \ + } \ + \ + double_unsigned_struct_return(ret); \ +} + +/* float to unsigned long long conversion */ +DEFINE__AEABIT_F2XLZ(f2ulz, 0) + +/* float to long long conversion */ +DEFINE__AEABIT_F2XLZ(f2lz, 1) + +/* double to [unsigned] long long conversion */ +#define DEFINE__AEABIT_D2XLZ(name, with_sign) \ +void __aeabi_ ## name(double_unsigned_struct val) \ +{ \ + int exp, high_shift, sign; \ + double_unsigned_struct ret; \ + \ + /* compute sign */ \ + sign = val.high >> 31; \ + \ + /* compute real exponent */ \ + exp = (val.high >> (DOUBLE_FRAC_BITS - 32)); \ + exp &= (1 << DOUBLE_EXP_BITS) - 1; \ + exp -= ONE_EXP(DOUBLE); \ + \ + /* undefined behavior if truncated value cannot be represented */ \ + if (with_sign) { \ + if (exp > 62) /* |val| too big, double cannot represent LLONG_MAX */ \ + return; \ + } else { \ + if ((sign && exp >= 0) || exp > 63) /* if val < 0 || val too big */ \ + return; \ + } \ + \ + val.high &= (1 << (DOUBLE_FRAC_BITS - 32)) - 1; \ + if (exp >= 32) { \ + ret.high = 1 << (exp - 32); \ + if (exp >= DOUBLE_FRAC_BITS) { \ + high_shift = exp - DOUBLE_FRAC_BITS; \ + ret.high |= val.high << high_shift; \ + ret.high |= val.low >> (32 - high_shift); \ + ret.low = val.low << high_shift; \ + } else { \ + high_shift = DOUBLE_FRAC_BITS - exp; \ + ret.high |= val.high >> high_shift; \ + ret.low = val.high << (32 - high_shift); \ + ret.low |= val.low >> high_shift; \ + } \ + } else { \ + ret.high = 0; \ + ret.low = 1 << exp; \ + if (exp > DOUBLE_FRAC_BITS - 32) { \ + high_shift = exp - DOUBLE_FRAC_BITS - 32; \ + ret.low |= val.high << high_shift; \ + ret.low |= val.low >> (32 - high_shift); \ + } else \ + ret.low = val.high >> (DOUBLE_FRAC_BITS - 32 - exp); \ + } \ + \ + /* encode negative integer using 2's complement */ \ + if (with_sign && sign) { \ + ret.low = ~ret.low; \ + ret.high = ~ret.high; \ + if (ret.low == UINT_MAX) { \ + ret.low = 0; \ + ret.high++; \ + } else \ + ret.low++; \ + } \ + \ + double_unsigned_struct_return(ret); \ +} + +/* double to unsigned long long conversion */ +DEFINE__AEABIT_D2XLZ(d2ulz, 0) + +/* double to long long conversion */ +DEFINE__AEABIT_D2XLZ(d2lz, 1) + +/* long long to float conversion */ +#define DEFINE__AEABI_XL2F(name, with_sign) \ +unsigned __aeabi_ ## name(unsigned long long v) \ +{ \ + int s /* shift */, sign = 0; \ + unsigned p = 0 /* power */, ret; \ + double_unsigned_struct val; \ + \ + /* fraction in negative float is encoded in 1's complement */ \ + if (with_sign && (v & (1 << 63))) { \ + sign = 1; \ + v = ~v + 1; \ + } \ + val.low = v; \ + val.high = v >> 32; \ + /* fill fraction bits */ \ + for (s = 31, p = 1 << 31; p && !(val.high & p); s--, p >>= 1); \ + if (p) { \ + ret = val.high & (p - 1); \ + if (s < FLOAT_FRAC_BITS) { \ + ret <<= FLOAT_FRAC_BITS - s; \ + ret |= val.low >> (32 - (FLOAT_FRAC_BITS - s)); \ + } else \ + ret >>= s - FLOAT_FRAC_BITS; \ + s += 32; \ + } else { \ + for (s = 31, p = 1 << 31; p && !(val.low & p); s--, p >>= 1); \ + if (p) { \ + ret = val.low & (p - 1); \ + if (s <= FLOAT_FRAC_BITS) \ + ret <<= FLOAT_FRAC_BITS - s; \ + else \ + ret >>= s - FLOAT_FRAC_BITS; \ + } else \ + return 0; \ + } \ + \ + /* fill exponent bits */ \ + ret |= (s + ONE_EXP(FLOAT)) << FLOAT_FRAC_BITS; \ + \ + /* fill sign bit */ \ + ret |= sign << 31; \ + \ + return ret; \ +} + +/* unsigned long long to float conversion */ +DEFINE__AEABI_XL2F(ul2f, 0) + +/* long long to float conversion */ +DEFINE__AEABI_XL2F(l2f, 0) + +/* long long to double conversion */ +#define __AEABI_XL2D(name, with_sign) \ +void __aeabi_ ## name(unsigned long long v) \ +{ \ + int s, high_shift, sign = 0; \ + unsigned tmp, p = 0; \ + double_unsigned_struct val, ret; \ + \ + /* fraction in negative float is encoded in 1's complement */ \ + if (with_sign && (v & (1ULL << 63))) { \ + sign = 1; \ + v = ~v + 1; \ + } \ + val.low = v; \ + val.high = v >> 32; \ + \ + /* fill fraction bits */ \ + for (s = 31, p = 1 << 31; p && !(val.high & p); s--, p >>= 1); \ + if (p) { \ + tmp = val.high & (p - 1); \ + if (s < DOUBLE_FRAC_BITS - 32) { \ + high_shift = DOUBLE_FRAC_BITS - 32 - s; \ + ret.high = tmp << high_shift; \ + ret.high |= val.low >> (32 - high_shift); \ + ret.low = val.low << high_shift; \ + } else { \ + high_shift = s - (DOUBLE_FRAC_BITS - 32); \ + ret.high = tmp >> high_shift; \ + ret.low = tmp << (32 - high_shift); \ + ret.low |= val.low >> high_shift; \ + } \ + s += 32; \ + } else { \ + for (s = 31, p = 1 << 31; p && !(val.low & p); s--, p >>= 1); \ + if (p) { \ + tmp = val.low & (p - 1); \ + if (s <= DOUBLE_FRAC_BITS - 32) { \ + high_shift = DOUBLE_FRAC_BITS - 32 - s; \ + ret.high = tmp << high_shift; \ + ret.low = 0; \ + } else { \ + high_shift = s - (DOUBLE_FRAC_BITS - 32); \ + ret.high = tmp >> high_shift; \ + ret.low = tmp << (32 - high_shift); \ + } \ + } else { \ + ret.high = ret.low = 0; \ + double_unsigned_struct_return(ret); \ + } \ + } \ + \ + /* fill exponent bits */ \ + ret.high |= (s + ONE_EXP(DOUBLE)) << (DOUBLE_FRAC_BITS - 32); \ + \ + /* fill sign bit */ \ + ret.high |= sign << 31; \ + \ + double_unsigned_struct_return(ret); \ +} + +/* unsigned long long to double conversion */ +__AEABI_XL2D(ul2d, 0) + +/* long long to double conversion */ +__AEABI_XL2D(l2d, 1) + + +/* Long long helper functions */ + +/* TODO: add error in case of den == 0 (see §4.3.1 and §4.3.2) */ + +#define define_aeabi_xdivmod_signed_type(basetype, type) \ +typedef struct type { \ + basetype quot; \ + unsigned basetype rem; \ +} type + +#define define_aeabi_xdivmod_unsigned_type(basetype, type) \ +typedef struct type { \ + basetype quot; \ + basetype rem; \ +} type + +#define AEABI_UXDIVMOD(name,type, rettype, typemacro) \ +static inline rettype aeabi_ ## name (type num, type den) \ +{ \ + rettype ret; \ + type quot = 0; \ + \ + /* Increase quotient while it is less than numerator */ \ + while (num >= den) { \ + type q = 1; \ + \ + /* Find closest power of two */ \ + while ((q << 1) * den <= num && q * den <= typemacro ## _MAX / 2) \ + q <<= 1; \ + \ + /* Compute difference between current quotient and numerator */ \ + num -= q * den; \ + quot += q; \ + } \ + ret.quot = quot; \ + ret.rem = num; \ + return ret; \ +} + +#define __AEABI_XDIVMOD(name, type, uiname, rettype, urettype, typemacro) \ +void __aeabi_ ## name(type numerator, type denominator) \ +{ \ + unsigned type num, den; \ + urettype uxdiv_ret; \ + rettype ret; \ + \ + num = numerator & typemacro ## _MAX; \ + den = denominator & typemacro ## _MAX; \ + uxdiv_ret = aeabi_ ## uiname(num, den); \ + /* signs differ */ \ + if ((numerator & typemacro ## _MIN) != (denominator & typemacro ## _MIN)) \ + ret.quot = uxdiv_ret.quot * -1; \ + else \ + ret.quot = uxdiv_ret.quot; \ + if (numerator & typemacro ## _MIN) \ + ret.rem = uxdiv_ret.rem * -1; \ + else \ + ret.rem = uxdiv_ret.rem; \ + \ + rettype ## _return(ret); \ +} + +define_aeabi_xdivmod_signed_type(long long, lldiv_t); +define_aeabi_xdivmod_unsigned_type(unsigned long long, ulldiv_t); +define_aeabi_xdivmod_signed_type(int, idiv_t); +define_aeabi_xdivmod_unsigned_type(unsigned, uidiv_t); + +REGS_RETURN(lldiv_t, lldiv_t) +REGS_RETURN(ulldiv_t, ulldiv_t) +REGS_RETURN(idiv_t, idiv_t) +REGS_RETURN(uidiv_t, uidiv_t) + +AEABI_UXDIVMOD(uldivmod, unsigned long long, ulldiv_t, ULONG) + +__AEABI_XDIVMOD(ldivmod, long long, uldivmod, lldiv_t, ulldiv_t, LLONG) + +void __aeabi_uldivmod(unsigned long long num, unsigned long long den) +{ + ulldiv_t_return(aeabi_uldivmod(num, den)); +} + +void __aeabi_llsl(double_unsigned_struct val, int shift) +{ + double_unsigned_struct ret; + + if (shift >= 32) { + val.high = val.low; + val.low = 0; + shift -= 32; + } + if (shift > 0) { + ret.low = val.low << shift; + ret.high = (val.high << shift) | (val.low >> (32 - shift)); + double_unsigned_struct_return(ret); + return; + } + double_unsigned_struct_return(val); +} + +#define aeabi_lsr(val, shift, fill, type) \ + type ## _struct ret; \ + \ + if (shift >= 32) { \ + val.low = val.high; \ + val.high = fill; \ + shift -= 32; \ + } \ + if (shift > 0) { \ + ret.high = val.high >> shift; \ + ret.low = (val.high << (32 - shift)) | (val.low >> shift); \ + type ## _struct_return(ret); \ + return; \ + } \ + type ## _struct_return(val); + +void __aeabi_llsr(double_unsigned_struct val, int shift) +{ + aeabi_lsr(val, shift, 0, double_unsigned); +} + +void __aeabi_lasr(unsigned_int_struct val, int shift) +{ + aeabi_lsr(val, shift, val.high >> 31, unsigned_int); +} + + +/* Integer division functions */ + +AEABI_UXDIVMOD(uidivmod, unsigned, uidiv_t, UINT) + +int __aeabi_idiv(int numerator, int denominator) +{ + unsigned num, den; + uidiv_t ret; + + num = numerator & INT_MAX; + den = denominator & INT_MAX; + ret = aeabi_uidivmod(num, den); + if ((numerator & INT_MIN) != (denominator & INT_MIN)) /* signs differ */ + ret.quot *= -1; + return ret.quot; +} + +unsigned __aeabi_uidiv(unsigned num, unsigned den) +{ + return aeabi_uidivmod(num, den).quot; +} + +__AEABI_XDIVMOD(idivmod, int, uidivmod, idiv_t, uidiv_t, INT) + +void __aeabi_uidivmod(unsigned num, unsigned den) +{ + uidiv_t_return(aeabi_uidivmod(num, den)); +} -- cgit v1.3.1 From a24e31e85d2980bf4863ad3dd371c6501810ae97 Mon Sep 17 00:00:00 2001 From: Thomas Preud'homme Date: Sun, 15 Dec 2013 09:44:20 +0800 Subject: Fix signed integer division in ARM runtime ABI - fix computation of absolute value (clearing the sign bit does not since integers are encoded in 2's complement) - test sign of integer in a more conventional way (binary and with the high bit does not work for long long due to a bug in gtst) - spacing in include --- lib/armeabi.c | 30 +++++++++++++++++++++--------- 1 file changed, 21 insertions(+), 9 deletions(-) (limited to 'lib/armeabi.c') diff --git a/lib/armeabi.c b/lib/armeabi.c index c00ace6..e787ec1 100644 --- a/lib/armeabi.c +++ b/lib/armeabi.c @@ -1,4 +1,4 @@ -#include +#include /* We rely on the little endianness and EABI calling convention for this to work */ @@ -325,22 +325,28 @@ static inline rettype aeabi_ ## name (type num, type den) \ } #define __AEABI_XDIVMOD(name, type, uiname, rettype, urettype, typemacro) \ -void __aeabi_ ## name(type numerator, type denominator) \ +void __aeabi_ ## name(type numerator, type denominator) \ { \ unsigned type num, den; \ urettype uxdiv_ret; \ rettype ret; \ \ - num = numerator & typemacro ## _MAX; \ - den = denominator & typemacro ## _MAX; \ + if (numerator >= 0) \ + num = numerator; \ + else \ + num = 0 - numerator; \ + if (denominator >= 0) \ + den = denominator; \ + else \ + den = 0 - denominator; \ uxdiv_ret = aeabi_ ## uiname(num, den); \ /* signs differ */ \ if ((numerator & typemacro ## _MIN) != (denominator & typemacro ## _MIN)) \ - ret.quot = uxdiv_ret.quot * -1; \ + ret.quot = 0 - uxdiv_ret.quot; \ else \ ret.quot = uxdiv_ret.quot; \ - if (numerator & typemacro ## _MIN) \ - ret.rem = uxdiv_ret.rem * -1; \ + if (numerator < 0) \ + ret.rem = 0 - uxdiv_ret.rem; \ else \ ret.rem = uxdiv_ret.rem; \ \ @@ -420,8 +426,14 @@ int __aeabi_idiv(int numerator, int denominator) unsigned num, den; uidiv_t ret; - num = numerator & INT_MAX; - den = denominator & INT_MAX; + if (numerator >= 0) + num = numerator; + else + num = 0 - numerator; + if (denominator >= 0) + den = denominator; + else + den = 0 - denominator; ret = aeabi_uidivmod(num, den); if ((numerator & INT_MIN) != (denominator & INT_MIN)) /* signs differ */ ret.quot *= -1; -- cgit v1.3.1 From 0ab07f39a63e1c183126a6b79db96819907e26dd Mon Sep 17 00:00:00 2001 From: Thomas Preud'homme Date: Wed, 5 Feb 2014 16:09:54 +0800 Subject: Fix float to long long conversion on ARM Fix float to long long conversion on ARM when the result would fit in an int. --- lib/armeabi.c | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) (limited to 'lib/armeabi.c') diff --git a/lib/armeabi.c b/lib/armeabi.c index e787ec1..616b9b5 100644 --- a/lib/armeabi.c +++ b/lib/armeabi.c @@ -34,7 +34,7 @@ REGS_RETURN(double_unsigned_struct, double_unsigned_struct) /* float to [unsigned] long long conversion */ -#define DEFINE__AEABIT_F2XLZ(name, with_sign) \ +#define DEFINE__AEABI_F2XLZ(name, with_sign) \ void __aeabi_ ## name(unsigned val) \ { \ int exp, high_shift, sign; \ @@ -74,7 +74,7 @@ void __aeabi_ ## name(unsigned val) \ if (exp > FLOAT_FRAC_BITS) \ ret.low |= val << (exp - FLOAT_FRAC_BITS); \ else \ - ret.low = val >> (FLOAT_FRAC_BITS - exp); \ + ret.low |= val >> (FLOAT_FRAC_BITS - exp); \ } \ \ /* encode negative integer using 2's complement */ \ @@ -92,13 +92,13 @@ void __aeabi_ ## name(unsigned val) \ } /* float to unsigned long long conversion */ -DEFINE__AEABIT_F2XLZ(f2ulz, 0) +DEFINE__AEABI_F2XLZ(f2ulz, 0) /* float to long long conversion */ -DEFINE__AEABIT_F2XLZ(f2lz, 1) +DEFINE__AEABI_F2XLZ(f2lz, 1) /* double to [unsigned] long long conversion */ -#define DEFINE__AEABIT_D2XLZ(name, with_sign) \ +#define DEFINE__AEABI_D2XLZ(name, with_sign) \ void __aeabi_ ## name(double_unsigned_struct val) \ { \ int exp, high_shift, sign; \ @@ -143,7 +143,7 @@ void __aeabi_ ## name(double_unsigned_struct val) \ ret.low |= val.high << high_shift; \ ret.low |= val.low >> (32 - high_shift); \ } else \ - ret.low = val.high >> (DOUBLE_FRAC_BITS - 32 - exp); \ + ret.low |= val.high >> (DOUBLE_FRAC_BITS - 32 - exp); \ } \ \ /* encode negative integer using 2's complement */ \ @@ -161,10 +161,10 @@ void __aeabi_ ## name(double_unsigned_struct val) \ } /* double to unsigned long long conversion */ -DEFINE__AEABIT_D2XLZ(d2ulz, 0) +DEFINE__AEABI_D2XLZ(d2ulz, 0) /* double to long long conversion */ -DEFINE__AEABIT_D2XLZ(d2lz, 1) +DEFINE__AEABI_D2XLZ(d2lz, 1) /* long long to float conversion */ #define DEFINE__AEABI_XL2F(name, with_sign) \ -- cgit v1.3.1 From d0295074941816351c15fe3d4326b5e98364ff9c Mon Sep 17 00:00:00 2001 From: Thomas Preud'homme Date: Wed, 5 Feb 2014 16:56:27 +0800 Subject: Fix negative long long to float conversion on ARM --- lib/armeabi.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'lib/armeabi.c') diff --git a/lib/armeabi.c b/lib/armeabi.c index 616b9b5..bf5e07a 100644 --- a/lib/armeabi.c +++ b/lib/armeabi.c @@ -175,7 +175,7 @@ unsigned __aeabi_ ## name(unsigned long long v) \ double_unsigned_struct val; \ \ /* fraction in negative float is encoded in 1's complement */ \ - if (with_sign && (v & (1 << 63))) { \ + if (with_sign && (v & (1ULL << 63))) { \ sign = 1; \ v = ~v + 1; \ } \ @@ -216,7 +216,7 @@ unsigned __aeabi_ ## name(unsigned long long v) \ DEFINE__AEABI_XL2F(ul2f, 0) /* long long to float conversion */ -DEFINE__AEABI_XL2F(l2f, 0) +DEFINE__AEABI_XL2F(l2f, 1) /* long long to double conversion */ #define __AEABI_XL2D(name, with_sign) \ -- cgit v1.3.1 From 88c9f1bb4e64d9dab658061b058b8bedc2c66ac5 Mon Sep 17 00:00:00 2001 From: Thomas Preud'homme Date: Wed, 5 Feb 2014 19:47:15 +0800 Subject: Round mode of ll -> float conversion to nearest Change rounding mode of long long to float conversion to nearest in libtcc1. --- lib/armeabi.c | 25 ++++++++++++++++++++----- 1 file changed, 20 insertions(+), 5 deletions(-) (limited to 'lib/armeabi.c') diff --git a/lib/armeabi.c b/lib/armeabi.c index bf5e07a..ce5e232 100644 --- a/lib/armeabi.c +++ b/lib/armeabi.c @@ -170,7 +170,7 @@ DEFINE__AEABI_D2XLZ(d2lz, 1) #define DEFINE__AEABI_XL2F(name, with_sign) \ unsigned __aeabi_ ## name(unsigned long long v) \ { \ - int s /* shift */, sign = 0; \ + int s /* shift */, flb /* first lost bit */, sign = 0; \ unsigned p = 0 /* power */, ret; \ double_unsigned_struct val; \ \ @@ -188,20 +188,28 @@ unsigned __aeabi_ ## name(unsigned long long v) \ if (s < FLOAT_FRAC_BITS) { \ ret <<= FLOAT_FRAC_BITS - s; \ ret |= val.low >> (32 - (FLOAT_FRAC_BITS - s)); \ - } else \ + flb = (val.low >> (32 - (FLOAT_FRAC_BITS - s - 1))) & 1; \ + } else { \ + flb = (ret >> (s - FLOAT_FRAC_BITS - 1)) & 1; \ ret >>= s - FLOAT_FRAC_BITS; \ + } \ s += 32; \ } else { \ for (s = 31, p = 1 << 31; p && !(val.low & p); s--, p >>= 1); \ if (p) { \ ret = val.low & (p - 1); \ - if (s <= FLOAT_FRAC_BITS) \ + if (s <= FLOAT_FRAC_BITS) { \ ret <<= FLOAT_FRAC_BITS - s; \ - else \ + flb = 0; \ + } else { \ + flb = (ret >> (s - FLOAT_FRAC_BITS - 1)) & 1; \ ret >>= s - FLOAT_FRAC_BITS; \ + } \ } else \ return 0; \ } \ + if (flb) \ + ret++; \ \ /* fill exponent bits */ \ ret |= (s + ONE_EXP(FLOAT)) << FLOAT_FRAC_BITS; \ @@ -222,7 +230,7 @@ DEFINE__AEABI_XL2F(l2f, 1) #define __AEABI_XL2D(name, with_sign) \ void __aeabi_ ## name(unsigned long long v) \ { \ - int s, high_shift, sign = 0; \ + int s /* shift */, high_shift, sign = 0; \ unsigned tmp, p = 0; \ double_unsigned_struct val, ret; \ \ @@ -248,6 +256,13 @@ void __aeabi_ ## name(unsigned long long v) \ ret.high = tmp >> high_shift; \ ret.low = tmp << (32 - high_shift); \ ret.low |= val.low >> high_shift; \ + if ((val.low >> (high_shift - 1)) & 1) { \ + if (ret.low == UINT_MAX) { \ + ret.high++; \ + ret.low = 0; \ + } else \ + ret.low++; \ + } \ } \ s += 32; \ } else { \ -- cgit v1.3.1