all: Fix implicit floating point promotion.

Initially some of these were found building the unix coverage variant on
MacOS because that build uses clang and has -Wdouble-promotion enabled, and
clang performs more vigorous promotion checks than gcc.  Additionally the
codebase has been compiled with clang and msvc (the latter with warning
level 3), and with MICROPY_FLOAT_IMPL_FLOAT to find the rest of the
conversions.

Fixes are implemented either as explicit casts, or by using the correct
type, or by using one of the utility functions to handle floating point
casting; these have been moved from nativeglue.c to the public API.
This commit is contained in:
stijn 2020-04-09 09:05:48 +02:00 committed by Damien George
parent b909e8b2dd
commit 0ba68f8a1d
11 changed files with 70 additions and 54 deletions

View File

@ -360,7 +360,7 @@ STATIC mp_obj_t get_aligned(uint val_type, void *p, mp_int_t index) {
return mp_obj_new_int_from_ll(((int64_t *)p)[index]); return mp_obj_new_int_from_ll(((int64_t *)p)[index]);
#if MICROPY_PY_BUILTINS_FLOAT #if MICROPY_PY_BUILTINS_FLOAT
case FLOAT32: case FLOAT32:
return mp_obj_new_float(((float *)p)[index]); return mp_obj_new_float_from_f(((float *)p)[index]);
case FLOAT64: case FLOAT64:
return mp_obj_new_float(((double *)p)[index]); return mp_obj_new_float(((double *)p)[index]);
#endif #endif
@ -373,11 +373,10 @@ STATIC mp_obj_t get_aligned(uint val_type, void *p, mp_int_t index) {
STATIC void set_aligned(uint val_type, void *p, mp_int_t index, mp_obj_t val) { STATIC void set_aligned(uint val_type, void *p, mp_int_t index, mp_obj_t val) {
#if MICROPY_PY_BUILTINS_FLOAT #if MICROPY_PY_BUILTINS_FLOAT
if (val_type == FLOAT32 || val_type == FLOAT64) { if (val_type == FLOAT32 || val_type == FLOAT64) {
mp_float_t v = mp_obj_get_float(val);
if (val_type == FLOAT32) { if (val_type == FLOAT32) {
((float *)p)[index] = v; ((float *)p)[index] = mp_obj_get_float_to_f(val);
} else { } else {
((double *)p)[index] = v; ((double *)p)[index] = mp_obj_get_float_to_d(val);
} }
return; return;
} }

View File

@ -125,7 +125,7 @@ STATIC mp_obj_t select_select(size_t n_args, const mp_obj_t *args) {
if (n_args == 4) { if (n_args == 4) {
if (args[3] != mp_const_none) { if (args[3] != mp_const_none) {
#if MICROPY_PY_BUILTINS_FLOAT #if MICROPY_PY_BUILTINS_FLOAT
float timeout_f = mp_obj_get_float(args[3]); float timeout_f = mp_obj_get_float_to_f(args[3]);
if (timeout_f >= 0) { if (timeout_f >= 0) {
timeout = (mp_uint_t)(timeout_f * 1000); timeout = (mp_uint_t)(timeout_f * 1000);
} }

View File

@ -167,7 +167,7 @@ STATIC mp_obj_t return_ffi_value(ffi_arg val, char type) {
union { ffi_arg ffi; union { ffi_arg ffi;
float flt; float flt;
} val_union = { .ffi = val }; } val_union = { .ffi = val };
return mp_obj_new_float(val_union.flt); return mp_obj_new_float_from_f(val_union.flt);
} }
case 'd': { case 'd': {
double *p = (double *)&val; double *p = (double *)&val;
@ -381,7 +381,7 @@ STATIC mp_obj_t ffifunc_call(mp_obj_t self_in, size_t n_args, size_t n_kw, const
*p = mp_obj_get_float(a); *p = mp_obj_get_float(a);
} else if (*argtype == 'd') { } else if (*argtype == 'd') {
double *p = (double *)&values[i]; double *p = (double *)&values[i];
*p = mp_obj_get_float(a); *p = mp_obj_get_float_to_d(a);
#endif #endif
} else if (a == mp_const_none) { } else if (a == mp_const_none) {
values[i] = 0; values[i] = 0;

View File

@ -61,7 +61,7 @@ static inline int msec_sleep_tv(struct timeval *tv) {
#endif #endif
#if defined(MP_CLOCKS_PER_SEC) #if defined(MP_CLOCKS_PER_SEC)
#define CLOCK_DIV (MP_CLOCKS_PER_SEC / 1000.0F) #define CLOCK_DIV (MP_CLOCKS_PER_SEC / MICROPY_FLOAT_CONST(1000.0))
#else #else
#error Unsupported clock() implementation #error Unsupported clock() implementation
#endif #endif
@ -84,7 +84,7 @@ STATIC mp_obj_t mod_time_clock(void) {
// float cannot represent full range of int32 precisely, so we pre-divide // float cannot represent full range of int32 precisely, so we pre-divide
// int to reduce resolution, and then actually do float division hoping // int to reduce resolution, and then actually do float division hoping
// to preserve integer part resolution. // to preserve integer part resolution.
return mp_obj_new_float((float)(clock() / 1000) / CLOCK_DIV); return mp_obj_new_float((clock() / 1000) / CLOCK_DIV);
#else #else
return mp_obj_new_int((mp_int_t)clock()); return mp_obj_new_int((mp_int_t)clock());
#endif #endif
@ -95,8 +95,8 @@ STATIC mp_obj_t mod_time_sleep(mp_obj_t arg) {
#if MICROPY_PY_BUILTINS_FLOAT #if MICROPY_PY_BUILTINS_FLOAT
struct timeval tv; struct timeval tv;
mp_float_t val = mp_obj_get_float(arg); mp_float_t val = mp_obj_get_float(arg);
double ipart; mp_float_t ipart;
tv.tv_usec = round(modf(val, &ipart) * 1000000); tv.tv_usec = MICROPY_FLOAT_C_FUN(round)(MICROPY_FLOAT_C_FUN(modf)(val, &ipart) * MICROPY_FLOAT_CONST(1000000.));
tv.tv_sec = ipart; tv.tv_sec = ipart;
int res; int res;
while (1) { while (1) {

View File

@ -378,8 +378,8 @@ STATIC mp_obj_t socket_settimeout(mp_obj_t self_in, mp_obj_t timeout_in) {
if (timeout_in != mp_const_none) { if (timeout_in != mp_const_none) {
#if MICROPY_PY_BUILTINS_FLOAT #if MICROPY_PY_BUILTINS_FLOAT
mp_float_t val = mp_obj_get_float(timeout_in); mp_float_t val = mp_obj_get_float(timeout_in);
double ipart; mp_float_t ipart;
tv.tv_usec = round(modf(val, &ipart) * 1000000); tv.tv_usec = MICROPY_FLOAT_C_FUN(round)(MICROPY_FLOAT_C_FUN(modf)(val, &ipart) * MICROPY_FLOAT_CONST(1000000.));
tv.tv_sec = ipart; tv.tv_sec = ipart;
#else #else
tv.tv_sec = mp_obj_get_int(timeout_in); tv.tv_sec = mp_obj_get_int(timeout_in);

View File

@ -176,7 +176,7 @@ mp_obj_t mp_binary_get_val_array(char typecode, void *p, size_t index) {
#endif #endif
#if MICROPY_PY_BUILTINS_FLOAT #if MICROPY_PY_BUILTINS_FLOAT
case 'f': case 'f':
return mp_obj_new_float(((float *)p)[index]); return mp_obj_new_float_from_f(((float *)p)[index]);
case 'd': case 'd':
return mp_obj_new_float(((double *)p)[index]); return mp_obj_new_float(((double *)p)[index]);
#endif #endif
@ -244,7 +244,7 @@ mp_obj_t mp_binary_get_val(char struct_type, char val_type, byte *p_base, byte *
union { uint32_t i; union { uint32_t i;
float f; float f;
} fpu = {val}; } fpu = {val};
return mp_obj_new_float(fpu.f); return mp_obj_new_float_from_f(fpu.f);
} else if (val_type == 'd') { } else if (val_type == 'd') {
union { uint64_t i; union { uint64_t i;
double f; double f;
@ -320,7 +320,7 @@ void mp_binary_set_val(char struct_type, char val_type, mp_obj_t val_in, byte *p
uint32_t i32[2]; uint32_t i32[2];
double f; double f;
} fp_dp; } fp_dp;
fp_dp.f = mp_obj_get_float(val_in); fp_dp.f = mp_obj_get_float_to_d(val_in);
if (BYTES_PER_WORD == 8) { if (BYTES_PER_WORD == 8) {
val = fp_dp.i64; val = fp_dp.i64;
} else { } else {
@ -362,7 +362,7 @@ void mp_binary_set_val_array(char typecode, void *p, size_t index, mp_obj_t val_
((float *)p)[index] = mp_obj_get_float(val_in); ((float *)p)[index] = mp_obj_get_float(val_in);
break; break;
case 'd': case 'd':
((double *)p)[index] = mp_obj_get_float(val_in); ((double *)p)[index] = mp_obj_get_float_to_d(val_in);
break; break;
#endif #endif
// Extension to CPython: array of objects // Extension to CPython: array of objects

View File

@ -72,7 +72,7 @@ STATIC MP_DEFINE_CONST_FUN_OBJ_1(mp_cmath_exp_obj, mp_cmath_exp);
STATIC mp_obj_t mp_cmath_log(mp_obj_t z_obj) { STATIC mp_obj_t mp_cmath_log(mp_obj_t z_obj) {
mp_float_t real, imag; mp_float_t real, imag;
mp_obj_get_complex(z_obj, &real, &imag); mp_obj_get_complex(z_obj, &real, &imag);
return mp_obj_new_complex(0.5 * MICROPY_FLOAT_C_FUN(log)(real * real + imag * imag), MICROPY_FLOAT_C_FUN(atan2)(imag, real)); return mp_obj_new_complex(MICROPY_FLOAT_CONST(0.5) * MICROPY_FLOAT_C_FUN(log)(real * real + imag * imag), MICROPY_FLOAT_C_FUN(atan2)(imag, real));
} }
STATIC MP_DEFINE_CONST_FUN_OBJ_1(mp_cmath_log_obj, mp_cmath_log); STATIC MP_DEFINE_CONST_FUN_OBJ_1(mp_cmath_log_obj, mp_cmath_log);
@ -81,7 +81,7 @@ STATIC MP_DEFINE_CONST_FUN_OBJ_1(mp_cmath_log_obj, mp_cmath_log);
STATIC mp_obj_t mp_cmath_log10(mp_obj_t z_obj) { STATIC mp_obj_t mp_cmath_log10(mp_obj_t z_obj) {
mp_float_t real, imag; mp_float_t real, imag;
mp_obj_get_complex(z_obj, &real, &imag); mp_obj_get_complex(z_obj, &real, &imag);
return mp_obj_new_complex(0.5 * MICROPY_FLOAT_C_FUN(log10)(real * real + imag * imag), 0.4342944819032518 * MICROPY_FLOAT_C_FUN(atan2)(imag, real)); return mp_obj_new_complex(MICROPY_FLOAT_CONST(0.5) * MICROPY_FLOAT_C_FUN(log10)(real * real + imag * imag), MICROPY_FLOAT_CONST(0.4342944819032518) * MICROPY_FLOAT_C_FUN(atan2)(imag, real));
} }
STATIC MP_DEFINE_CONST_FUN_OBJ_1(mp_cmath_log10_obj, mp_cmath_log10); STATIC MP_DEFINE_CONST_FUN_OBJ_1(mp_cmath_log10_obj, mp_cmath_log10);
#endif #endif
@ -90,8 +90,8 @@ STATIC MP_DEFINE_CONST_FUN_OBJ_1(mp_cmath_log10_obj, mp_cmath_log10);
STATIC mp_obj_t mp_cmath_sqrt(mp_obj_t z_obj) { STATIC mp_obj_t mp_cmath_sqrt(mp_obj_t z_obj) {
mp_float_t real, imag; mp_float_t real, imag;
mp_obj_get_complex(z_obj, &real, &imag); mp_obj_get_complex(z_obj, &real, &imag);
mp_float_t sqrt_abs = MICROPY_FLOAT_C_FUN(pow)(real * real + imag * imag, 0.25); mp_float_t sqrt_abs = MICROPY_FLOAT_C_FUN(pow)(real * real + imag * imag, MICROPY_FLOAT_CONST(0.25));
mp_float_t theta = 0.5 * MICROPY_FLOAT_C_FUN(atan2)(imag, real); mp_float_t theta = MICROPY_FLOAT_CONST(0.5) * MICROPY_FLOAT_C_FUN(atan2)(imag, real);
return mp_obj_new_complex(sqrt_abs * MICROPY_FLOAT_C_FUN(cos)(theta), sqrt_abs * MICROPY_FLOAT_C_FUN(sin)(theta)); return mp_obj_new_complex(sqrt_abs * MICROPY_FLOAT_C_FUN(cos)(theta), sqrt_abs * MICROPY_FLOAT_C_FUN(sin)(theta));
} }
STATIC MP_DEFINE_CONST_FUN_OBJ_1(mp_cmath_sqrt_obj, mp_cmath_sqrt); STATIC MP_DEFINE_CONST_FUN_OBJ_1(mp_cmath_sqrt_obj, mp_cmath_sqrt);

View File

@ -227,25 +227,7 @@ STATIC bool mp_native_yield_from(mp_obj_t gen, mp_obj_t send_value, mp_obj_t *re
return false; return false;
} }
#if MICROPY_PY_BUILTINS_FLOAT #if !MICROPY_PY_BUILTINS_FLOAT
STATIC mp_obj_t mp_obj_new_float_from_f(float f) {
return mp_obj_new_float((mp_float_t)f);
}
STATIC mp_obj_t mp_obj_new_float_from_d(double d) {
return mp_obj_new_float((mp_float_t)d);
}
STATIC float mp_obj_get_float_to_f(mp_obj_t o) {
return (float)mp_obj_get_float(o);
}
STATIC double mp_obj_get_float_to_d(mp_obj_t o) {
return (double)mp_obj_get_float(o);
}
#else
STATIC mp_obj_t mp_obj_new_float_from_f(float f) { STATIC mp_obj_t mp_obj_new_float_from_f(float f) {
(void)f; (void)f;

View File

@ -820,6 +820,39 @@ void mp_str_print_quoted(const mp_print_t *print, const byte *str_data, size_t s
#if MICROPY_PY_BUILTINS_FLOAT #if MICROPY_PY_BUILTINS_FLOAT
// float // float
#if MICROPY_FLOAT_IMPL == MICROPY_FLOAT_IMPL_FLOAT
static inline float mp_obj_get_float_to_f(mp_obj_t o) {
return mp_obj_get_float(o);
}
static inline double mp_obj_get_float_to_d(mp_obj_t o) {
return (double)mp_obj_get_float(o);
}
static inline mp_obj_t mp_obj_new_float_from_f(float o) {
return mp_obj_new_float(o);
}
static inline mp_obj_t mp_obj_new_float_from_d(double o) {
return mp_obj_new_float((mp_float_t)o);
}
#elif MICROPY_FLOAT_IMPL == MICROPY_FLOAT_IMPL_DOUBLE
static inline float mp_obj_get_float_to_f(mp_obj_t o) {
return (float)mp_obj_get_float(o);
}
static inline double mp_obj_get_float_to_d(mp_obj_t o) {
return mp_obj_get_float(o);
}
static inline mp_obj_t mp_obj_new_float_from_f(float o) {
return mp_obj_new_float((mp_float_t)o);
}
static inline mp_obj_t mp_obj_new_float_from_d(double o) {
return mp_obj_new_float(o);
}
#endif
#if MICROPY_FLOAT_HIGH_QUALITY_HASH #if MICROPY_FLOAT_HIGH_QUALITY_HASH
mp_int_t mp_float_hash(mp_float_t val); mp_int_t mp_float_hash(mp_float_t val);
#else #else

View File

@ -52,11 +52,13 @@ typedef struct _mp_obj_float_t {
mp_float_t value; mp_float_t value;
} mp_obj_float_t; } mp_obj_float_t;
const mp_obj_float_t mp_const_float_e_obj = {{&mp_type_float}, M_E}; const mp_obj_float_t mp_const_float_e_obj = {{&mp_type_float}, (mp_float_t)M_E};
const mp_obj_float_t mp_const_float_pi_obj = {{&mp_type_float}, M_PI}; const mp_obj_float_t mp_const_float_pi_obj = {{&mp_type_float}, (mp_float_t)M_PI};
#endif #endif
#define MICROPY_FLOAT_ZERO MICROPY_FLOAT_CONST(0.0)
#if MICROPY_FLOAT_HIGH_QUALITY_HASH #if MICROPY_FLOAT_HIGH_QUALITY_HASH
// must return actual integer value if it fits in mp_int_t // must return actual integer value if it fits in mp_int_t
mp_int_t mp_float_hash(mp_float_t src) { mp_int_t mp_float_hash(mp_float_t src) {
@ -208,24 +210,24 @@ STATIC void mp_obj_float_divmod(mp_float_t *x, mp_float_t *y) {
mp_float_t div = (*x - mod) / *y; mp_float_t div = (*x - mod) / *y;
// Python specs require that mod has same sign as second operand // Python specs require that mod has same sign as second operand
if (mod == 0.0) { if (mod == MICROPY_FLOAT_ZERO) {
mod = MICROPY_FLOAT_C_FUN(copysign)(0.0, *y); mod = MICROPY_FLOAT_C_FUN(copysign)(MICROPY_FLOAT_ZERO, *y);
} else { } else {
if ((mod < 0.0) != (*y < 0.0)) { if ((mod < MICROPY_FLOAT_ZERO) != (*y < MICROPY_FLOAT_ZERO)) {
mod += *y; mod += *y;
div -= 1.0; div -= MICROPY_FLOAT_CONST(1.0);
} }
} }
mp_float_t floordiv; mp_float_t floordiv;
if (div == 0.0) { if (div == MICROPY_FLOAT_ZERO) {
// if division is zero, take the correct sign of zero // if division is zero, take the correct sign of zero
floordiv = MICROPY_FLOAT_C_FUN(copysign)(0.0, *x / *y); floordiv = MICROPY_FLOAT_C_FUN(copysign)(MICROPY_FLOAT_ZERO, *x / *y);
} else { } else {
// Python specs require that x == (x//y)*y + (x%y) // Python specs require that x == (x//y)*y + (x%y)
floordiv = MICROPY_FLOAT_C_FUN(floor)(div); floordiv = MICROPY_FLOAT_C_FUN(floor)(div);
if (div - floordiv > 0.5) { if (div - floordiv > MICROPY_FLOAT_CONST(0.5)) {
floordiv += 1.0; floordiv += MICROPY_FLOAT_CONST(1.0);
} }
} }
@ -273,15 +275,15 @@ mp_obj_t mp_obj_float_binary_op(mp_binary_op_t op, mp_float_t lhs_val, mp_obj_t
break; break;
case MP_BINARY_OP_MODULO: case MP_BINARY_OP_MODULO:
case MP_BINARY_OP_INPLACE_MODULO: case MP_BINARY_OP_INPLACE_MODULO:
if (rhs_val == 0) { if (rhs_val == MICROPY_FLOAT_ZERO) {
goto zero_division_error; goto zero_division_error;
} }
lhs_val = MICROPY_FLOAT_C_FUN(fmod)(lhs_val, rhs_val); lhs_val = MICROPY_FLOAT_C_FUN(fmod)(lhs_val, rhs_val);
// Python specs require that mod has same sign as second operand // Python specs require that mod has same sign as second operand
if (lhs_val == 0.0) { if (lhs_val == MICROPY_FLOAT_ZERO) {
lhs_val = MICROPY_FLOAT_C_FUN(copysign)(0.0, rhs_val); lhs_val = MICROPY_FLOAT_C_FUN(copysign)(0.0, rhs_val);
} else { } else {
if ((lhs_val < 0.0) != (rhs_val < 0.0)) { if ((lhs_val < MICROPY_FLOAT_ZERO) != (rhs_val < MICROPY_FLOAT_ZERO)) {
lhs_val += rhs_val; lhs_val += rhs_val;
} }
} }

View File

@ -220,7 +220,7 @@ mp_obj_t mp_parse_num_decimal(const char *str, size_t len, bool allow_imag, bool
if (str + 2 < top && (str[1] | 0x20) == 'n' && (str[2] | 0x20) == 'f') { if (str + 2 < top && (str[1] | 0x20) == 'n' && (str[2] | 0x20) == 'f') {
// inf // inf
str += 3; str += 3;
dec_val = INFINITY; dec_val = (mp_float_t)INFINITY;
if (str + 4 < top && (str[0] | 0x20) == 'i' && (str[1] | 0x20) == 'n' && (str[2] | 0x20) == 'i' && (str[3] | 0x20) == 't' && (str[4] | 0x20) == 'y') { if (str + 4 < top && (str[0] | 0x20) == 'i' && (str[1] | 0x20) == 'n' && (str[2] | 0x20) == 'i' && (str[3] | 0x20) == 't' && (str[4] | 0x20) == 'y') {
// infinity // infinity
str += 5; str += 5;