Skip to content

Commit

Permalink
all: Fix implicit floating point promotion.
Browse files Browse the repository at this point in the history
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.
  • Loading branch information
stinos authored and dpgeorge committed Apr 18, 2020
1 parent b909e8b commit 0ba68f8
Show file tree
Hide file tree
Showing 11 changed files with 70 additions and 54 deletions.
7 changes: 3 additions & 4 deletions extmod/moductypes.c
Expand Up @@ -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]);
#if MICROPY_PY_BUILTINS_FLOAT
case FLOAT32:
return mp_obj_new_float(((float *)p)[index]);
return mp_obj_new_float_from_f(((float *)p)[index]);
case FLOAT64:
return mp_obj_new_float(((double *)p)[index]);
#endif
Expand All @@ -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) {
#if MICROPY_PY_BUILTINS_FLOAT
if (val_type == FLOAT32 || val_type == FLOAT64) {
mp_float_t v = mp_obj_get_float(val);
if (val_type == FLOAT32) {
((float *)p)[index] = v;
((float *)p)[index] = mp_obj_get_float_to_f(val);
} else {
((double *)p)[index] = v;
((double *)p)[index] = mp_obj_get_float_to_d(val);
}
return;
}
Expand Down
2 changes: 1 addition & 1 deletion extmod/moduselect.c
Expand Up @@ -125,7 +125,7 @@ STATIC mp_obj_t select_select(size_t n_args, const mp_obj_t *args) {
if (n_args == 4) {
if (args[3] != mp_const_none) {
#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) {
timeout = (mp_uint_t)(timeout_f * 1000);
}
Expand Down
4 changes: 2 additions & 2 deletions ports/unix/modffi.c
Expand Up @@ -167,7 +167,7 @@ STATIC mp_obj_t return_ffi_value(ffi_arg val, char type) {
union { ffi_arg ffi;
float flt;
} val_union = { .ffi = val };
return mp_obj_new_float(val_union.flt);
return mp_obj_new_float_from_f(val_union.flt);
}
case 'd': {
double *p = (double *)&val;
Expand Down Expand Up @@ -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);
} else if (*argtype == 'd') {
double *p = (double *)&values[i];
*p = mp_obj_get_float(a);
*p = mp_obj_get_float_to_d(a);
#endif
} else if (a == mp_const_none) {
values[i] = 0;
Expand Down
8 changes: 4 additions & 4 deletions ports/unix/modtime.c
Expand Up @@ -61,7 +61,7 @@ static inline int msec_sleep_tv(struct timeval *tv) {
#endif

#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
#error Unsupported clock() implementation
#endif
Expand All @@ -84,7 +84,7 @@ STATIC mp_obj_t mod_time_clock(void) {
// float cannot represent full range of int32 precisely, so we pre-divide
// int to reduce resolution, and then actually do float division hoping
// 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
return mp_obj_new_int((mp_int_t)clock());
#endif
Expand All @@ -95,8 +95,8 @@ STATIC mp_obj_t mod_time_sleep(mp_obj_t arg) {
#if MICROPY_PY_BUILTINS_FLOAT
struct timeval tv;
mp_float_t val = mp_obj_get_float(arg);
double ipart;
tv.tv_usec = round(modf(val, &ipart) * 1000000);
mp_float_t ipart;
tv.tv_usec = MICROPY_FLOAT_C_FUN(round)(MICROPY_FLOAT_C_FUN(modf)(val, &ipart) * MICROPY_FLOAT_CONST(1000000.));
tv.tv_sec = ipart;
int res;
while (1) {
Expand Down
4 changes: 2 additions & 2 deletions ports/unix/modusocket.c
Expand Up @@ -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 MICROPY_PY_BUILTINS_FLOAT
mp_float_t val = mp_obj_get_float(timeout_in);
double ipart;
tv.tv_usec = round(modf(val, &ipart) * 1000000);
mp_float_t ipart;
tv.tv_usec = MICROPY_FLOAT_C_FUN(round)(MICROPY_FLOAT_C_FUN(modf)(val, &ipart) * MICROPY_FLOAT_CONST(1000000.));
tv.tv_sec = ipart;
#else
tv.tv_sec = mp_obj_get_int(timeout_in);
Expand Down
8 changes: 4 additions & 4 deletions py/binary.c
Expand Up @@ -176,7 +176,7 @@ mp_obj_t mp_binary_get_val_array(char typecode, void *p, size_t index) {
#endif
#if MICROPY_PY_BUILTINS_FLOAT
case 'f':
return mp_obj_new_float(((float *)p)[index]);
return mp_obj_new_float_from_f(((float *)p)[index]);
case 'd':
return mp_obj_new_float(((double *)p)[index]);
#endif
Expand Down Expand Up @@ -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;
float f;
} fpu = {val};
return mp_obj_new_float(fpu.f);
return mp_obj_new_float_from_f(fpu.f);
} else if (val_type == 'd') {
union { uint64_t i;
double f;
Expand Down Expand Up @@ -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];
double f;
} 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) {
val = fp_dp.i64;
} else {
Expand Down Expand Up @@ -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);
break;
case 'd':
((double *)p)[index] = mp_obj_get_float(val_in);
((double *)p)[index] = mp_obj_get_float_to_d(val_in);
break;
#endif
// Extension to CPython: array of objects
Expand Down
8 changes: 4 additions & 4 deletions py/modcmath.c
Expand Up @@ -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) {
mp_float_t 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);

Expand All @@ -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) {
mp_float_t 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);
#endif
Expand All @@ -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) {
mp_float_t 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 theta = 0.5 * MICROPY_FLOAT_C_FUN(atan2)(imag, real);
mp_float_t sqrt_abs = MICROPY_FLOAT_C_FUN(pow)(real * real + imag * imag, MICROPY_FLOAT_CONST(0.25));
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));
}
STATIC MP_DEFINE_CONST_FUN_OBJ_1(mp_cmath_sqrt_obj, mp_cmath_sqrt);
Expand Down
20 changes: 1 addition & 19 deletions py/nativeglue.c
Expand Up @@ -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;
}

