Skip to content

Commit

Permalink
Add IEEE 754 TiesToAway rounding mode
Browse files Browse the repository at this point in the history
This adds IEEE 754 TiesToAway rounding mode, which rounds away from zero in
case of a tie.

The rounding mode is added to three distinct implementations:

1. The implementation for constants, in util/ieee_float.h

2. The implementation that creates a bit-level encoding, in
src/solvers/floatbv/float_utils.h.

3. The implementation that creates a word-level encoding, in
solvers/floatbv/float_bv.cpp.
  • Loading branch information
kroening committed Jan 2, 2025
1 parent 1102fa1 commit 6f246fe
Show file tree
Hide file tree
Showing 8 changed files with 69 additions and 21 deletions.
11 changes: 10 additions & 1 deletion src/solvers/floatbv/float_bv.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -282,11 +282,14 @@ void float_bvt::rounding_mode_bitst::get(const exprt &rm)
exprt round_to_minus_inf_const=
from_integer(ieee_floatt::ROUND_TO_MINUS_INF, rm.type());
exprt round_to_zero_const=from_integer(ieee_floatt::ROUND_TO_ZERO, rm.type());
exprt round_to_away_const =
from_integer(ieee_floatt::ROUND_TO_AWAY, rm.type());

round_to_even=equal_exprt(rm, round_to_even_const);
round_to_plus_inf=equal_exprt(rm, round_to_plus_inf_const);
round_to_minus_inf=equal_exprt(rm, round_to_minus_inf_const);
round_to_zero=equal_exprt(rm, round_to_zero_const);
round_to_away = equal_exprt(rm, round_to_away_const);
}

exprt float_bvt::sign_bit(const exprt &op)
Expand Down Expand Up @@ -1166,12 +1169,18 @@ exprt float_bvt::fraction_rounding_decision(
// round to zero
false_exprt round_to_zero;

// round to away

Check warning on line 1172 in src/solvers/floatbv/float_bv.cpp

View check run for this annotation

Codecov / codecov/patch

src/solvers/floatbv/float_bv.cpp#L1172

Added line #L1172 was not covered by tests
const auto round_to_away = or_exprt(rounding_bit, sticky_bit);

Check warning on line 1174 in src/solvers/floatbv/float_bv.cpp

View check run for this annotation

Codecov / codecov/patch

src/solvers/floatbv/float_bv.cpp#L1174

Added line #L1174 was not covered by tests
// now select appropriate one
// clang-format off
return if_exprt(rounding_mode_bits.round_to_even, round_to_even,
if_exprt(rounding_mode_bits.round_to_plus_inf, round_to_plus_inf,
if_exprt(rounding_mode_bits.round_to_minus_inf, round_to_minus_inf,
if_exprt(rounding_mode_bits.round_to_zero, round_to_zero,
false_exprt())))); // otherwise zero
if_exprt(rounding_mode_bits.round_to_away, round_to_away,
false_exprt()))))); // otherwise zero
// clang-format off

Check warning on line 1183 in src/solvers/floatbv/float_bv.cpp

View check run for this annotation

Codecov / codecov/patch

src/solvers/floatbv/float_bv.cpp#L1183

Added line #L1183 was not covered by tests
}

void float_bvt::round_fraction(
Expand Down
1 change: 1 addition & 0 deletions src/solvers/floatbv/float_bv.h
Original file line number Diff line number Diff line change
Expand Up @@ -104,6 +104,7 @@ class float_bvt
exprt round_to_zero;
exprt round_to_plus_inf;
exprt round_to_minus_inf;
exprt round_to_away;

void get(const exprt &rm);
explicit rounding_mode_bitst(const exprt &rm) { get(rm); }
Expand Down
11 changes: 10 additions & 1 deletion src/solvers/floatbv/float_utils.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -22,11 +22,14 @@ void float_utilst::set_rounding_mode(const bvt &src)
bv_utils.build_constant(ieee_floatt::ROUND_TO_MINUS_INF, src.size());
bvt round_to_zero=
bv_utils.build_constant(ieee_floatt::ROUND_TO_ZERO, src.size());
bvt round_to_away =
bv_utils.build_constant(ieee_floatt::ROUND_TO_AWAY, src.size());

rounding_mode_bits.round_to_even=bv_utils.equal(src, round_to_even);
rounding_mode_bits.round_to_plus_inf=bv_utils.equal(src, round_to_plus_inf);
rounding_mode_bits.round_to_minus_inf=bv_utils.equal(src, round_to_minus_inf);
rounding_mode_bits.round_to_zero=bv_utils.equal(src, round_to_zero);
rounding_mode_bits.round_to_away = bv_utils.equal(src, round_to_away);
}

