mirror of
https://github.com/Z3Prover/z3
synced 2025-04-10 19:27:06 +00:00
Merge branch 'master' of https://github.com/Z3Prover/z3
This commit is contained in:
commit
271b56aa1b
|
@ -335,10 +335,13 @@ void fpa2bv_converter::mk_rm_const(func_decl * f, expr_ref & result) {
|
|||
}
|
||||
|
||||
void fpa2bv_converter::mk_pinf(func_decl * f, expr_ref & result) {
|
||||
sort * srt = f->get_range();
|
||||
SASSERT(is_float(srt));
|
||||
unsigned sbits = m_util.get_sbits(srt);
|
||||
unsigned ebits = m_util.get_ebits(srt);
|
||||
mk_pinf(f->get_range(), result);
|
||||
}
|
||||
|
||||
void fpa2bv_converter::mk_pinf(sort * s, expr_ref & result) {
|
||||
SASSERT(is_float(s));
|
||||
unsigned sbits = m_util.get_sbits(s);
|
||||
unsigned ebits = m_util.get_ebits(s);
|
||||
expr_ref top_exp(m);
|
||||
mk_top_exp(ebits, top_exp);
|
||||
mk_fp(m_bv_util.mk_numeral(0, 1),
|
||||
|
@ -348,10 +351,13 @@ void fpa2bv_converter::mk_pinf(func_decl * f, expr_ref & result) {
|
|||
}
|
||||
|
||||
void fpa2bv_converter::mk_ninf(func_decl * f, expr_ref & result) {
|
||||
sort * srt = f->get_range();
|
||||
SASSERT(is_float(srt));
|
||||
unsigned sbits = m_util.get_sbits(srt);
|
||||
unsigned ebits = m_util.get_ebits(srt);
|
||||
mk_ninf(f->get_range(), result);
|
||||
}
|
||||
|
||||
void fpa2bv_converter::mk_ninf(sort * s, expr_ref & result) {
|
||||
SASSERT(is_float(s));
|
||||
unsigned sbits = m_util.get_sbits(s);
|
||||
unsigned ebits = m_util.get_ebits(s);
|
||||
expr_ref top_exp(m);
|
||||
mk_top_exp(ebits, top_exp);
|
||||
mk_fp(m_bv_util.mk_numeral(1, 1),
|
||||
|
@ -361,23 +367,29 @@ void fpa2bv_converter::mk_ninf(func_decl * f, expr_ref & result) {
|
|||
}
|
||||
|
||||
void fpa2bv_converter::mk_nan(func_decl * f, expr_ref & result) {
|
||||
sort * srt = f->get_range();
|
||||
SASSERT(is_float(srt));
|
||||
unsigned sbits = m_util.get_sbits(srt);
|
||||
unsigned ebits = m_util.get_ebits(srt);
|
||||
mk_nan(f->get_range(), result);
|
||||
}
|
||||
|
||||
void fpa2bv_converter::mk_nan(sort * s, expr_ref & result) {
|
||||
SASSERT(is_float(s));
|
||||
unsigned sbits = m_util.get_sbits(s);
|
||||
unsigned ebits = m_util.get_ebits(s);
|
||||
expr_ref top_exp(m);
|
||||
mk_top_exp(ebits, top_exp);
|
||||
mk_fp(m_bv_util.mk_numeral(0, 1),
|
||||
top_exp,
|
||||
m_bv_util.mk_numeral(1, sbits-1),
|
||||
m_bv_util.mk_numeral(1, sbits - 1),
|
||||
result);
|
||||
}
|
||||
|
||||
void fpa2bv_converter::mk_nzero(func_decl *f, expr_ref & result) {
|
||||
sort * srt = f->get_range();
|
||||
SASSERT(is_float(srt));
|
||||
unsigned sbits = m_util.get_sbits(srt);
|
||||
unsigned ebits = m_util.get_ebits(srt);
|
||||
void fpa2bv_converter::mk_nzero(func_decl * f, expr_ref & result) {
|
||||
mk_nzero(f->get_range(), result);
|
||||
}
|
||||
|
||||
void fpa2bv_converter::mk_nzero(sort * s, expr_ref & result) {
|
||||
SASSERT(is_float(s));
|
||||
unsigned sbits = m_util.get_sbits(s);
|
||||
unsigned ebits = m_util.get_ebits(s);
|
||||
expr_ref bot_exp(m);
|
||||
mk_bot_exp(ebits, bot_exp);
|
||||
mk_fp(m_bv_util.mk_numeral(1, 1),
|
||||
|
@ -386,11 +398,14 @@ void fpa2bv_converter::mk_nzero(func_decl *f, expr_ref & result) {
|
|||
result);
|
||||
}
|
||||
|
||||
void fpa2bv_converter::mk_pzero(func_decl *f, expr_ref & result) {
|
||||
sort * srt = f->get_range();
|
||||
SASSERT(is_float(srt));
|
||||
unsigned sbits = m_util.get_sbits(srt);
|
||||
unsigned ebits = m_util.get_ebits(srt);
|
||||
void fpa2bv_converter::mk_pzero(func_decl * f, expr_ref & result) {
|
||||
mk_pzero(f->get_range(), result);
|
||||
}
|
||||
|
||||
void fpa2bv_converter::mk_pzero(sort * s, expr_ref & result) {
|
||||
SASSERT(is_float(s));
|
||||
unsigned sbits = m_util.get_sbits(s);
|
||||
unsigned ebits = m_util.get_ebits(s);
|
||||
expr_ref bot_exp(m);
|
||||
mk_bot_exp(ebits, bot_exp);
|
||||
mk_fp(m_bv_util.mk_numeral(0, 1),
|
||||
|
@ -399,11 +414,22 @@ void fpa2bv_converter::mk_pzero(func_decl *f, expr_ref & result) {
|
|||
result);
|
||||
}
|
||||
|
||||
void fpa2bv_converter::mk_one(func_decl *f, expr_ref sign, expr_ref & result) {
|
||||
sort * srt = f->get_range();
|
||||
SASSERT(is_float(srt));
|
||||
unsigned sbits = m_util.get_sbits(srt);
|
||||
unsigned ebits = m_util.get_ebits(srt);
|
||||
void fpa2bv_converter::mk_zero(sort * s, expr_ref & sgn, expr_ref & result) {
|
||||
expr_ref is_pos(m), pzero(m), nzero(m);
|
||||
is_pos = m.mk_eq(sgn, m_bv_util.mk_numeral(0, 1));
|
||||
mk_pzero(s, pzero);
|
||||
mk_nzero(s, nzero);
|
||||
mk_ite(is_pos, pzero, nzero, result);
|
||||
}
|
||||
|
||||
void fpa2bv_converter::mk_one(func_decl * f, expr_ref & sign, expr_ref & result) {
|
||||
mk_one(f->get_range(), sign, result);
|
||||
}
|
||||
|
||||
void fpa2bv_converter::mk_one(sort * s, expr_ref & sign, expr_ref & result) {
|
||||
SASSERT(is_float(s));
|
||||
unsigned sbits = m_util.get_sbits(s);
|
||||
unsigned ebits = m_util.get_ebits(s);
|
||||
mk_fp(sign,
|
||||
m_bv_util.mk_numeral(fu().fm().m_powers2.m1(ebits-1), ebits),
|
||||
m_bv_util.mk_numeral(0, sbits-1),
|
||||
|
@ -524,15 +550,18 @@ void fpa2bv_converter::mk_add(func_decl * f, unsigned num, expr * const * args,
|
|||
SASSERT(num == 3);
|
||||
SASSERT(is_app_of(args[0], m_util.get_family_id(), OP_FPA_INTERNAL_RM));
|
||||
|
||||
expr_ref bv_rm(m), x(m), y(m);
|
||||
bv_rm = to_app(args[0])->get_arg(0);
|
||||
expr_ref rm(m), x(m), y(m);
|
||||
rm = to_app(args[0])->get_arg(0);
|
||||
x = args[1];
|
||||
y = args[2];
|
||||
mk_add(f->get_range(), rm, x, y, result);
|
||||
}
|
||||
|
||||
void fpa2bv_converter::mk_add(sort * s, expr_ref & rm, expr_ref & x, expr_ref & y, expr_ref & result) {
|
||||
expr_ref nan(m), nzero(m), pzero(m);
|
||||
mk_nan(f, nan);
|
||||
mk_nzero(f, nzero);
|
||||
mk_pzero(f, pzero);
|
||||
mk_nan(s, nan);
|
||||
mk_nzero(s, nzero);
|
||||
mk_pzero(s, pzero);
|
||||
|
||||
expr_ref x_is_nan(m), x_is_zero(m), x_is_pos(m), x_is_neg(m), x_is_inf(m);
|
||||
expr_ref y_is_nan(m), y_is_zero(m), y_is_pos(m), y_is_neg(m), y_is_inf(m);
|
||||
|
@ -582,7 +611,7 @@ void fpa2bv_converter::mk_add(func_decl * f, unsigned num, expr * const * args,
|
|||
m_simp.mk_and(x_is_zero, y_is_zero, c4);
|
||||
m_simp.mk_and(x_is_neg, y_is_neg, signs_and);
|
||||
m_simp.mk_xor(x_is_neg, y_is_neg, signs_xor);
|
||||
mk_is_rm(bv_rm, BV_RM_TO_NEGATIVE, rm_is_to_neg);
|
||||
mk_is_rm(rm, BV_RM_TO_NEGATIVE, rm_is_to_neg);
|
||||
m_simp.mk_and(rm_is_to_neg, signs_xor, rm_and_xor);
|
||||
m_simp.mk_or(signs_and, rm_and_xor, neg_cond);
|
||||
mk_ite(neg_cond, nzero, pzero, v4);
|
||||
|
@ -595,9 +624,9 @@ void fpa2bv_converter::mk_add(func_decl * f, unsigned num, expr * const * args,
|
|||
c6 = y_is_zero;
|
||||
v6 = x;
|
||||
|
||||
//// Actual addition.
|
||||
unsigned ebits = m_util.get_ebits(f->get_range());
|
||||
unsigned sbits = m_util.get_sbits(f->get_range());
|
||||
// Actual addition.
|
||||
unsigned ebits = m_util.get_ebits(s);
|
||||
unsigned sbits = m_util.get_sbits(s);
|
||||
|
||||
expr_ref a_sgn(m), a_sig(m), a_exp(m), a_lz(m), b_sgn(m), b_sig(m), b_exp(m), b_lz(m);
|
||||
unpack(x, a_sgn, a_sig, a_exp, a_lz, false);
|
||||
|
@ -638,7 +667,7 @@ void fpa2bv_converter::mk_add(func_decl * f, unsigned num, expr * const * args,
|
|||
mk_ite(rm_is_to_neg, nzero, pzero, zero_case);
|
||||
|
||||
expr_ref rounded(m);
|
||||
round(f->get_range(), bv_rm, res_sgn, res_sig, res_exp, rounded);
|
||||
round(s, rm, res_sgn, res_sig, res_exp, rounded);
|
||||
|
||||
mk_ite(is_zero_sig, zero_case, rounded, v7);
|
||||
|
||||
|
@ -656,39 +685,55 @@ void fpa2bv_converter::mk_add(func_decl * f, unsigned num, expr * const * args,
|
|||
|
||||
void fpa2bv_converter::mk_sub(func_decl * f, unsigned num, expr * const * args, expr_ref & result) {
|
||||
SASSERT(num == 3);
|
||||
expr_ref rm(m), x(m), y(m);
|
||||
rm = args[0];
|
||||
x = args[1];
|
||||
y = args[2];
|
||||
mk_sub(f->get_range(), rm, x, y, result);
|
||||
}
|
||||
|
||||
void fpa2bv_converter::mk_sub(sort * s, expr_ref & rm, expr_ref & x, expr_ref & y, expr_ref & result) {
|
||||
expr_ref t(m);
|
||||
mk_neg(f, 1, &args[2], t);
|
||||
expr * nargs[3] = { args[0], args[1], t };
|
||||
mk_add(f, 3, nargs, result);
|
||||
mk_neg(s, y, t);
|
||||
mk_add(s, rm, x, t, result);
|
||||
}
|
||||
|
||||
void fpa2bv_converter::mk_neg(func_decl * f, unsigned num, expr * const * args, expr_ref & result) {
|
||||
SASSERT(num == 1);
|
||||
expr * sgn, * s, * e;
|
||||
split_fp(args[0], sgn, e, s);
|
||||
expr_ref x(m);
|
||||
x = args[0];
|
||||
mk_neg(f->get_range(), x, result);
|
||||
}
|
||||
|
||||
void fpa2bv_converter::mk_neg(sort * srt, expr_ref & x, expr_ref & result) {
|
||||
expr * sgn, *sig, *e;
|
||||
split_fp(x, sgn, e, sig);
|
||||
expr_ref c(m), nsgn(m);
|
||||
mk_is_nan(args[0], c);
|
||||
mk_is_nan(x, c);
|
||||
nsgn = m_bv_util.mk_bv_not(sgn);
|
||||
expr_ref r_sgn(m);
|
||||
m_simp.mk_ite(c, sgn, nsgn, r_sgn);
|
||||
mk_fp(r_sgn, e, s, result);
|
||||
mk_fp(r_sgn, e, sig, result);
|
||||
}
|
||||
|
||||
void fpa2bv_converter::mk_mul(func_decl * f, unsigned num, expr * const * args, expr_ref & result) {
|
||||
SASSERT(num == 3);
|
||||
SASSERT(is_app_of(args[0], m_util.get_family_id(), OP_FPA_INTERNAL_RM));
|
||||
|
||||
expr_ref bv_rm(m), x(m), y(m);
|
||||
bv_rm = to_app(args[0])->get_arg(0);
|
||||
expr_ref rm(m), x(m), y(m);
|
||||
rm = to_app(args[0])->get_arg(0);
|
||||
x = args[1];
|
||||
y = args[2];
|
||||
mk_mul(f->get_range(), rm, x, y, result);
|
||||
}
|
||||
|
||||
void fpa2bv_converter::mk_mul(sort * s, expr_ref & rm, expr_ref & x, expr_ref & y, expr_ref & result) {
|
||||
expr_ref nan(m), nzero(m), pzero(m), ninf(m), pinf(m);
|
||||
mk_nan(f, nan);
|
||||
mk_nzero(f, nzero);
|
||||
mk_pzero(f, pzero);
|
||||
mk_ninf(f, ninf);
|
||||
mk_pinf(f, pinf);
|
||||
mk_nan(s, nan);
|
||||
mk_nzero(s, nzero);
|
||||
mk_pzero(s, pzero);
|
||||
mk_ninf(s, ninf);
|
||||
mk_pinf(s, pinf);
|
||||
|
||||
expr_ref x_is_nan(m), x_is_zero(m), x_is_pos(m), x_is_inf(m);
|
||||
expr_ref y_is_nan(m), y_is_zero(m), y_is_pos(m), y_is_inf(m);
|
||||
|
@ -748,7 +793,7 @@ void fpa2bv_converter::mk_mul(func_decl * f, unsigned num, expr * const * args,
|
|||
mk_ite(sign_xor, nzero, pzero, v6);
|
||||
|
||||
// else comes the actual multiplication.
|
||||
unsigned sbits = m_util.get_sbits(f->get_range());
|
||||
unsigned sbits = m_util.get_sbits(s);
|
||||
|
||||
expr_ref a_sgn(m), a_sig(m), a_exp(m), a_lz(m), b_sgn(m), b_sig(m), b_exp(m), b_lz(m);
|
||||
unpack(x, a_sgn, a_sig, a_exp, a_lz, true);
|
||||
|
@ -806,7 +851,7 @@ void fpa2bv_converter::mk_mul(func_decl * f, unsigned num, expr * const * args,
|
|||
SASSERT(m_bv_util.get_bv_size(rbits) == 4);
|
||||
res_sig = m_bv_util.mk_concat(h_p, rbits);
|
||||
|
||||
round(f->get_range(), bv_rm, res_sgn, res_sig, res_exp, v7);
|
||||
round(s, rm, res_sgn, res_sig, res_exp, v7);
|
||||
|
||||
// And finally, we tie them together.
|
||||
mk_ite(c6, v6, v7, result);
|
||||
|
@ -824,18 +869,20 @@ void fpa2bv_converter::mk_mul(func_decl * f, unsigned num, expr * const * args,
|
|||
void fpa2bv_converter::mk_div(func_decl * f, unsigned num, expr * const * args, expr_ref & result) {
|
||||
SASSERT(num == 3);
|
||||
SASSERT(is_app_of(args[0], m_util.get_family_id(), OP_FPA_INTERNAL_RM));
|
||||
|
||||
expr_ref bv_rm(m), x(m), y(m);
|
||||
bv_rm = to_app(args[0])->get_arg(0);
|
||||
expr_ref rm(m), x(m), y(m);
|
||||
rm = to_app(args[0])->get_arg(0);
|
||||
x = args[1];
|
||||
y = args[2];
|
||||
mk_div(f->get_range(), rm, x, y, result);
|
||||
}
|
||||
|
||||
void fpa2bv_converter::mk_div(sort * s, expr_ref & rm, expr_ref & x, expr_ref & y, expr_ref & result) {
|
||||
expr_ref nan(m), nzero(m), pzero(m), ninf(m), pinf(m);
|
||||
mk_nan(f, nan);
|
||||
mk_nzero(f, nzero);
|
||||
mk_pzero(f, pzero);
|
||||
mk_ninf(f, ninf);
|
||||
mk_pinf(f, pinf);
|
||||
mk_nan(s, nan);
|
||||
mk_nzero(s, nzero);
|
||||
mk_pzero(s, pzero);
|
||||
mk_ninf(s, ninf);
|
||||
mk_pinf(s, pinf);
|
||||
|
||||
expr_ref x_is_nan(m), x_is_zero(m), x_is_pos(m), x_is_inf(m);
|
||||
expr_ref y_is_nan(m), y_is_zero(m), y_is_pos(m), y_is_inf(m);
|
||||
|
@ -899,8 +946,8 @@ void fpa2bv_converter::mk_div(func_decl * f, unsigned num, expr * const * args,
|
|||
mk_ite(signs_xor, nzero, pzero, v7);
|
||||
|
||||
// else comes the actual division.
|
||||
unsigned ebits = m_util.get_ebits(f->get_range());
|
||||
unsigned sbits = m_util.get_sbits(f->get_range());
|
||||
unsigned ebits = m_util.get_ebits(s);
|
||||
unsigned sbits = m_util.get_sbits(s);
|
||||
SASSERT(ebits <= sbits);
|
||||
|
||||
expr_ref a_sgn(m), a_sig(m), a_exp(m), a_lz(m), b_sgn(m), b_sig(m), b_exp(m), b_lz(m);
|
||||
|
@ -956,7 +1003,7 @@ void fpa2bv_converter::mk_div(func_decl * f, unsigned num, expr * const * args,
|
|||
m_simp.mk_ite(shift_cond, res_sig, res_sig_shifted, res_sig);
|
||||
m_simp.mk_ite(shift_cond, res_exp, res_exp_shifted, res_exp);
|
||||
|
||||
round(f->get_range(), bv_rm, res_sgn, res_sig, res_exp, v8);
|
||||
round(s, rm, res_sgn, res_sig, res_exp, v8);
|
||||
|
||||
// And finally, we tie them together.
|
||||
mk_ite(c7, v7, v8, result);
|
||||
|
@ -974,21 +1021,22 @@ void fpa2bv_converter::mk_div(func_decl * f, unsigned num, expr * const * args,
|
|||
|
||||
void fpa2bv_converter::mk_rem(func_decl * f, unsigned num, expr * const * args, expr_ref & result) {
|
||||
SASSERT(num == 2);
|
||||
|
||||
// Remainder is always exact, so there is no rounding mode.
|
||||
expr_ref x(m), y(m);
|
||||
x = args[0];
|
||||
y = args[1];
|
||||
mk_rem(f->get_range(), x, y, result);
|
||||
}
|
||||
|
||||
void fpa2bv_converter::mk_rem(sort * s, expr_ref & x, expr_ref & y, expr_ref & result) {
|
||||
TRACE("fpa2bv_rem", tout << "X = " << mk_ismt2_pp(x, m) << std::endl;
|
||||
tout << "Y = " << mk_ismt2_pp(y, m) << std::endl;);
|
||||
tout << "Y = " << mk_ismt2_pp(y, m) << std::endl;);
|
||||
|
||||
expr_ref nan(m), nzero(m), pzero(m), ninf(m), pinf(m);
|
||||
mk_nan(f, nan);
|
||||
mk_nzero(f, nzero);
|
||||
mk_pzero(f, pzero);
|
||||
mk_ninf(f, ninf);
|
||||
mk_pinf(f, pinf);
|
||||
mk_nan(s, nan);
|
||||
mk_nzero(s, nzero);
|
||||
mk_pzero(s, pzero);
|
||||
mk_ninf(s, ninf);
|
||||
mk_pinf(s, pinf);
|
||||
|
||||
expr_ref x_is_nan(m), x_is_zero(m), x_is_pos(m), x_is_inf(m);
|
||||
expr_ref y_is_nan(m), y_is_zero(m), y_is_pos(m), y_is_inf(m);
|
||||
|
@ -1033,71 +1081,32 @@ void fpa2bv_converter::mk_rem(func_decl * f, unsigned num, expr * const * args,
|
|||
c5 = x_is_zero;
|
||||
v5 = pzero;
|
||||
|
||||
// else the actual remainder.
|
||||
unsigned ebits = m_util.get_ebits(f->get_range());
|
||||
unsigned sbits = m_util.get_sbits(f->get_range());
|
||||
|
||||
expr_ref a_sgn(m), a_sig(m), a_exp(m), a_lz(m);
|
||||
expr_ref b_sgn(m), b_sig(m), b_exp(m), b_lz(m);
|
||||
unpack(x, a_sgn, a_sig, a_exp, a_lz, true);
|
||||
unpack(y, b_sgn, b_sig, b_exp, b_lz, true);
|
||||
|
||||
dbg_decouple("fpa2bv_rem_a_sgn", a_sgn);
|
||||
dbg_decouple("fpa2bv_rem_a_sig", a_sig);
|
||||
dbg_decouple("fpa2bv_rem_a_exp", a_exp);
|
||||
dbg_decouple("fpa2bv_rem_a_lz", a_lz);
|
||||
dbg_decouple("fpa2bv_rem_b_sgn", b_sgn);
|
||||
dbg_decouple("fpa2bv_rem_b_sig", b_sig);
|
||||
dbg_decouple("fpa2bv_rem_b_exp", b_exp);
|
||||
dbg_decouple("fpa2bv_rem_b_lz", b_lz);
|
||||
|
||||
BVSLT(a_exp, b_exp, c6);
|
||||
// exp(x) < exp(y) -> x
|
||||
expr * x_sgn, *x_sig, *x_exp;
|
||||
expr * y_sgn, *y_sig, *y_exp;
|
||||
split_fp(x, x_sgn, x_exp, x_sig);
|
||||
split_fp(y, y_sgn, y_exp, y_sig);
|
||||
BVSLT(x_exp, y_exp, c6);
|
||||
v6 = x;
|
||||
|
||||
// max. exponent difference is (2^ebits) - 3
|
||||
const mpz & two_to_ebits = fu().fm().m_powers2(ebits);
|
||||
mpz max_exp_diff;
|
||||
m_mpz_manager.sub(two_to_ebits, 3, max_exp_diff);
|
||||
SASSERT(m_mpz_manager.is_int64(max_exp_diff));
|
||||
SASSERT(m_mpz_manager.get_uint64(max_exp_diff) <= UINT_MAX);
|
||||
// else the actual remainder, r = x - y * n
|
||||
expr_ref rne(m), nr(m), n(m), yn(m), r(m);
|
||||
rne = m_bv_util.mk_numeral(BV_RM_TIES_TO_EVEN, 3);
|
||||
mk_div(s, rne, x, y, nr);
|
||||
mk_round_to_integral(s, rne, nr, n);
|
||||
mk_mul(s, rne, y, n, yn);
|
||||
mk_sub(s, rne, x, yn, r);
|
||||
|
||||
unsigned int max_exp_diff_ui = (unsigned int)m_mpz_manager.get_uint64(max_exp_diff);
|
||||
m_mpz_manager.del(max_exp_diff);
|
||||
expr_ref r_is_zero(m), x_sgn_ref(x_sgn, m), x_sgn_zero(m);
|
||||
mk_is_zero(r, r_is_zero);
|
||||
mk_zero(s, x_sgn_ref, x_sgn_zero);
|
||||
mk_ite(r_is_zero, x_sgn_zero, r, v7);
|
||||
|
||||
expr_ref a_exp_ext(m), b_exp_ext(m);
|
||||
a_exp_ext = m_bv_util.mk_sign_extend(2, a_exp);
|
||||
b_exp_ext = m_bv_util.mk_sign_extend(2, b_exp);
|
||||
|
||||
expr_ref a_lz_ext(m), b_lz_ext(m);
|
||||
a_lz_ext = m_bv_util.mk_zero_extend(2, a_lz);
|
||||
b_lz_ext = m_bv_util.mk_zero_extend(2, b_lz);
|
||||
|
||||
expr_ref exp_diff(m);
|
||||
exp_diff = m_bv_util.mk_bv_sub(
|
||||
m_bv_util.mk_bv_sub(a_exp_ext, a_lz_ext),
|
||||
m_bv_util.mk_bv_sub(b_exp_ext, b_lz_ext));
|
||||
dbg_decouple("fpa2bv_rem_exp_diff", exp_diff);
|
||||
|
||||
// CMW: This creates _huge_ bit-vectors, which is potentially sub-optimal,
|
||||
// but calculating this via rem = x - y * nearest(x/y) creates huge circuits.
|
||||
expr_ref huge_sig(m), shifted_sig(m), huge_rem(m);
|
||||
huge_sig = m_bv_util.mk_zero_extend(max_exp_diff_ui, a_sig);
|
||||
shifted_sig = m_bv_util.mk_bv_shl(huge_sig, m_bv_util.mk_zero_extend(max_exp_diff_ui + sbits - ebits - 2, exp_diff));
|
||||
huge_rem = m_bv_util.mk_bv_urem(shifted_sig, m_bv_util.mk_zero_extend(max_exp_diff_ui, b_sig));
|
||||
dbg_decouple("fpa2bv_rem_huge_rem", huge_rem);
|
||||
|
||||
expr_ref res_sgn(m), res_sig(m), res_exp(m);
|
||||
res_sgn = a_sgn;
|
||||
res_sig = m_bv_util.mk_concat(m_bv_util.mk_extract(sbits, 0, huge_rem),
|
||||
m_bv_util.mk_numeral(0, 3));
|
||||
|
||||
res_exp = m_bv_util.mk_bv_sub(b_exp_ext, b_lz_ext);
|
||||
|
||||
// CMW: Actual rounding is not necessary here, this is
|
||||
// just convenience to get rid of the extra bits.
|
||||
expr_ref bv_rm(m);
|
||||
bv_rm = m_bv_util.mk_numeral(BV_RM_TIES_TO_EVEN, 3);
|
||||
round(f->get_range(), bv_rm, res_sgn, res_sig, res_exp, v7);
|
||||
dbg_decouple("fpa2bv_rem_nr", nr);
|
||||
dbg_decouple("fpa2bv_rem_n", n);
|
||||
dbg_decouple("fpa2bv_rem_yn", yn);
|
||||
dbg_decouple("fpa2bv_rem_r", r);
|
||||
dbg_decouple("fpa2bv_rem_v7", v7);
|
||||
|
||||
// And finally, we tie them together.
|
||||
mk_ite(c6, v6, v7, result);
|
||||
|
@ -1302,8 +1311,8 @@ void fpa2bv_converter::mk_fma(func_decl * f, unsigned num, expr * const * args,
|
|||
SASSERT(is_app_of(args[0], m_util.get_family_id(), OP_FPA_INTERNAL_RM));
|
||||
|
||||
// fusedma means (x * y) + z
|
||||
expr_ref bv_rm(m), x(m), y(m), z(m);
|
||||
bv_rm = to_app(args[0])->get_arg(0);
|
||||
expr_ref rm(m), x(m), y(m), z(m);
|
||||
rm = to_app(args[0])->get_arg(0);
|
||||
x = args[1];
|
||||
y = args[2];
|
||||
z = args[3];
|
||||
|
@ -1335,7 +1344,7 @@ void fpa2bv_converter::mk_fma(func_decl * f, unsigned num, expr * const * args,
|
|||
mk_is_inf(z, z_is_inf);
|
||||
|
||||
expr_ref rm_is_to_neg(m);
|
||||
mk_is_rm(bv_rm, BV_RM_TO_NEGATIVE, rm_is_to_neg);
|
||||
mk_is_rm(rm, BV_RM_TO_NEGATIVE, rm_is_to_neg);
|
||||
|
||||
dbg_decouple("fpa2bv_fma_x_is_nan", x_is_nan);
|
||||
dbg_decouple("fpa2bv_fma_x_is_zero", x_is_zero);
|
||||
|
@ -1597,7 +1606,7 @@ void fpa2bv_converter::mk_fma(func_decl * f, unsigned num, expr * const * args,
|
|||
mk_ite(rm_is_to_neg, nzero, pzero, zero_case);
|
||||
|
||||
expr_ref rounded(m);
|
||||
round(f->get_range(), bv_rm, res_sgn, res_sig, res_exp, rounded);
|
||||
round(f->get_range(), rm, res_sgn, res_sig, res_exp, rounded);
|
||||
|
||||
mk_ite(is_zero_sig, zero_case, rounded, v8);
|
||||
|
||||
|
@ -1619,8 +1628,8 @@ void fpa2bv_converter::mk_sqrt(func_decl * f, unsigned num, expr * const * args,
|
|||
SASSERT(num == 2);
|
||||
SASSERT(is_app_of(args[0], m_util.get_family_id(), OP_FPA_INTERNAL_RM));
|
||||
|
||||
expr_ref bv_rm(m), x(m);
|
||||
bv_rm = to_app(args[0])->get_arg(0);
|
||||
expr_ref rm(m), x(m);
|
||||
rm = to_app(args[0])->get_arg(0);
|
||||
x = args[1];
|
||||
|
||||
expr_ref nan(m), nzero(m), pzero(m), ninf(m), pinf(m);
|
||||
|
@ -1752,7 +1761,7 @@ void fpa2bv_converter::mk_sqrt(func_decl * f, unsigned num, expr * const * args,
|
|||
SASSERT(m_bv_util.get_bv_size(res_sig) == sbits + 4);
|
||||
|
||||
expr_ref rounded(m);
|
||||
round(f->get_range(), bv_rm, res_sgn, res_sig, res_exp, rounded);
|
||||
round(f->get_range(), rm, res_sgn, res_sig, res_exp, rounded);
|
||||
v5 = rounded;
|
||||
|
||||
// And finally, we tie them together.
|
||||
|
@ -1768,21 +1777,24 @@ void fpa2bv_converter::mk_round_to_integral(func_decl * f, unsigned num, expr *
|
|||
SASSERT(num == 2);
|
||||
SASSERT(is_app_of(args[0], m_util.get_family_id(), OP_FPA_INTERNAL_RM));
|
||||
|
||||
expr_ref bv_rm(m), x(m);
|
||||
bv_rm = to_app(args[0])->get_arg(0);
|
||||
expr_ref rm(m), x(m);
|
||||
rm = to_app(args[0])->get_arg(0);
|
||||
x = args[1];
|
||||
mk_round_to_integral(f->get_range(), rm, x, result);
|
||||
}
|
||||
|
||||
void fpa2bv_converter::mk_round_to_integral(sort * s, expr_ref & rm, expr_ref & x, expr_ref & result) {
|
||||
expr_ref rm_is_rta(m), rm_is_rte(m), rm_is_rtp(m), rm_is_rtn(m), rm_is_rtz(m);
|
||||
mk_is_rm(bv_rm, BV_RM_TIES_TO_AWAY, rm_is_rta);
|
||||
mk_is_rm(bv_rm, BV_RM_TIES_TO_EVEN, rm_is_rte);
|
||||
mk_is_rm(bv_rm, BV_RM_TO_POSITIVE, rm_is_rtp);
|
||||
mk_is_rm(bv_rm, BV_RM_TO_NEGATIVE, rm_is_rtn);
|
||||
mk_is_rm(bv_rm, BV_RM_TO_ZERO, rm_is_rtz);
|
||||
mk_is_rm(rm, BV_RM_TIES_TO_AWAY, rm_is_rta);
|
||||
mk_is_rm(rm, BV_RM_TIES_TO_EVEN, rm_is_rte);
|
||||
mk_is_rm(rm, BV_RM_TO_POSITIVE, rm_is_rtp);
|
||||
mk_is_rm(rm, BV_RM_TO_NEGATIVE, rm_is_rtn);
|
||||
mk_is_rm(rm, BV_RM_TO_ZERO, rm_is_rtz);
|
||||
|
||||
expr_ref nan(m), nzero(m), pzero(m), ninf(m), pinf(m);
|
||||
mk_nan(f, nan);
|
||||
mk_nzero(f, nzero);
|
||||
mk_pzero(f, pzero);
|
||||
mk_nan(s, nan);
|
||||
mk_nzero(s, nzero);
|
||||
mk_pzero(s, pzero);
|
||||
|
||||
expr_ref x_is_zero(m), x_is_pos(m), x_is_neg(m);
|
||||
mk_is_zero(x, x_is_zero);
|
||||
|
@ -1812,14 +1824,16 @@ void fpa2bv_converter::mk_round_to_integral(func_decl * f, unsigned num, expr *
|
|||
one_1 = m_bv_util.mk_numeral(1, 1);
|
||||
zero_1 = m_bv_util.mk_numeral(0, 1);
|
||||
|
||||
unsigned ebits = m_util.get_ebits(f->get_range());
|
||||
unsigned sbits = m_util.get_sbits(f->get_range());
|
||||
unsigned ebits = m_util.get_ebits(s);
|
||||
unsigned sbits = m_util.get_sbits(s);
|
||||
|
||||
expr_ref a_sgn(m), a_sig(m), a_exp(m), a_lz(m);
|
||||
unpack(x, a_sgn, a_sig, a_exp, a_lz, true);
|
||||
|
||||
dbg_decouple("fpa2bv_r2i_unpacked_sig", a_sig);
|
||||
dbg_decouple("fpa2bv_r2i_unpacked_sgn", a_sgn);
|
||||
dbg_decouple("fpa2bv_r2i_unpacked_exp", a_exp);
|
||||
dbg_decouple("fpa2bv_r2i_unpacked_sig", a_sig);
|
||||
dbg_decouple("fpa2bv_r2i_unpacked_lz", a_lz);
|
||||
|
||||
expr_ref xzero(m), sgn_eq_1(m);
|
||||
sgn_eq_1 = m.mk_eq(a_sgn, one_1);
|
||||
|
@ -1833,8 +1847,8 @@ void fpa2bv_converter::mk_round_to_integral(func_decl * f, unsigned num, expr *
|
|||
c4 = exp_lt_zero;
|
||||
|
||||
expr_ref pone(m), none(m), xone(m), c421(m), c422(m), c423(m), t1(m), t2(m), tie(m), v42(m), exp_lt_m1(m);
|
||||
mk_one(f, zero_1, pone);
|
||||
mk_one(f, one_1, none);
|
||||
mk_one(s, zero_1, pone);
|
||||
mk_one(s, one_1, none);
|
||||
mk_ite(sgn_eq_1, none, pone, xone);
|
||||
|
||||
expr_ref pow_2_sbitsm1(m), m1(m);
|
||||
|
@ -1882,49 +1896,53 @@ void fpa2bv_converter::mk_round_to_integral(func_decl * f, unsigned num, expr *
|
|||
res_sgn = a_sgn;
|
||||
res_exp = a_exp;
|
||||
|
||||
expr_ref shift(m), rshift(m), div(m), rem(m);
|
||||
shift = m_bv_util.mk_bv_sub(m_bv_util.mk_numeral(sbits - 1, sbits + 1),
|
||||
m_bv_util.mk_sign_extend(sbits - ebits + 1, a_exp));
|
||||
rshift = m_bv_util.mk_bv_sub(m_bv_util.mk_numeral(sbits, sbits + 1), shift);
|
||||
div = m_bv_util.mk_bv_lshr(m_bv_util.mk_zero_extend(1, a_sig), shift);
|
||||
rem = m_bv_util.mk_bv_lshr(m_bv_util.mk_bv_shl(m_bv_util.mk_zero_extend(1, a_sig), rshift), rshift);
|
||||
SASSERT(m_bv_util.get_bv_size(a_sig) == sbits);
|
||||
SASSERT(m_bv_util.get_bv_size(a_exp) == ebits);
|
||||
|
||||
expr_ref zero_s(m);
|
||||
zero_s = m_bv_util.mk_numeral(0, sbits);
|
||||
|
||||
expr_ref shift(m), shifted_sig(m), div(m), rem(m);
|
||||
shift = m_bv_util.mk_bv_sub(m_bv_util.mk_numeral(sbits - 1, sbits),
|
||||
m_bv_util.mk_zero_extend(sbits-ebits, a_exp));
|
||||
shifted_sig = m_bv_util.mk_bv_lshr(m_bv_util.mk_concat(a_sig, zero_s),
|
||||
m_bv_util.mk_concat(zero_s, shift));
|
||||
div = m_bv_util.mk_extract(2*sbits-1, sbits, shifted_sig);
|
||||
rem = m_bv_util.mk_extract(sbits-1, 0, shifted_sig);
|
||||
|
||||
SASSERT(is_well_sorted(m, div));
|
||||
SASSERT(is_well_sorted(m, rem));
|
||||
SASSERT(m_bv_util.get_bv_size(div) == sbits + 1);
|
||||
SASSERT(m_bv_util.get_bv_size(rem) == sbits + 1);
|
||||
SASSERT(m_bv_util.get_bv_size(shift) == sbits);
|
||||
SASSERT(m_bv_util.get_bv_size(div) == sbits);
|
||||
SASSERT(m_bv_util.get_bv_size(rem) == sbits);
|
||||
|
||||
dbg_decouple("fpa2bv_r2i_shifted_sig", shifted_sig);
|
||||
dbg_decouple("fpa2bv_r2i_shift", shift);
|
||||
dbg_decouple("fpa2bv_r2i_rshift", rshift);
|
||||
dbg_decouple("fpa2bv_r2i_div", div);
|
||||
dbg_decouple("fpa2bv_r2i_rem", rem);
|
||||
|
||||
expr_ref div_p1(m);
|
||||
div_p1 = m_bv_util.mk_bv_add(div, m_bv_util.mk_numeral(1, sbits+1));
|
||||
div_p1 = m_bv_util.mk_bv_add(div, m_bv_util.mk_numeral(1, sbits));
|
||||
|
||||
expr_ref tie2(m), tie2_c(m), div_last(m), v51(m), rem_shl(m);
|
||||
rem_shl = m_bv_util.mk_concat(m_bv_util.mk_extract(sbits - 1, 0, rem), zero_1);
|
||||
m_simp.mk_eq(rem_shl,
|
||||
m_bv_util.mk_bv_shl(m_bv_util.mk_numeral(1, sbits+1), shift),
|
||||
tie2);
|
||||
expr_ref tie_pttrn(m), tie2(m), tie2_c(m), div_last(m), v51(m);
|
||||
tie_pttrn = m_bv_util.mk_concat(one_1, m_bv_util.mk_numeral(0, sbits-1));
|
||||
m_simp.mk_eq(rem, tie_pttrn, tie2);
|
||||
div_last = m_bv_util.mk_extract(0, 0, div);
|
||||
tie2_c = m.mk_or(m.mk_and(tie2,
|
||||
m.mk_or(m.mk_and(rm_is_rte, m.mk_eq(div_last, one_1)),
|
||||
m.mk_and(rm_is_rta, m.mk_eq(div_last, zero_1)))),
|
||||
m.mk_xor(m.mk_eq(a_sgn, one_1),
|
||||
m_bv_util.mk_sle(m_bv_util.mk_bv_shl(m_bv_util.mk_numeral(1, sbits + 1), shift),
|
||||
rem_shl)));
|
||||
tie2_c = m.mk_ite(tie2, m.mk_or(m.mk_and(rm_is_rte, m.mk_eq(div_last, one_1)),
|
||||
m.mk_and(rm_is_rta, m.mk_eq(div_last, zero_1))),
|
||||
m_bv_util.mk_ule(tie_pttrn, rem));
|
||||
m_simp.mk_ite(tie2_c, div_p1, div, v51);
|
||||
|
||||
dbg_decouple("fpa2bv_r2i_v51", v51);
|
||||
dbg_decouple("fpa2bv_r2i_tie2", tie2);
|
||||
dbg_decouple("fpa2bv_r2i_tie2_c", tie2_c);
|
||||
|
||||
SASSERT(is_well_sorted(m, tie2));
|
||||
SASSERT(is_well_sorted(m, tie2_c));
|
||||
SASSERT(is_well_sorted(m, v51));
|
||||
|
||||
expr_ref c521(m), v52(m), rem_eq_0(m), sgn_eq_zero(m);
|
||||
rem_eq_0 = m.mk_eq(rem, m_bv_util.mk_numeral(0, sbits + 1));
|
||||
rem_eq_0 = m.mk_eq(rem, m_bv_util.mk_numeral(0, sbits));
|
||||
sgn_eq_zero = m.mk_eq(res_sgn, zero_1);
|
||||
m_simp.mk_not(rem_eq_0, c521);
|
||||
m_simp.mk_and(c521, sgn_eq_zero, c521);
|
||||
|
@ -1945,14 +1963,14 @@ void fpa2bv_converter::mk_round_to_integral(func_decl * f, unsigned num, expr *
|
|||
m_simp.mk_ite(c53, v53, res_sig, res_sig);
|
||||
m_simp.mk_ite(c52, v52, res_sig, res_sig);
|
||||
m_simp.mk_ite(c51, v51, res_sig, res_sig);
|
||||
res_sig = m_bv_util.mk_concat(res_sig, m_bv_util.mk_numeral(0, 3)); // rounding bits are all 0.
|
||||
res_sig = m_bv_util.mk_zero_extend(1, m_bv_util.mk_concat(res_sig, m_bv_util.mk_numeral(0, 3))); // rounding bits are all 0.
|
||||
|
||||
SASSERT(m_bv_util.get_bv_size(res_exp) == ebits);
|
||||
SASSERT(m_bv_util.get_bv_size(shift) == sbits + 1);
|
||||
SASSERT(m_bv_util.get_bv_size(shift) == sbits);
|
||||
|
||||
expr_ref e_shift(m);
|
||||
e_shift = (ebits + 2 <= sbits + 1) ? m_bv_util.mk_extract(ebits + 1, 0, shift) :
|
||||
m_bv_util.mk_sign_extend((ebits + 2) - (sbits + 1), shift);
|
||||
m_bv_util.mk_sign_extend((ebits + 2) - (sbits), shift);
|
||||
SASSERT(m_bv_util.get_bv_size(e_shift) == ebits + 2);
|
||||
res_exp = m_bv_util.mk_bv_add(m_bv_util.mk_zero_extend(2, res_exp), e_shift);
|
||||
|
||||
|
@ -1961,7 +1979,7 @@ void fpa2bv_converter::mk_round_to_integral(func_decl * f, unsigned num, expr *
|
|||
SASSERT(m_bv_util.get_bv_size(res_exp) == ebits + 2);
|
||||
|
||||
// CMW: We use the rounder for normalization.
|
||||
round(f->get_range(), bv_rm, res_sgn, res_sig, res_exp, v6);
|
||||
round(s, rm, res_sgn, res_sig, res_exp, v6);
|
||||
|
||||
// And finally, we tie them together.
|
||||
mk_ite(c5, v5, v6, result);
|
||||
|
@ -2683,8 +2701,8 @@ void fpa2bv_converter::mk_to_fp_signed(func_decl * f, unsigned num, expr * const
|
|||
SASSERT(is_app_of(args[0], m_util.get_family_id(), OP_FPA_INTERNAL_RM));
|
||||
SASSERT(m_bv_util.is_bv(args[1]));
|
||||
|
||||
expr_ref bv_rm(m), x(m);
|
||||
bv_rm = to_app(args[0])->get_arg(0);
|
||||
expr_ref rm(m), x(m);
|
||||
rm = to_app(args[0])->get_arg(0);
|
||||
x = args[1];
|
||||
|
||||
dbg_decouple("fpa2bv_to_fp_signed_x", x);
|
||||
|
@ -2692,7 +2710,7 @@ void fpa2bv_converter::mk_to_fp_signed(func_decl * f, unsigned num, expr * const
|
|||
unsigned ebits = m_util.get_ebits(f->get_range());
|
||||
unsigned sbits = m_util.get_sbits(f->get_range());
|
||||
unsigned bv_sz = m_bv_util.get_bv_size(x);
|
||||
SASSERT(m_bv_util.get_bv_size(bv_rm) == 3);
|
||||
SASSERT(m_bv_util.get_bv_size(rm) == 3);
|
||||
|
||||
expr_ref bv0_1(m), bv1_1(m), bv0_sz(m), bv1_sz(m);
|
||||
bv0_1 = m_bv_util.mk_numeral(0, 1);
|
||||
|
@ -2802,7 +2820,7 @@ void fpa2bv_converter::mk_to_fp_signed(func_decl * f, unsigned num, expr * const
|
|||
SASSERT(m_bv_util.get_bv_size(exp) == ebits + 2);
|
||||
|
||||
expr_ref v2(m);
|
||||
round(f->get_range(), bv_rm, sgn, sig, exp, v2);
|
||||
round(f->get_range(), rm, sgn, sig, exp, v2);
|
||||
|
||||
mk_ite(c1, v1, v2, result);
|
||||
}
|
||||
|
@ -2825,8 +2843,8 @@ void fpa2bv_converter::mk_to_fp_unsigned(func_decl * f, unsigned num, expr * con
|
|||
SASSERT(is_app_of(args[0], m_util.get_family_id(), OP_FPA_INTERNAL_RM));
|
||||
SASSERT(m_bv_util.is_bv(args[1]));
|
||||
|
||||
expr_ref bv_rm(m), x(m);
|
||||
bv_rm = to_app(args[0])->get_arg(0);
|
||||
expr_ref rm(m), x(m);
|
||||
rm = to_app(args[0])->get_arg(0);
|
||||
x = args[1];
|
||||
|
||||
dbg_decouple("fpa2bv_to_fp_unsigned_x", x);
|
||||
|
@ -2834,7 +2852,7 @@ void fpa2bv_converter::mk_to_fp_unsigned(func_decl * f, unsigned num, expr * con
|
|||
unsigned ebits = m_util.get_ebits(f->get_range());
|
||||
unsigned sbits = m_util.get_sbits(f->get_range());
|
||||
unsigned bv_sz = m_bv_util.get_bv_size(x);
|
||||
SASSERT(m_bv_util.get_bv_size(bv_rm) == 3);
|
||||
SASSERT(m_bv_util.get_bv_size(rm) == 3);
|
||||
|
||||
expr_ref bv0_1(m), bv1_1(m), bv0_sz(m), bv1_sz(m);
|
||||
bv0_1 = m_bv_util.mk_numeral(0, 1);
|
||||
|
@ -2935,7 +2953,7 @@ void fpa2bv_converter::mk_to_fp_unsigned(func_decl * f, unsigned num, expr * con
|
|||
SASSERT(m_bv_util.get_bv_size(exp) == ebits + 2);
|
||||
|
||||
expr_ref v2(m);
|
||||
round(f->get_range(), bv_rm, sgn, sig, exp, v2);
|
||||
round(f->get_range(), rm, sgn, sig, exp, v2);
|
||||
|
||||
mk_ite(c1, v1, v2, result);
|
||||
}
|
||||
|
@ -2977,7 +2995,7 @@ void fpa2bv_converter::mk_to_bv(func_decl * f, unsigned num, expr * const * args
|
|||
SASSERT(is_app_of(args[0], m_util.get_family_id(), OP_FPA_INTERNAL_RM));
|
||||
SASSERT(m_util.is_float(args[1]));
|
||||
|
||||
expr * bv_rm = to_app(args[0])->get_arg(0);
|
||||
expr * rm = to_app(args[0])->get_arg(0);
|
||||
expr * x = args[1];
|
||||
sort * xs = m.get_sort(x);
|
||||
sort * bv_srt = f->get_range();
|
||||
|
@ -3080,7 +3098,7 @@ void fpa2bv_converter::mk_to_bv(func_decl * f, unsigned num, expr * const * args
|
|||
dbg_decouple("fpa2bv_to_bv_sticky", sticky);
|
||||
|
||||
expr_ref rounding_decision(m);
|
||||
rounding_decision = mk_rounding_decision(bv_rm, sgn, last, round, sticky);
|
||||
rounding_decision = mk_rounding_decision(rm, sgn, last, round, sticky);
|
||||
SASSERT(m_bv_util.get_bv_size(rounding_decision) == 1);
|
||||
dbg_decouple("fpa2bv_to_bv_rounding_decision", rounding_decision);
|
||||
|
||||
|
@ -3382,7 +3400,7 @@ void fpa2bv_converter::mk_is_normal(expr * e, expr_ref & result) {
|
|||
m_simp.mk_not(or_ex, result);
|
||||
}
|
||||
|
||||
void fpa2bv_converter::mk_is_rm(expr * bv_rm, BV_RM_VAL rm, expr_ref & result) {
|
||||
void fpa2bv_converter::mk_is_rm(expr * rme, BV_RM_VAL rm, expr_ref & result) {
|
||||
expr_ref rm_num(m);
|
||||
rm_num = m_bv_util.mk_numeral(rm, 3);
|
||||
|
||||
|
@ -3393,7 +3411,7 @@ void fpa2bv_converter::mk_is_rm(expr * bv_rm, BV_RM_VAL rm, expr_ref & result) {
|
|||
case BV_RM_TO_NEGATIVE:
|
||||
case BV_RM_TO_POSITIVE:
|
||||
case BV_RM_TO_ZERO:
|
||||
return m_simp.mk_eq(bv_rm, rm_num, result);
|
||||
return m_simp.mk_eq(rme, rm_num, result);
|
||||
default:
|
||||
UNREACHABLE();
|
||||
}
|
||||
|
@ -3598,15 +3616,34 @@ void fpa2bv_converter::dbg_decouple(const char * prefix, expr_ref & e) {
|
|||
#ifdef Z3DEBUG
|
||||
return;
|
||||
// CMW: This works only for quantifier-free formulas.
|
||||
expr_ref new_e(m);
|
||||
new_e = m.mk_fresh_const(prefix, m.get_sort(e));
|
||||
m_extra_assertions.push_back(m.mk_eq(new_e, e));
|
||||
e = new_e;
|
||||
if (is_app_of(e, m_plugin->get_family_id(), OP_FPA_FP)) {
|
||||
expr_ref new_bv(m);
|
||||
expr *e_sgn, *e_sig, *e_exp;
|
||||
split_fp(e, e_sgn, e_exp, e_sig);
|
||||
unsigned ebits = m_bv_util.get_bv_size(e_exp);
|
||||
unsigned sbits = m_bv_util.get_bv_size(e_sig) + 1;
|
||||
unsigned bv_sz = ebits + sbits;
|
||||
new_bv = m.mk_fresh_const(prefix, m_bv_util.mk_sort(bv_sz));
|
||||
expr_ref bv_sgn(m), bv_exp(m), bv_sig(m);
|
||||
bv_sgn = m_bv_util.mk_extract(bv_sz-1, bv_sz-1, new_bv);
|
||||
bv_exp = m_bv_util.mk_extract(bv_sz-2, bv_sz-ebits-1, new_bv);
|
||||
bv_sig = m_bv_util.mk_extract(sbits-2, 0, new_bv);
|
||||
m_extra_assertions.push_back(m.mk_eq(e_sgn, bv_sgn));
|
||||
m_extra_assertions.push_back(m.mk_eq(e_exp, bv_exp));
|
||||
m_extra_assertions.push_back(m.mk_eq(e_sig, bv_sig));
|
||||
e = m_util.mk_fp(bv_sgn, bv_exp, bv_sig);
|
||||
}
|
||||
else {
|
||||
expr_ref new_e(m);
|
||||
new_e = m.mk_fresh_const(prefix, m.get_sort(e));
|
||||
m_extra_assertions.push_back(m.mk_eq(new_e, e));
|
||||
e = new_e;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
expr_ref fpa2bv_converter::mk_rounding_decision(expr * bv_rm, expr * sgn, expr * last, expr * round, expr * sticky) {
|
||||
expr_ref rmr(bv_rm, m);
|
||||
expr_ref fpa2bv_converter::mk_rounding_decision(expr * rm, expr * sgn, expr * last, expr * round, expr * sticky) {
|
||||
expr_ref rmr(rm, m);
|
||||
expr_ref sgnr(sgn, m);
|
||||
expr_ref lastr(last, m);
|
||||
expr_ref roundr(round, m);
|
||||
|
@ -3645,10 +3682,10 @@ expr_ref fpa2bv_converter::mk_rounding_decision(expr * bv_rm, expr * sgn, expr *
|
|||
expr_ref res(m), inc_c2(m), inc_c3(m), inc_c4(m);
|
||||
expr_ref rm_is_to_neg(m), rm_is_to_pos(m), rm_is_away(m), rm_is_even(m), nil_1(m);
|
||||
nil_1 = m_bv_util.mk_numeral(0, 1);
|
||||
mk_is_rm(bv_rm, BV_RM_TO_NEGATIVE, rm_is_to_neg);
|
||||
mk_is_rm(bv_rm, BV_RM_TO_POSITIVE, rm_is_to_pos);
|
||||
mk_is_rm(bv_rm, BV_RM_TIES_TO_AWAY, rm_is_away);
|
||||
mk_is_rm(bv_rm, BV_RM_TIES_TO_EVEN, rm_is_even);
|
||||
mk_is_rm(rm, BV_RM_TO_NEGATIVE, rm_is_to_neg);
|
||||
mk_is_rm(rm, BV_RM_TO_POSITIVE, rm_is_to_pos);
|
||||
mk_is_rm(rm, BV_RM_TIES_TO_AWAY, rm_is_away);
|
||||
mk_is_rm(rm, BV_RM_TIES_TO_EVEN, rm_is_even);
|
||||
m_simp.mk_ite(rm_is_to_neg, inc_neg, nil_1, inc_c4);
|
||||
m_simp.mk_ite(rm_is_to_pos, inc_pos, inc_c4, inc_c3);
|
||||
m_simp.mk_ite(rm_is_away, inc_taway, inc_c3, inc_c2);
|
||||
|
@ -3658,16 +3695,16 @@ expr_ref fpa2bv_converter::mk_rounding_decision(expr * bv_rm, expr * sgn, expr *
|
|||
return res;
|
||||
}
|
||||
|
||||
void fpa2bv_converter::round(sort * s, expr_ref & bv_rm, expr_ref & sgn, expr_ref & sig, expr_ref & exp, expr_ref & result) {
|
||||
void fpa2bv_converter::round(sort * s, expr_ref & rm, expr_ref & sgn, expr_ref & sig, expr_ref & exp, expr_ref & result) {
|
||||
unsigned ebits = m_util.get_ebits(s);
|
||||
unsigned sbits = m_util.get_sbits(s);
|
||||
|
||||
dbg_decouple("fpa2bv_rnd_rm", bv_rm);
|
||||
dbg_decouple("fpa2bv_rnd_rm", rm);
|
||||
dbg_decouple("fpa2bv_rnd_sgn", sgn);
|
||||
dbg_decouple("fpa2bv_rnd_sig", sig);
|
||||
dbg_decouple("fpa2bv_rnd_exp", exp);
|
||||
|
||||
SASSERT(is_well_sorted(m, bv_rm));
|
||||
SASSERT(is_well_sorted(m, rm));
|
||||
SASSERT(is_well_sorted(m, sgn));
|
||||
SASSERT(is_well_sorted(m, sig));
|
||||
SASSERT(is_well_sorted(m, exp));
|
||||
|
@ -3683,7 +3720,7 @@ void fpa2bv_converter::round(sort * s, expr_ref & bv_rm, expr_ref & sgn, expr_re
|
|||
// i.e., it has 2 + (sbits-1) + 3 = sbits + 4 bits, where the first one is in sgn.
|
||||
// Furthermore, note that sig is an unsigned bit-vector, while exp is signed.
|
||||
|
||||
SASSERT(m_bv_util.is_bv(bv_rm) && m_bv_util.get_bv_size(bv_rm) == 3);
|
||||
SASSERT(m_bv_util.is_bv(rm) && m_bv_util.get_bv_size(rm) == 3);
|
||||
SASSERT(m_bv_util.is_bv(sgn) && m_bv_util.get_bv_size(sgn) == 1);
|
||||
SASSERT(m_bv_util.is_bv(sig) && m_bv_util.get_bv_size(sig) >= 5);
|
||||
SASSERT(m_bv_util.is_bv(exp) && m_bv_util.get_bv_size(exp) >= 4);
|
||||
|
@ -3833,7 +3870,7 @@ void fpa2bv_converter::round(sort * s, expr_ref & bv_rm, expr_ref & sgn, expr_re
|
|||
sig = m_bv_util.mk_extract(sbits+1, 2, sig);
|
||||
|
||||
expr_ref inc(m);
|
||||
inc = mk_rounding_decision(bv_rm, sgn, last, round, sticky);
|
||||
inc = mk_rounding_decision(rm, sgn, last, round, sticky);
|
||||
|
||||
SASSERT(m_bv_util.get_bv_size(inc) == 1 && is_well_sorted(m, inc));
|
||||
dbg_decouple("fpa2bv_rnd_inc", inc);
|
||||
|
@ -3906,9 +3943,9 @@ void fpa2bv_converter::round(sort * s, expr_ref & bv_rm, expr_ref & sgn, expr_re
|
|||
nil_1 = m_bv_util.mk_numeral(0, 1);
|
||||
|
||||
expr_ref rm_is_to_zero(m), rm_is_to_neg(m), rm_is_to_pos(m), rm_zero_or_neg(m), rm_zero_or_pos(m);
|
||||
mk_is_rm(bv_rm, BV_RM_TO_ZERO, rm_is_to_zero);
|
||||
mk_is_rm(bv_rm, BV_RM_TO_NEGATIVE, rm_is_to_neg);
|
||||
mk_is_rm(bv_rm, BV_RM_TO_POSITIVE, rm_is_to_pos);
|
||||
mk_is_rm(rm, BV_RM_TO_ZERO, rm_is_to_zero);
|
||||
mk_is_rm(rm, BV_RM_TO_NEGATIVE, rm_is_to_neg);
|
||||
mk_is_rm(rm, BV_RM_TO_POSITIVE, rm_is_to_pos);
|
||||
m_simp.mk_or(rm_is_to_zero, rm_is_to_neg, rm_zero_or_neg);
|
||||
m_simp.mk_or(rm_is_to_zero, rm_is_to_pos, rm_zero_or_pos);
|
||||
dbg_decouple("fpa2bv_rnd_rm_is_to_zero", rm_is_to_zero);
|
||||
|
|
|
@ -145,7 +145,7 @@ public:
|
|||
expr_ref_vector m_extra_assertions;
|
||||
|
||||
protected:
|
||||
void mk_one(func_decl *f, expr_ref sign, expr_ref & result);
|
||||
void mk_one(func_decl *f, expr_ref & sign, expr_ref & result);
|
||||
|
||||
void mk_is_nan(expr * e, expr_ref & result);
|
||||
void mk_is_inf(expr * e, expr_ref & result);
|
||||
|
@ -184,6 +184,23 @@ protected:
|
|||
void mk_to_bv(func_decl * f, unsigned num, expr * const * args, bool is_signed, expr_ref & result);
|
||||
|
||||
void mk_uninterpreted_output(sort * rng, func_decl * fbv, expr_ref_buffer & new_args, expr_ref & result);
|
||||
|
||||
private:
|
||||
void mk_nan(sort * s, expr_ref & result);
|
||||
void mk_nzero(sort * s, expr_ref & result);
|
||||
void mk_pzero(sort * s, expr_ref & result);
|
||||
void mk_zero(sort * s, expr_ref & sgn, expr_ref & result);
|
||||
void mk_ninf(sort * s, expr_ref & result);
|
||||
void mk_pinf(sort * s, expr_ref & result);
|
||||
|
||||
void mk_one(sort * s, expr_ref & sign, expr_ref & result);
|
||||
void mk_neg(sort * s, expr_ref & x, expr_ref & result);
|
||||
void mk_add(sort * s, expr_ref & bv_rm, expr_ref & x, expr_ref & y, expr_ref & result);
|
||||
void mk_sub(sort * s, expr_ref & bv_rm, expr_ref & x, expr_ref & y, expr_ref & result);
|
||||
void mk_mul(sort * s, expr_ref & bv_rm, expr_ref & x, expr_ref & y, expr_ref & result);
|
||||
void mk_div(sort * s, expr_ref & bv_rm, expr_ref & x, expr_ref & y, expr_ref & result);
|
||||
void mk_rem(sort * s, expr_ref & x, expr_ref & y, expr_ref & result);
|
||||
void mk_round_to_integral(sort * s, expr_ref & rm, expr_ref & x, expr_ref & result);
|
||||
};
|
||||
|
||||
#endif
|
||||
|
|
|
@ -38,13 +38,13 @@ Revision History:
|
|||
|
||||
// Note:
|
||||
// Which FPU will be used is determined by compiler settings. On x64 it's always SSE2,
|
||||
// on x86 we have to chose SSE2 by enabling /arch:SSE2 (otherwise the x87 FPU will be used).
|
||||
// on x86 we have to chose SSE2 by enabling /arch:SSE2 (otherwise the x87 FPU will be used).
|
||||
// Christoph has decided that we don't want to use the x87; this makes everything a lot easier.
|
||||
|
||||
|
||||
// For SSE2, it is best to use compiler intrinsics because this makes it completely
|
||||
// clear to the compiler what instructions should be used. E.g., for sqrt(), the Windows compiler selects
|
||||
// the x87 FPU, even when /arch:SSE2 is on.
|
||||
// the x87 FPU, even when /arch:SSE2 is on.
|
||||
// Luckily, these are kind of standardized, at least for Windows/Linux/OSX.
|
||||
#ifdef __clang__
|
||||
#undef USE_INTRINSICS
|
||||
|
@ -56,19 +56,19 @@ Revision History:
|
|||
|
||||
hwf_manager::hwf_manager() :
|
||||
m_mpz_manager(m_mpq_manager)
|
||||
{
|
||||
{
|
||||
#ifdef _WINDOWS
|
||||
#if defined(_AMD64_) || defined(_M_IA64)
|
||||
// Precision control is not supported on x64.
|
||||
// Precision control is not supported on x64.
|
||||
// See: http://msdn.microsoft.com/en-us/library/e9b52ceh(VS.110).aspx
|
||||
// CMW: I think this is okay though, the compiler will chose the right instructions
|
||||
// CMW: I think this is okay though, the compiler will chose the right instructions
|
||||
// (the x64/SSE2 FPU has separate instructions for different precisions).
|
||||
#else
|
||||
// Setting the precision should only be required on the x87, but it won't hurt to do it anyways.
|
||||
// _PC_53 means double precision (53 significand bits). For extended precision use _PC_64.
|
||||
|
||||
#ifndef USE_INTRINSICS
|
||||
__control87_2(_PC_53, _MCW_PC, &x86_state, &sse2_state);
|
||||
__control87_2(_PC_53, _MCW_PC, &x86_state, &sse2_state);
|
||||
#endif
|
||||
#endif
|
||||
#else
|
||||
|
@ -78,7 +78,7 @@ hwf_manager::hwf_manager() :
|
|||
// We only set the precision of the FPU here in the constructor. At the moment, there are no
|
||||
// other parts of the code that could overwrite this, and Windows takes care of context switches.
|
||||
|
||||
// CMW: I'm not sure what happens on CPUs with hyper-threading (since the FPU is shared).
|
||||
// CMW: I'm not sure what happens on CPUs with hyper-threading (since the FPU is shared).
|
||||
// I have yet to discover whether Linux and OSX save the FPU state when switching context.
|
||||
// As long as we stick to using the SSE2 FPU though, there shouldn't be any problems with respect
|
||||
// to the precision (not sure about the rounding modes though).
|
||||
|
@ -104,7 +104,7 @@ void hwf_manager::set(hwf & o, double value) {
|
|||
o.value = value;
|
||||
}
|
||||
|
||||
void hwf_manager::set(hwf & o, float value) {
|
||||
void hwf_manager::set(hwf & o, float value) {
|
||||
o.value = (double)value;
|
||||
}
|
||||
|
||||
|
@ -113,7 +113,7 @@ void hwf_manager::set(hwf & o, mpf_rounding_mode rm, mpq const & value) {
|
|||
o.value = m_mpq_manager.get_double(value);
|
||||
}
|
||||
|
||||
void hwf_manager::set(hwf & o, mpf_rounding_mode rm, char const * value) {
|
||||
void hwf_manager::set(hwf & o, mpf_rounding_mode rm, char const * value) {
|
||||
// We expect [i].[f]P[e], where P means that the exponent is interpreted as 2^e instead of 10^e.
|
||||
|
||||
std::string v(value);
|
||||
|
@ -123,17 +123,17 @@ void hwf_manager::set(hwf & o, mpf_rounding_mode rm, char const * value) {
|
|||
std::string f, e;
|
||||
|
||||
f = (e_pos != std::string::npos) ? v.substr(0, e_pos) : v;
|
||||
e = (e_pos != std::string::npos) ? v.substr(e_pos+1) : "0";
|
||||
e = (e_pos != std::string::npos) ? v.substr(e_pos+1) : "0";
|
||||
|
||||
TRACE("mpf_dbg", tout << " f = " << f << " e = " << e << std::endl;);
|
||||
TRACE("mpf_dbg", tout << " f = " << f << " e = " << e << std::endl;);
|
||||
|
||||
mpq q;
|
||||
mpq q;
|
||||
m_mpq_manager.set(q, f.c_str());
|
||||
|
||||
mpz ex;
|
||||
m_mpz_manager.set(ex, e.c_str());
|
||||
|
||||
set(o, rm, q, ex);
|
||||
set(o, rm, q, ex);
|
||||
|
||||
TRACE("mpf_dbg", tout << "set: res = " << to_string(o) << std::endl;);
|
||||
}
|
||||
|
@ -142,7 +142,7 @@ void hwf_manager::set(hwf & o, mpf_rounding_mode rm, mpq const & significand, mp
|
|||
// Assumption: this represents significand * 2^exponent.
|
||||
set_rounding_mode(rm);
|
||||
|
||||
mpq sig;
|
||||
mpq sig;
|
||||
m_mpq_manager.set(sig, significand);
|
||||
int64 exp = m_mpz_manager.get_int64(exponent);
|
||||
|
||||
|
@ -150,7 +150,7 @@ void hwf_manager::set(hwf & o, mpf_rounding_mode rm, mpq const & significand, mp
|
|||
o.value = 0.0;
|
||||
else
|
||||
{
|
||||
while (m_mpq_manager.lt(sig, 1))
|
||||
while (m_mpq_manager.lt(sig, 1))
|
||||
{
|
||||
m_mpq_manager.mul(sig, 2, sig);
|
||||
exp--;
|
||||
|
@ -176,7 +176,7 @@ void hwf_manager::set(hwf & o, hwf const & x) {
|
|||
o.value = x.value;
|
||||
}
|
||||
|
||||
void hwf_manager::abs(hwf & o) {
|
||||
void hwf_manager::abs(hwf & o) {
|
||||
o.value = fabs(o.value);
|
||||
}
|
||||
|
||||
|
@ -244,14 +244,14 @@ void hwf_manager::mul(mpf_rounding_mode rm, hwf const & x, hwf const & y, hwf &
|
|||
// On the x86 FPU (x87), we use custom assembly routines because
|
||||
// the code generated for x*y and x/y suffers from the double
|
||||
// rounding on underflow problem. The scaling trick is described
|
||||
// in Roger Golliver: `Efficiently producing default orthogonal IEEE
|
||||
// in Roger Golliver: `Efficiently producing default orthogonal IEEE
|
||||
// double results using extended IEEE hardware', see
|
||||
// http://www.open-std.org/JTC1/SC22/JSG/docs/m3/docs/jsgn326.pdf
|
||||
// CMW: Tthis is not really needed if we use only the SSE2 FPU,
|
||||
// it shouldn't hurt the performance too much though.
|
||||
|
||||
static const int const1 = -DBL_SCALE;
|
||||
static const int const2 = +DBL_SCALE;
|
||||
static const int const2 = +DBL_SCALE;
|
||||
double xv = x.value;
|
||||
double yv = y.value;
|
||||
double & ov = o.value;
|
||||
|
@ -266,14 +266,14 @@ void hwf_manager::mul(mpf_rounding_mode rm, hwf const & x, hwf const & y, hwf &
|
|||
fxch st(1);
|
||||
fscale;
|
||||
fstp ov;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
void hwf_manager::div(mpf_rounding_mode rm, hwf const & x, hwf const & y, hwf & o) {
|
||||
set_rounding_mode(rm);
|
||||
#ifdef USE_INTRINSICS
|
||||
_mm_store_sd(&o.value, _mm_div_sd(_mm_set_sd(x.value), _mm_set_sd(y.value)));
|
||||
_mm_store_sd(&o.value, _mm_div_sd(_mm_set_sd(x.value), _mm_set_sd(y.value)));
|
||||
#else
|
||||
o.value = x.value / y.value;
|
||||
#endif
|
||||
|
@ -306,18 +306,18 @@ void hwf_manager::div(mpf_rounding_mode rm, hwf const & x, hwf const & y, hwf &
|
|||
#endif
|
||||
|
||||
void hwf_manager::fma(mpf_rounding_mode rm, hwf const & x, hwf const & y, hwf const &z, hwf & o) {
|
||||
// CMW: fused_mul_add is not available on most CPUs. As of 2012, only Itanium,
|
||||
// CMW: fused_mul_add is not available on most CPUs. As of 2012, only Itanium,
|
||||
// Intel Sandybridge and AMD Bulldozers support that (via AVX).
|
||||
|
||||
set_rounding_mode(rm);
|
||||
|
||||
#ifdef _M_IA64
|
||||
// IA64 (Itanium) will do it, if contractions are on.
|
||||
// IA64 (Itanium) will do it, if contractions are on.
|
||||
o.value = x.value * y.value + z.value;
|
||||
#else
|
||||
#if defined(_WINDOWS)
|
||||
#if defined(_WINDOWS)
|
||||
#if _MSC_VER >= 1800
|
||||
o.value = ::fma(x.value, y.value, z.value);
|
||||
o.value = ::fma(x.value, y.value, z.value);
|
||||
#else // Windows, older than VS 2013
|
||||
#ifdef USE_INTRINSICS
|
||||
_mm_store_sd(&o.value, _mm_fmadd_sd(_mm_set_sd(x.value), _mm_set_sd(y.value), _mm_set_sd(z.value)));
|
||||
|
@ -351,7 +351,7 @@ void hwf_manager::round_to_integral(mpf_rounding_mode rm, hwf const & x, hwf & o
|
|||
// CMW: modf is not the right function here.
|
||||
// modf(x.value, &o.value);
|
||||
|
||||
// According to the Intel Architecture manual, the x87-instrunction FRNDINT is the
|
||||
// According to the Intel Architecture manual, the x87-instrunction FRNDINT is the
|
||||
// same in 32-bit and 64-bit mode. The _mm_round_* intrinsics are SSE4 extensions.
|
||||
#ifdef _WINDOWS
|
||||
#ifdef USE_INTRINSICS
|
||||
|
@ -383,17 +383,10 @@ void hwf_manager::round_to_integral(mpf_rounding_mode rm, hwf const & x, hwf & o
|
|||
}
|
||||
|
||||
void hwf_manager::rem(hwf const & x, hwf const & y, hwf & o) {
|
||||
// The built-in fmod() works, except for the special numbers.
|
||||
o.value = remainder(x.value, y.value);
|
||||
|
||||
if (is_inf(x) && is_inf(y))
|
||||
o.value = x.value/y.value; // NaN
|
||||
else if (is_inf(y))
|
||||
o.value = x.value;
|
||||
else
|
||||
o.value = fmod(x.value, y.value);
|
||||
|
||||
// Here is an x87 alternative if the above makes problems; this may also be faster.
|
||||
#if 0
|
||||
// Here is an x87 alternative if the above makes problems; this may also be faster.
|
||||
double xv = x.value;
|
||||
double yv = y.value;
|
||||
double & ov = o.value;
|
||||
|
@ -423,7 +416,7 @@ void hwf_manager::maximum(hwf const & x, hwf const & y, hwf & o) {
|
|||
o.value = x.value;
|
||||
else if (lt(x, y))
|
||||
o.value = y.value;
|
||||
else
|
||||
else
|
||||
o.value = x.value;
|
||||
#endif
|
||||
}
|
||||
|
@ -439,12 +432,12 @@ void hwf_manager::minimum(hwf const & x, hwf const & y, hwf & o) {
|
|||
o.value = x.value;
|
||||
else if (lt(x, y))
|
||||
o.value = x.value;
|
||||
else
|
||||
else
|
||||
o.value = y.value;
|
||||
#endif
|
||||
}
|
||||
|
||||
std::string hwf_manager::to_string(hwf const & x) {
|
||||
std::string hwf_manager::to_string(hwf const & x) {
|
||||
std::stringstream ss("");
|
||||
ss << std::scientific << x.value;
|
||||
return ss.str();
|
||||
|
@ -488,9 +481,9 @@ void hwf_manager::to_rational(hwf const & x, unsynch_mpq_manager & qm, mpq & o)
|
|||
int e = exp(x);
|
||||
if (e >= 0)
|
||||
qm.mul2k(n, (unsigned)e);
|
||||
else
|
||||
else
|
||||
qm.mul2k(d, (unsigned)-e);
|
||||
qm.set(o, n, d);
|
||||
qm.set(o, n, d);
|
||||
}
|
||||
|
||||
bool hwf_manager::is_zero(hwf const & x) {
|
||||
|
@ -559,13 +552,13 @@ bool hwf_manager::is_denormal(hwf const & x) {
|
|||
(t & 0x000FFFFFFFFFFFFFull) != 0x0);
|
||||
}
|
||||
|
||||
bool hwf_manager::is_regular(hwf const & x) {
|
||||
bool hwf_manager::is_regular(hwf const & x) {
|
||||
// Everything that doesn't have the top-exponent is considered regular.
|
||||
// Note that +-0.0 and denormal numbers have exponent==0; these are regular.
|
||||
// All normal numbers are also regular. What remains is +-Inf and NaN, they are
|
||||
// All normal numbers are also regular. What remains is +-Inf and NaN, they are
|
||||
// not regular and they are the only numbers that have exponent 7FF.
|
||||
uint64 e = RAW(x.value) & 0x7FF0000000000000ull; // the exponent
|
||||
return (e != 0x7FF0000000000000ull);
|
||||
return (e != 0x7FF0000000000000ull);
|
||||
}
|
||||
|
||||
bool hwf_manager::is_int(hwf const & x) {
|
||||
|
@ -596,8 +589,8 @@ void hwf_manager::mk_pzero(hwf & o) {
|
|||
}
|
||||
|
||||
void hwf_manager::mk_zero(bool sign, hwf & o) {
|
||||
if (sign)
|
||||
mk_nzero(o);
|
||||
if (sign)
|
||||
mk_nzero(o);
|
||||
else
|
||||
mk_pzero(o);
|
||||
}
|
||||
|
@ -627,7 +620,7 @@ void hwf_manager::mk_ninf(hwf & o) {
|
|||
#ifdef USE_INTRINSICS
|
||||
#define SETRM(RM) _MM_SET_ROUNDING_MODE(RM)
|
||||
#else
|
||||
#define SETRM(RM) _controlfp_s(&sse2_state, RM, _MCW_RC);
|
||||
#define SETRM(RM) _controlfp_s(&sse2_state, RM, _MCW_RC);
|
||||
#endif
|
||||
#else
|
||||
#ifdef USE_INTRINSICS
|
||||
|
@ -691,7 +684,7 @@ void hwf_manager::set_rounding_mode(mpf_rounding_mode rm)
|
|||
#endif
|
||||
#else // OSX/Linux
|
||||
switch (rm) {
|
||||
case MPF_ROUND_NEAREST_TEVEN:
|
||||
case MPF_ROUND_NEAREST_TEVEN:
|
||||
SETRM(FE_TONEAREST);
|
||||
break;
|
||||
case MPF_ROUND_TOWARD_POSITIVE:
|
||||
|
|
|
@ -1077,21 +1077,20 @@ void mpf_manager::round_to_integral(mpf_rounding_mode rm, mpf const & x, mpf & o
|
|||
|
||||
unsigned shift = (o.sbits - 1) - ((unsigned)o.exponent);
|
||||
const mpz & shift_p = m_powers2(shift);
|
||||
const mpz & shiftm1_p = m_powers2(shift-1);
|
||||
TRACE("mpf_dbg", tout << "shift=" << shift << std::endl;);
|
||||
TRACE("mpf_dbg", tout << "shiftm1_p=" << m_mpz_manager.to_string(shiftm1_p) << std::endl;);
|
||||
|
||||
scoped_mpz div(m_mpz_manager), rem(m_mpz_manager);
|
||||
m_mpz_manager.machine_div_rem(o.significand, shift_p, div, rem);
|
||||
TRACE("mpf_dbg", tout << "div=" << m_mpz_manager.to_string(div) << " rem=" << m_mpz_manager.to_string(rem) << std::endl;);
|
||||
|
||||
const mpz & shift_p1 = m_powers2(shift-1);
|
||||
TRACE("mpf_dbg", tout << "shift_p1=" << m_mpz_manager.to_string(shift_p1) << std::endl;);
|
||||
|
||||
switch (rm) {
|
||||
case MPF_ROUND_NEAREST_TEVEN:
|
||||
case MPF_ROUND_NEAREST_TAWAY: {
|
||||
bool tie = m_mpz_manager.eq(rem, shift_p1);
|
||||
bool less_than_tie = m_mpz_manager.lt(rem, shift_p1);
|
||||
bool more_than_tie = m_mpz_manager.gt(rem, shift_p1);
|
||||
bool tie = m_mpz_manager.eq(rem, shiftm1_p);
|
||||
bool less_than_tie = m_mpz_manager.lt(rem, shiftm1_p);
|
||||
bool more_than_tie = m_mpz_manager.gt(rem, shiftm1_p);
|
||||
TRACE("mpf_dbg", tout << "tie= " << tie << "; <tie = " << less_than_tie << "; >tie = " << more_than_tie << std::endl;);
|
||||
if (tie) {
|
||||
if ((rm == MPF_ROUND_NEAREST_TEVEN && m_mpz_manager.is_odd(div)) ||
|
||||
|
@ -1231,43 +1230,18 @@ void mpf_manager::rem(mpf const & x, mpf const & y, mpf & o) {
|
|||
else if (is_zero(x))
|
||||
set(o, x);
|
||||
else {
|
||||
o.ebits = x.ebits;
|
||||
o.sbits = x.sbits;
|
||||
o.sign = x.sign;
|
||||
// r = x - y * n
|
||||
scoped_mpf nr(*this), n(*this), yn(*this);
|
||||
div(MPF_ROUND_NEAREST_TEVEN, x, y, nr);
|
||||
round_to_integral(MPF_ROUND_NEAREST_TEVEN, nr, n);
|
||||
mul(MPF_ROUND_NEAREST_TEVEN, y, n, yn);
|
||||
sub(MPF_ROUND_NEAREST_TEVEN, x, yn, o);
|
||||
|
||||
scoped_mpf a(*this), b(*this);
|
||||
set(a, x);
|
||||
set(b, y);
|
||||
unpack(a, true);
|
||||
unpack(b, true);
|
||||
if (is_zero(o))
|
||||
o.sign = x.sign;
|
||||
|
||||
TRACE("mpf_dbg", tout << "A = " << to_string(a) << std::endl;);
|
||||
TRACE("mpf_dbg", tout << "B = " << to_string(b) << std::endl;);
|
||||
|
||||
if (a.exponent() < b.exponent())
|
||||
set(o, x);
|
||||
else {
|
||||
mpf_exp_t exp_diff = a.exponent() - b.exponent();
|
||||
SASSERT(exp_diff >= 0);
|
||||
TRACE("mpf_dbg", tout << "exp_diff = " << exp_diff << std::endl;);
|
||||
|
||||
SASSERT(exp_diff < INT_MAX);
|
||||
// CMW: This requires rather a lot of memory. There are algorithms that trade space for time by
|
||||
// computing only a small chunk of the remainder bits at a time.
|
||||
unsigned extra_bits = (unsigned) exp_diff;
|
||||
m_mpz_manager.mul2k(a.significand(), extra_bits);
|
||||
m_mpz_manager.rem(a.significand(), b.significand(), o.significand);
|
||||
|
||||
TRACE("mpf_dbg", tout << "REM' = " << to_string(o) << std::endl;);
|
||||
|
||||
if (m_mpz_manager.is_zero(o.significand))
|
||||
mk_zero(o.ebits, o.sbits, o.sign, o);
|
||||
else {
|
||||
o.exponent = b.exponent();
|
||||
m_mpz_manager.mul2k(o.significand, 3); // rounding bits
|
||||
round(MPF_ROUND_NEAREST_TEVEN, o);
|
||||
}
|
||||
}
|
||||
TRACE("mpf_dbg", tout << "N = " << to_string(n) << std::endl;);
|
||||
TRACE("mpf_dbg", tout << "YN = " << to_string(yn) << std::endl;);
|
||||
}
|
||||
|
||||
TRACE("mpf_dbg", tout << "REMAINDER = " << to_string(o) << std::endl;);
|
||||
|
|
Loading…
Reference in a new issue