Commit 3c98a9d1 authored by Matthias Braun's avatar Matthias Braun
Browse files

add some overflow behaviour to tarval float to int conversions

parent 31bcbeaf
......@@ -1347,12 +1347,12 @@ fp_value *fc_rnd(const fp_value *a, fp_value *result)
panic("not yet implemented");
}
bool fc_flt2int(const fp_value *a, void *result, ir_mode *dst_mode)
flt2int_result_t fc_flt2int(const fp_value *a, void *result, ir_mode *dst_mode)
{
if (a->clss == FC_NORMAL) {
if (a->sign && !mode_is_signed(dst_mode)) {
/* FIXME: for now we cannot convert this */
return false;
return FLT2INT_UNKNOWN;
}
int tgt_bits = get_mode_size_bits(dst_mode);
......@@ -1362,6 +1362,15 @@ bool fc_flt2int(const fp_value *a, void *result, ir_mode *dst_mode)
int exp_bias = (1 << (a->desc.exponent_size - 1)) - 1;
int exp_val = sc_val_to_long(_exp(a)) - exp_bias;
assert(exp_val >= 0 && "floating point value not integral before fc_flt2int() call");
/* highest bit outside dst_mode range */
if (exp_val > tgt_bits || (exp_val == tgt_bits &&
/* MIN_INT is the only exception allowed */
(!mode_is_signed(dst_mode) || !a->sign ||
sc_get_highest_set_bit(_mant(a))
!= sc_get_lowest_set_bit(_mant(a))))) {
return a->sign ? FLT2INT_NEGATIVE_OVERFLOW
: FLT2INT_POSITIVE_OVERFLOW;
}
int mantissa_size = a->desc.mantissa_size + ROUNDING_BITS;
int shift = exp_val - mantissa_size;
......@@ -1372,39 +1381,15 @@ bool fc_flt2int(const fp_value *a, void *result, ir_mode *dst_mode)
} else {
sc_shrI(_mant(a), -shift, tgt_bits, 0, result);
}
/* check for overflow */
int highest = sc_get_highest_set_bit(result);
if (mode_is_signed(dst_mode)) {
if (highest == sc_get_lowest_set_bit(result)) {
/* need extra test for MIN_INT */
if (highest >= (int) get_mode_size_bits(dst_mode)) {
/* FIXME: handle overflow */
return false;
}
} else {
if (highest >= (int) get_mode_size_bits(dst_mode) - 1) {
/* FIXME: handle overflow */
return false;
}
}
} else {
if (highest >= (int) get_mode_size_bits(dst_mode)) {
/* FIXME: handle overflow */
return false;
}
}
if (a->sign)
sc_neg(result, result);
return true;
return FLT2INT_OK;
} else if (a->clss == FC_ZERO) {
sc_zero(result);
return true;
return FLT2INT_OK;
}
return false;
return FLT2INT_UNKNOWN;
}
int fc_is_exact(void)
......
......@@ -151,10 +151,17 @@ char *fc_print(const fp_value *a, char *buf, int buflen, unsigned base);
*/
ir_relation fc_comp(const fp_value *a, const fp_value *b);
typedef enum flt2int_result_t {
FLT2INT_OK,
FLT2INT_POSITIVE_OVERFLOW,
FLT2INT_NEGATIVE_OVERFLOW,
FLT2INT_UNKNOWN
} flt2int_result_t;
/**
* Converts an floating point value into an integer value.
*/
bool fc_flt2int(const fp_value *a, void *result, ir_mode *dst_mode);
flt2int_result_t fc_flt2int(const fp_value *a, void *result, ir_mode *dst_mode);
/**
* Returns non-zero if the mantissa is zero, i.e. 1.0Exxx
......
......@@ -707,9 +707,17 @@ ir_tarval *tarval_convert_to(ir_tarval *src, ir_mode *dst_mode)
case irms_int_number: {
fp_value *res = fc_int((const fp_value*) src->value, NULL);
char *buffer = ALLOCAN(char, sc_get_buffer_length());
if (!fc_flt2int(res, buffer, dst_mode))
flt2int_result_t cres = fc_flt2int(res, buffer, dst_mode);
switch (cres) {
case FLT2INT_POSITIVE_OVERFLOW:
return get_mode_max(dst_mode);
case FLT2INT_NEGATIVE_OVERFLOW:
return get_mode_min(dst_mode);
case FLT2INT_UNKNOWN:
return tarval_bad;
return get_tarval(buffer, sc_get_buffer_length(), dst_mode);
case FLT2INT_OK:
return get_tarval(buffer, sc_get_buffer_length(), dst_mode);
}
}
default:
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment