Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add IEEE 754 TiesToAway rounding mode #8515

Merged
merged 1 commit into from
Feb 11, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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 @@
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 @@
// 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 @@
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 round_to_zero=
const_literal(false);

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

Check warning on line 998 in src/solvers/floatbv/float_utils.cpp

View check run for this annotation

Codecov / codecov/patch

src/solvers/floatbv/float_utils.cpp#L998

Added line #L998 was not covered by tests
// 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 @@
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 @@
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 @@ -3917,10 +3917,12 @@
out << "roundTowardPositive";
else if(value==3)
out << "roundTowardZero";
else if(value == 4)
out << "roundNearestTiesToAway";

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

View check run for this annotation

Codecov / codecov/patch

src/solvers/smt2/smt2_conv.cpp#L3920-L3921

Added lines #L3920 - L3921 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 @@ -3940,10 +3942,14 @@
convert_expr(expr);
out << ") roundTowardPositive ";

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

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

View check run for this annotation

Codecov / codecov/patch

src/solvers/smt2/smt2_conv.cpp#L3945-L3948

Added lines #L3945 - L3948 were not covered by tests
// TODO: add some kind of error checking here
out << "roundTowardZero";
out << "roundNearestTiesToAway";

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

View check run for this annotation

Codecov / codecov/patch

src/solvers/smt2/smt2_conv.cpp#L3950

Added line #L3950 was not covered by tests

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

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

View check run for this annotation

Codecov / codecov/patch

src/solvers/smt2/smt2_conv.cpp#L3952

Added line #L3952 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 @@
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 @@ -894,6 +894,11 @@
else
make_fltmax(); // positive
break;

case ROUND_TO_AWAY:
// round towards + or - infinity
infinity_flag = true;
break;

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

View check run for this annotation

Codecov / codecov/patch

src/util/ieee_float.cpp#L898-L901

Added lines #L898 - L901 were not covered by tests
}

return; // done
Expand Down Expand Up @@ -969,6 +974,10 @@
++dividend;
break;

case ROUND_TO_AWAY:

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

View check run for this annotation

Codecov / codecov/patch

src/util/ieee_float.cpp#L977

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

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

View check run for this annotation

Codecov / codecov/patch

src/util/ieee_float.cpp#L979

Added line #L979 was not covered by tests

case NONDETERMINISTIC:
case UNKNOWN:
UNREACHABLE;
Expand Down
5 changes: 4 additions & 1 deletion src/util/ieee_float.h
Original file line number Diff line number Diff line change
Expand Up @@ -331,14 +331,17 @@ class ieee_floatt : public ieee_float_valuet
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,
ROUND_TO_AWAY = 4,
UNKNOWN,
NONDETERMINISTIC
};
Expand Down
Loading