if (is_Const(b)) {
tarval *tv = get_Const_tarval(b);
- if (tarval_ieee754_zero_mantissa(tv)) {
- tv = tarval_quo(get_mode_one(mode), tv);
- if (tv != tarval_bad) {
- ir_node *blk = get_irn_n(n, -1);
- ir_node *c = new_r_Const(current_ir_graph, blk, mode, tv);
- ir_node *a = get_Quot_left(n);
- ir_node *m = new_rd_Mul(get_irn_dbg_info(n), current_ir_graph, blk, a, c, mode);
- ir_node *mem = get_Quot_mem(n);
-
- turn_into_tuple(n, pn_Quot_max);
- set_Tuple_pred(n, pn_Quot_M, mem);
- set_Tuple_pred(n, pn_Quot_X_regular, new_r_Jmp(current_ir_graph, blk));
- set_Tuple_pred(n, pn_Quot_X_except, new_r_Bad(current_ir_graph));
- set_Tuple_pred(n, pn_Quot_res, m);
- DBG_OPT_ALGSIM1(oldn, a, b, m, FS_OPT_FP_INV_MUL);
- }
+ tv = tarval_quo(get_mode_one(mode), tv);
+
+ if (tv != tarval_bad && tarval_ieee754_get_exact()) {
+ ir_node *blk = get_irn_n(n, -1);
+ ir_node *c = new_r_Const(current_ir_graph, blk, mode, tv);
+ ir_node *a = get_Quot_left(n);
+ ir_node *m = new_rd_Mul(get_irn_dbg_info(n), current_ir_graph, blk, a, c, mode);
+ ir_node *mem = get_Quot_mem(n);
+
+ turn_into_tuple(n, pn_Quot_max);
+ set_Tuple_pred(n, pn_Quot_M, mem);
+ set_Tuple_pred(n, pn_Quot_X_regular, new_r_Jmp(current_ir_graph, blk));
+ set_Tuple_pred(n, pn_Quot_X_except, new_r_Bad(current_ir_graph));
+ set_Tuple_pred(n, pn_Quot_res, m);
+ DBG_OPT_ALGSIM1(oldn, a, b, m, FS_OPT_FP_INV_MUL);
}
}
}
static int value_size;
static int max_precision;
+/** Exact flag. */
+static int fc_exact = 1;
+
#if 0
static void fail_char(const char *str, unsigned int len, int pos) {
if (*(str+pos))
return packed;
}
-static void normalize(const fp_value *in_val, fp_value *out_val, int sticky) {
+/**
+ * Normalize a fp_value.
+ *
+ * @return non-zero if result is exact
+ */
+static int normalize(const fp_value *in_val, fp_value *out_val, int sticky) {
+ int exact = 1;
int hsb;
char lsb, guard, round, round_dir = 0;
char *temp = alloca(value_size);
out_val->desc.clss = NORMAL;
- /* mantissa all zeros, so zero exponent (because of explicit one)*/
+ /* mantissa all zeros, so zero exponent (because of explicit one) */
if (hsb == 2 + in_val->desc.mantissa_size) {
sc_val_from_ulong(0, _exp(out_val));
hsb = -1;
_shift_right(_mant(in_val), temp, _mant(out_val));
/* remember if some bits were shifted away */
- if (!sticky) sticky = sc_had_carry();
-
+ if (sc_had_carry()) {
+ exact = 0;
+ sticky = 1;
+ }
sc_add(_exp(in_val), temp, _exp(out_val));
} else if (hsb > -1) {
/* shift left */
sc_sub(temp, _exp(out_val), NULL);
_shift_right(_mant(out_val), sc_get_buffer(), _mant(out_val));
- if (!sticky) sticky = sc_had_carry();
+ if (sc_had_carry()) {
+ exact = 0;
+ sticky = 1;
+ }
/* denormalized means exponent of zero */
sc_val_from_ulong(0, _exp(out_val));
if (lsb != 0) {
sc_val_from_long(lsb, temp);
sc_add(_mant(out_val), temp, _mant(out_val));
+ exact = 0;
}
/* could have rounded down to zero */
if ((out_val->desc.clss != SUBNORMAL) && (hsb < -1)) {
sc_val_from_ulong(1, temp);
_shift_right(_mant(out_val), temp, _mant(out_val));
-
+ if (exact && sc_had_carry())
+ exact = 0;
sc_add(_exp(out_val), temp, _exp(out_val));
} else if ((out_val->desc.clss == SUBNORMAL) && (hsb == -1)) {
/* overflow caused the mantissa to be normal again,
}
}
}
+ return exact;
}
/**
char sign, res_sign;
char sticky;
+ fc_exact = 1;
+
handle_NAN(a, b, result);
/* make sure result has a descriptor */
_shift_right(_mant(b), exp_diff, temp);
sticky = sc_had_carry();
+ fc_exact &= !sticky;
if (sticky && sign) {
/* if subtracting a little more than the represented value or adding a little
/* resulting exponent is the bigger one */
memmove(_exp(result), _exp(a), value_size);
- normalize(result, result, sticky);
+ fc_exact &= normalize(result, result, sticky);
}
/**
* calculate a * b
*/
static void _fmul(const fp_value *a, const fp_value *b, fp_value *result) {
+ int sticky;
char *temp;
char res_sign;
+ fc_exact = 1;
+
handle_NAN(a, b, result);
temp = alloca(value_size);
sc_val_from_ulong(2 + result->desc.mantissa_size, temp);
_shift_right(_mant(result), temp, _mant(result));
+ sticky = sc_had_carry();
+ fc_exact &= !sticky;
- normalize(result, result, sc_had_carry());
+ fc_exact &= normalize(result, result, sticky);
}
/**
* calculate a / b
*/
static void _fdiv(const fp_value *a, const fp_value *b, fp_value *result) {
+ int sticky;
char *temp, *dividend;
char res_sign;
+ fc_exact = 1;
+
handle_NAN(a, b, result);
temp = alloca(value_size);
sc_val_from_ulong(1, divisor);
_shift_right(_mant(b), divisor, divisor);
sc_div(dividend, divisor, _mant(result));
+ sticky = sc_had_carry();
+ fc_exact &= !sticky;
}
- normalize(result, result, sc_had_carry());
+ fc_exact &= normalize(result, result, sticky);
}
#if 0
int exp_bias, exp_val;
char *temp;
+ /* fixme: can be exact */
+ fc_exact = 0;
+
temp = alloca(value_size);
if (a != result)
immediate_prec = bits;
return old;
}
+
+int fc_is_exact(void) {
+ return fc_exact;
+}
}
}
-int sc_div(const void *value1, const void *value2, void *buffer) {
+void sc_div(const void *value1, const void *value2, void *buffer) {
/* temp buffer holding unused result of divmod */
- char *mod_res = alloca(calc_buffer_size);
+ char *unused_res = alloca(calc_buffer_size);
CLEAR_BUFFER(calc_buffer);
carry_flag = 0;
DEBUGPRINTF_COMPUTATION(("%s / ", sc_print_hex(value1)));
DEBUGPRINTF_COMPUTATION(("%s -> ", sc_print_hex(value2)));
- _divmod(value1, value2, calc_buffer, mod_res);
+ _divmod(value1, value2, calc_buffer, unused_res);
DEBUGPRINTF_COMPUTATION(("%s\n", sc_print_hex(calc_buffer)));
if ((buffer != NULL) && (buffer != calc_buffer)) {
memcpy(buffer, calc_buffer, calc_buffer_size);
}
- return sc_is_zero(mod_res);
}
void sc_mod(const void *value1, const void *value2, void *buffer) {