bvt float_utilst::from_signed_integer(const bvt &src)
Expand Down Expand Up @@ -990,12 +993,18 @@ literalt float_utilst::fraction_rounding_decision(
literalt round_to_zero=
const_literal(false);

// round to away
literalt round_to_away = prop.lor(rounding_least, sticky_bit);

// now select appropriate one
// clang-format off
return prop.lselect(rounding_mode_bits.round_to_even, round_to_even,
prop.lselect(rounding_mode_bits.round_to_plus_inf, round_to_plus_inf,
prop.lselect(rounding_mode_bits.round_to_minus_inf, round_to_minus_inf,
prop.lselect(rounding_mode_bits.round_to_zero, round_to_zero,
prop.new_variable())))); // otherwise non-det
prop.lselect(rounding_mode_bits.round_to_away, round_to_away,
prop.new_variable()))))); // otherwise non-det
// clang-format on
}

void float_utilst::round_fraction(unbiased_floatt &result)
Expand Down
22 changes: 14 additions & 8 deletions src/solvers/floatbv/float_utils.h
Original file line number Diff line number Diff line change
Expand Up @@ -25,19 +25,21 @@ class float_utilst
literalt round_to_zero;
literalt round_to_plus_inf;
literalt round_to_minus_inf;

rounding_mode_bitst():
round_to_even(const_literal(true)),
round_to_zero(const_literal(false)),
round_to_plus_inf(const_literal(false)),
round_to_minus_inf(const_literal(false))
literalt round_to_away;

rounding_mode_bitst()
: round_to_even(const_literal(true)),
round_to_zero(const_literal(false)),
round_to_plus_inf(const_literal(false)),
round_to_minus_inf(const_literal(false)),
round_to_away(const_literal(false))
{
}

void set(const ieee_floatt::rounding_modet mode)
{
round_to_even=round_to_zero=round_to_plus_inf=round_to_minus_inf=
const_literal(false);
round_to_even = round_to_zero = round_to_plus_inf = round_to_minus_inf =
round_to_away = const_literal(false);

switch(mode)
{
Expand All @@ -57,6 +59,10 @@ class float_utilst
round_to_zero=const_literal(true);
break;

case ieee_floatt::ROUND_TO_AWAY:
round_to_away = const_literal(true);
break;

Check warning on line 64 in src/solvers/floatbv/float_utils.h

View check run for this annotation

Codecov / codecov/patch

src/solvers/floatbv/float_utils.h#L62-L64

Added lines #L62 - L64 were not covered by tests

case ieee_floatt::NONDETERMINISTIC:
case ieee_floatt::UNKNOWN:
UNREACHABLE;
Expand Down
12 changes: 9 additions & 3 deletions src/solvers/smt2/smt2_conv.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3897,10 +3897,12 @@ void smt2_convt::convert_rounding_mode_FPA(const exprt &expr)
out << "roundTowardPositive";
else if(value==3)
out << "roundTowardZero";
else if(value == 4)
out << "roundNearestTiesToAway";

Check warning on line 3901 in src/solvers/smt2/smt2_conv.cpp

View check run for this annotation

Codecov / codecov/patch

src/solvers/smt2/smt2_conv.cpp#L3900-L3901

Added lines #L3900 - L3901 were not covered by tests
else
INVARIANT_WITH_DIAGNOSTICS(
false,
"Rounding mode should have value 0, 1, 2, or 3",
"Rounding mode should have value 0, 1, 2, 3, or 4",
id2string(cexpr.get_value()));
}
else
Expand All @@ -3920,10 +3922,14 @@ void smt2_convt::convert_rounding_mode_FPA(const exprt &expr)
convert_expr(expr);
out << ") roundTowardPositive ";

out << "(ite (= (_ bv3 " << width << ") ";
convert_expr(expr);
out << ") roundTowardZero ";

Check warning on line 3927 in src/solvers/smt2/smt2_conv.cpp

View check run for this annotation

Codecov / codecov/patch

src/solvers/smt2/smt2_conv.cpp#L3925-L3927

Added lines #L3925 - L3927 were not covered by tests

// TODO: add some kind of error checking here
out << "roundTowardZero";
out << "roundTowardAway";

Check warning on line 3930 in src/solvers/smt2/smt2_conv.cpp

View check run for this annotation

Codecov / codecov/patch

src/solvers/smt2/smt2_conv.cpp#L3930

Added line #L3930 was not covered by tests

out << ")))";
out << "))))";

Check warning on line 3932 in src/solvers/smt2/smt2_conv.cpp

View check run for this annotation

Codecov / codecov/patch

src/solvers/smt2/smt2_conv.cpp#L3932

Added line #L3932 was not covered by tests
}
}