#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
#if !MICROPY_PY_BUILTINS_FLOAT

STATIC mp_obj_t mp_obj_new_float_from_f(float f) {
(void)f;
Expand Down
33 changes: 33 additions & 0 deletions py/obj.h
Expand Up @@ -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
// 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
mp_int_t mp_float_hash(mp_float_t val);
#else
Expand Down
28 changes: 15 additions & 13 deletions py/objfloat.c
Expand Up @@ -52,11 +52,13 @@ typedef struct _mp_obj_float_t {
mp_float_t value;
} 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_pi_obj = {{&mp_type_float}, M_PI};
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}, (mp_float_t)M_PI};

#endif

#define MICROPY_FLOAT_ZERO MICROPY_FLOAT_CONST(0.0)

#if MICROPY_FLOAT_HIGH_QUALITY_HASH
// must return actual integer value if it fits in mp_int_t
mp_int_t mp_float_hash(mp_float_t src) {
Expand Down Expand Up @@ -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;

// Python specs require that mod has same sign as second operand
if (mod == 0.0) {
mod = MICROPY_FLOAT_C_FUN(copysign)(0.0, *y);
if (mod == MICROPY_FLOAT_ZERO) {
mod = MICROPY_FLOAT_C_FUN(copysign)(MICROPY_FLOAT_ZERO, *y);
} else {
if ((mod < 0.0) != (*y < 0.0)) {
if ((mod < MICROPY_FLOAT_ZERO) != (*y < MICROPY_FLOAT_ZERO)) {
mod += *y;
div -= 1.0;
div -= MICROPY_FLOAT_CONST(1.0);
}
}

mp_float_t floordiv;
if (div == 0.0) {
if (div == MICROPY_FLOAT_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 {
// Python specs require that x == (x//y)*y + (x%y)
floordiv = MICROPY_FLOAT_C_FUN(floor)(div);
if (div - floordiv > 0.5) {
floordiv += 1.0;
if (div - floordiv > MICROPY_FLOAT_CONST(0.5)) {
floordiv += MICROPY_FLOAT_CONST(1.0);
}
}

Expand Down Expand Up @@ -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;
case MP_BINARY_OP_MODULO:
case MP_BINARY_OP_INPLACE_MODULO:
if (rhs_val == 0) {
if (rhs_val == MICROPY_FLOAT_ZERO) {
goto zero_division_error;
}
lhs_val = MICROPY_FLOAT_C_FUN(fmod)(lhs_val, rhs_val);
// 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);
} 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;
}
}
Expand Down
2 changes: 1 addition & 1 deletion py/parsenum.c
Expand Up @@ -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') {
// inf
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') {
// infinity
str += 5;
Expand Down

0 comments on commit 0ba68f8

Please sign in to comment.