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

Cleanup/Rewrite fltcalc parts

- x86 extended float mantissa size includes the explicit one now
- fixed broken qnan/snan for x86 extended float
- simplification/tuning
parent 6e6733f9
......@@ -96,8 +96,8 @@ FIRM_API ir_mode *new_reference_mode(const char *name,
* @param name the name of the mode to be created
* @param arithmetic arithmetic/representation of the mode
* @param exponent_size size of exponent in bits
* @param mantissa_size size of mantissa in bits (number of bits after the
* leading one).
* @param mantissa_size size of mantissa in bits (including explicit one in
* irma_x86_extended_float)
* @param int_conv_overflow Semantic on float to integer conversion overflow.
*/
FIRM_API ir_mode *new_float_mode(const char *name,
......@@ -416,11 +416,8 @@ FIRM_API ir_mode *get_reference_mode_unsigned_eq(ir_mode *mode);
FIRM_API void set_reference_mode_unsigned_eq(ir_mode *ref_mode, ir_mode *int_mode);
/**
* Returns size of mantissa in bits (for float modes).
* Note: This is the number of bits used after the leading one. So the actual
* accuracy of the significand is get_mode_mantissa_size()+1. The number of bits
* used in the encoding depends on whether the floating point mode has an implicit
* (ieee754) or explicit (x86_extended) encoding of the leading one.
* Returns size of bits used for to encode the mantissa (for float modes).
* This includes the leading one for modes with irma_x86_extended_float.
*/
FIRM_API unsigned get_mode_mantissa_size(const ir_mode *mode);
......
......@@ -1450,7 +1450,7 @@ static void ia32_init(void)
/* note mantissa is 64bit but with explicitely encoded 1 so the really
* usable part as counted by firm is only 63 bits */
ia32_mode_E = new_float_mode("E", irma_x86_extended_float, 15, 63,
ia32_mode_E = new_float_mode("E", irma_x86_extended_float, 15, 64,
ir_overflow_indefinite);
ia32_type_E = new_type_primitive(ia32_mode_E);
set_type_size_bytes(ia32_type_E, 12);
......
......@@ -234,7 +234,6 @@ ir_mode *new_float_mode(const char *name, ir_mode_arithmetic arithmetic,
if (arithmetic == irma_x86_extended_float) {
explicit_one = true;
bit_size++;
} else if (arithmetic != irma_ieee754) {
panic("Arithmetic %s invalid for float");
}
......
This diff is collapsed.
......@@ -117,12 +117,10 @@ fp_value *fc_cast(const fp_value *val, const float_descriptor_t *desc, fp_value
* @return The result pointer passed to the function. If this was NULL this returns
* a pointer to the internal accumulator buffer
*/
fp_value *fc_get_min(const float_descriptor_t *desc, fp_value *result);
fp_value *fc_get_max(const float_descriptor_t *desc, fp_value *result);
fp_value *fc_get_max(const float_descriptor_t *desc, fp_value *result, bool sign);
fp_value *fc_get_snan(const float_descriptor_t *desc, fp_value *result);
fp_value *fc_get_qnan(const float_descriptor_t *desc, fp_value *result);
fp_value *fc_get_plusinf(const float_descriptor_t *desc, fp_value *result);
fp_value *fc_get_minusinf(const float_descriptor_t *desc, fp_value *result);
fp_value *fc_get_inf(const float_descriptor_t *desc, fp_value *result, bool sign);
/*@}*/
bool fc_is_zero(const fp_value *a);
......
......@@ -362,7 +362,7 @@ static void do_divmod(const char *rDividend, const char *divisor, char *quot,
}
end:
/* sets carry if remainder is non-zero ??? */
carry_flag = !sc_is_zero(rem);
carry_flag = !sc_is_zero(rem, calc_buffer_size);
if (div_sign)
do_negate(quot, quot);
......@@ -453,7 +453,7 @@ static void do_shr(const char *val1, char *buffer, long shift_cnt, int bitsize,
/* if shifting far enough the result is either 0 or -1 */
if (shift_cnt >= bitsize) {
if (!sc_is_zero(val1)) {
if (!sc_is_zero(val1, calc_buffer_size)) {
carry_flag = true;
}
memset(buffer, sign, calc_buffer_size);
......@@ -820,14 +820,36 @@ void sc_set_bit_at(void *value, unsigned pos)
val[nibble] |= SHIFT(pos & 3);
}
bool sc_is_zero(const void *value)
void sc_clear_bit_at(void *value, unsigned pos)
{
char *val = (char*) value;
unsigned nibble = pos >> 2;
val[nibble] &= ~SHIFT(pos & 3);
}
bool sc_is_zero(const void *value, unsigned bits)
{
const char* val = (const char *)value;
for (int counter = 0; counter < calc_buffer_size; ++counter) {
if (val[counter] != SC_0)
unsigned i;
for (i = 0; i < bits/SC_BITS; ++i) {
if (val[i] != SC_0)
return false;
}
return true;
char mask = max_digit[bits%SC_BITS];
return mask == 0 || (val[i] & mask) == SC_0;
}
bool sc_is_all_one(const void *value, unsigned bits)
{
const char* val = (const char*)value;
unsigned i;
for (i = 0; i < bits/SC_BITS; ++i) {
if (val[i] != SC_F)
return false;
}
char mask = max_digit[bits%SC_BITS];
return mask == 0 || (val[i] & mask) == mask;
}
bool sc_is_negative(const void *value)
......
......@@ -227,8 +227,9 @@ ir_relation sc_comp(void const *val1, void const *val2);
int sc_get_highest_set_bit(const void *value);
int sc_get_lowest_set_bit(const void *value);
bool sc_is_zero(const void *value);
bool sc_is_negative(const void *value);
bool sc_is_zero(const void *value, unsigned num_bits);
bool sc_is_all_one(const void *value, unsigned num_bits);
/**
* Return the bits of a tarval at a given byte-offset.
......@@ -274,6 +275,7 @@ int sc_get_bit_at(const void *value, unsigned pos);
/** Set the bit at the specified position. */
void sc_set_bit_at(void *value, unsigned pos);
void sc_clear_bit_at(void *value, unsigned pos);
/* Strange semantics */
bool sc_had_carry(void);
......
......@@ -201,7 +201,7 @@ static const float_descriptor_t *get_descriptor(const ir_mode *mode)
return &mode->float_desc;
}
static ir_tarval *get_tarval_from_fp_value(fp_value *val, ir_mode *mode)
static ir_tarval *get_tarval_from_fp_value(const fp_value *val, ir_mode *mode)
{
const float_descriptor_t *desc = get_descriptor(mode);
const int buffer_length = fc_get_buffer_length();
......@@ -470,7 +470,7 @@ ir_tarval *get_tarval_max(ir_mode *mode)
switch (get_mode_sort(mode)) {
case irms_float_number: {
const float_descriptor_t *desc = get_descriptor(mode);
fc_get_max(desc, NULL);
fc_get_max(desc, NULL, false);
return get_tarval(fc_get_buffer(), fc_get_buffer_length(), mode);
}
......@@ -494,7 +494,7 @@ ir_tarval *get_tarval_min(ir_mode *mode)
switch (get_mode_sort(mode)) {
case irms_float_number: {
const float_descriptor_t *desc = get_descriptor(mode);
fc_get_min(desc, NULL);
fc_get_max(desc, NULL, true);
return get_tarval(fc_get_buffer(), fc_get_buffer_length(), mode);
}
......@@ -618,7 +618,7 @@ ir_tarval *get_tarval_plus_inf(ir_mode *mode)
if (get_mode_sort(mode) != irms_float_number)
panic("mode %F does not support +inf value", mode);
const float_descriptor_t *desc = get_descriptor(mode);
fc_get_plusinf(desc, NULL);
fc_get_inf(desc, NULL, false);
return get_tarval(fc_get_buffer(), fc_get_buffer_length(), mode);
}
......@@ -627,7 +627,7 @@ ir_tarval *get_tarval_minus_inf(ir_mode *mode)
if (get_mode_sort(mode) != irms_float_number)
panic("mode %F does not support -inf value", mode);
const float_descriptor_t *desc = get_descriptor(mode);
fc_get_minusinf(desc, NULL);
fc_get_inf(desc, NULL, true);
return get_tarval(fc_get_buffer(), fc_get_buffer_length(), mode);
}
......
#include <float.h>
#include <assert.h>
#include <math.h>
#include "firm.h"
#include "tv.h"
#include "irmode.h"
static void test_float(float v, ir_tarval *known)
{
ir_tarval *tv = new_tarval_from_double(v, mode_F);
assert(tarval_is_double(tv));
float back = get_tarval_double(tv);
assert(v == back || (isnan(v) && isnan(back)));
assert(known == NULL || tv == known);
}
static void test_double(double v, ir_tarval *known)
{
ir_tarval *tv = new_tarval_from_double(v, mode_D);
assert(tarval_is_double(tv));
double back = get_tarval_double(tv);
assert(v == back || (isnan(v) && isnan(back)));
assert(known == NULL || tv == known);
}
static ir_mode *mode_E;
static void test_ldouble(long double v, ir_tarval *known)
{
ir_tarval *tv = new_tarval_from_long_double(v, mode_E);
long double back = get_tarval_long_double(tv);
assert(v == back || (isnan(v) && isnan(back)));
assert(known == NULL || tv == known);
}
int main(void)
{
ir_init();
test_float(0, get_mode_null(mode_F));
test_float(1, get_mode_one(mode_F));
test_float(-1, get_mode_minus_one(mode_F));
test_float(FLT_MAX, get_mode_max(mode_F));
test_float(-FLT_MAX, get_mode_min(mode_F));
test_float(FLT_EPSILON, NULL);
test_float(FLT_MIN, NULL);
test_float(INFINITY, get_mode_infinite(mode_F));
test_float(HUGE_VALF, NULL);
test_float(NAN, get_mode_NAN(mode_F));
test_float(FLT_MIN * FLT_EPSILON, NULL); // subnormal
test_double(0, get_mode_null(mode_D));
test_double(1, get_mode_one(mode_D));
test_double(-1, get_mode_minus_one(mode_D));
test_double(DBL_MAX, get_mode_max(mode_D));
test_double(-DBL_MAX, get_mode_min(mode_D));
test_double(DBL_EPSILON, NULL);
test_double(DBL_MIN, NULL);
test_double(HUGE_VAL, NULL);
test_double(INFINITY, get_mode_infinite(mode_D));
test_double(NAN, get_mode_NAN(mode_D));
test_double(DBL_MIN * DBL_EPSILON, NULL); // subnormal
#if LDBL_MANT_DIG == 64
mode_E = new_float_mode("E", irma_x86_extended_float, 15, 64,
ir_overflow_indefinite);
#elif LDBL_MANT_DIG == 53
mode_E = mode_D;
#else
printf("long double tests skipped\n");
return 0;
#endif
test_ldouble(0, get_mode_null(mode_E));
test_ldouble(1, get_mode_one(mode_E));
test_ldouble(-1, get_mode_minus_one(mode_E));
test_ldouble(LDBL_MAX, get_mode_max(mode_E));
test_ldouble(-LDBL_MAX, get_mode_min(mode_E));
test_ldouble(LDBL_EPSILON, NULL);
test_ldouble(LDBL_MIN, NULL);
test_ldouble(HUGE_VAL, NULL);
test_ldouble(INFINITY, get_mode_infinite(mode_E));
test_ldouble(NAN, get_mode_NAN(mode_E));
test_ldouble(LDBL_MIN * LDBL_EPSILON, NULL); // subnormal
return 0;
}
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