Expand Down
10 changes: 6 additions & 4 deletions src/solvers/smt2/smt2_parser.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1093,12 +1093,14 @@ void smt2_parsert::setup_expressions()
return from_integer(ieee_floatt::ROUND_TO_EVEN, unsignedbv_typet(32));
};

expressions["roundNearestTiesToAway"] = [this]() -> exprt {
throw error("unsupported rounding mode");
expressions["roundNearestTiesToAway"] = [] {
// we encode as 32-bit unsignedbv
return from_integer(ieee_floatt::ROUND_TO_AWAY, unsignedbv_typet(32));

Check warning on line 1098 in src/solvers/smt2/smt2_parser.cpp

View check run for this annotation

Codecov / codecov/patch

src/solvers/smt2/smt2_parser.cpp#L1097-L1098

Added lines #L1097 - L1098 were not covered by tests
};

expressions["RNA"] = [this]() -> exprt {
throw error("unsupported rounding mode");
expressions["RNA"] = [] {
// we encode as 32-bit unsignedbv
return from_integer(ieee_floatt::ROUND_TO_AWAY, unsignedbv_typet(32));

Check warning on line 1103 in src/solvers/smt2/smt2_parser.cpp

View check run for this annotation

Codecov / codecov/patch

src/solvers/smt2/smt2_parser.cpp#L1102-L1103

Added lines #L1102 - L1103 were not covered by tests
};

expressions["roundTowardPositive"] = [] {
Expand Down
9 changes: 9 additions & 0 deletions src/util/ieee_float.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -618,6 +618,11 @@ void ieee_floatt::align()
else
make_fltmax(); // positive
break;

case ROUND_TO_AWAY:

Check warning on line 622 in src/util/ieee_float.cpp

View check run for this annotation

Codecov / codecov/patch

src/util/ieee_float.cpp#L622

Added line #L622 was not covered by tests
// round towards + or - infinity
infinity_flag = true;
break;

Check warning on line 625 in src/util/ieee_float.cpp

View check run for this annotation

Codecov / codecov/patch

src/util/ieee_float.cpp#L624-L625

Added lines #L624 - L625 were not covered by tests
}

return; // done
Expand Down Expand Up @@ -693,6 +698,10 @@ void ieee_floatt::divide_and_round(
++dividend;
break;

case ROUND_TO_AWAY:

Check warning on line 701 in src/util/ieee_float.cpp

View check run for this annotation

Codecov / codecov/patch

src/util/ieee_float.cpp#L701

Added line #L701 was not covered by tests
++dividend;
break;

case NONDETERMINISTIC:
case UNKNOWN:
UNREACHABLE;
Expand Down
14 changes: 10 additions & 4 deletions src/util/ieee_float.h
Original file line number Diff line number Diff line change
Expand Up @@ -117,13 +117,19 @@ class ieee_floatt
public:
// ROUND_TO_EVEN is also known as "round to nearest, ties to even", and
// is the IEEE default.
// ROUND_TO_AWAY is also known as "round to infinity".
// The numbering below is what x86 uses in the control word and
// what is recommended in C11 5.2.4.2.2
// what is recommended in C11 5.2.4.2.2.
// The numbering of ROUND_TO_AWAY is not specified in C11 5.2.4.2.2.
enum rounding_modet
{
ROUND_TO_EVEN=0, ROUND_TO_MINUS_INF=1,
ROUND_TO_PLUS_INF=2, ROUND_TO_ZERO=3,
UNKNOWN, NONDETERMINISTIC
ROUND_TO_EVEN = 0,
ROUND_TO_MINUS_INF = 1,
ROUND_TO_PLUS_INF = 2,
ROUND_TO_ZERO = 3,
ROUND_TO_AWAY = 4,
UNKNOWN,
NONDETERMINISTIC
};

// A helper to turn a rounding mode into a constant bitvector expression
Expand Down

0 comments on commit 6f246fe

Please sign in to comment.