Skip to content

Commit 278c8af

Browse files
committed
Add IEEE 754 TiesToAway rounding mode
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.
1 parent 7eef276 commit 278c8af

8 files changed

+59
-13
lines changed

src/solvers/floatbv/float_bv.cpp

+10-1
Original file line numberDiff line numberDiff line change
@@ -282,11 +282,14 @@ void float_bvt::rounding_mode_bitst::get(const exprt &rm)
282282
exprt round_to_minus_inf_const=
283283
from_integer(ieee_floatt::ROUND_TO_MINUS_INF, rm.type());
284284
exprt round_to_zero_const=from_integer(ieee_floatt::ROUND_TO_ZERO, rm.type());
285+
exprt round_to_away_const =
286+
from_integer(ieee_floatt::ROUND_TO_AWAY, rm.type());
285287

286288
round_to_even=equal_exprt(rm, round_to_even_const);
287289
round_to_plus_inf=equal_exprt(rm, round_to_plus_inf_const);
288290
round_to_minus_inf=equal_exprt(rm, round_to_minus_inf_const);
289291
round_to_zero=equal_exprt(rm, round_to_zero_const);
292+
round_to_away = equal_exprt(rm, round_to_away_const);
290293
}
291294

292295
exprt float_bvt::sign_bit(const exprt &op)
@@ -1166,12 +1169,18 @@ exprt float_bvt::fraction_rounding_decision(
11661169
// round to zero
11671170
false_exprt round_to_zero;
11681171

1172+
// round to away
1173+
const auto round_to_away = or_exprt(rounding_bit, sticky_bit);
1174+
11691175
// now select appropriate one
1176+
// clang-format off
11701177
return if_exprt(rounding_mode_bits.round_to_even, round_to_even,
11711178
if_exprt(rounding_mode_bits.round_to_plus_inf, round_to_plus_inf,
11721179
if_exprt(rounding_mode_bits.round_to_minus_inf, round_to_minus_inf,
11731180
if_exprt(rounding_mode_bits.round_to_zero, round_to_zero,
1174-
false_exprt())))); // otherwise zero
1181+
if_exprt(rounding_mode_bits.round_to_away, round_to_away,
1182+
false_exprt()))))); // otherwise zero
1183+
// clang-format off
11751184
}
11761185

11771186
void float_bvt::round_fraction(

src/solvers/floatbv/float_bv.h

+1
Original file line numberDiff line numberDiff line change
@@ -104,6 +104,7 @@ class float_bvt
104104
exprt round_to_zero;
105105
exprt round_to_plus_inf;
106106
exprt round_to_minus_inf;
107+
exprt round_to_away;
107108

108109
void get(const exprt &rm);
109110
explicit rounding_mode_bitst(const exprt &rm) { get(rm); }

src/solvers/floatbv/float_utils.cpp

+10-1
Original file line numberDiff line numberDiff line change
@@ -22,11 +22,14 @@ void float_utilst::set_rounding_mode(const bvt &src)
2222
bv_utils.build_constant(ieee_floatt::ROUND_TO_MINUS_INF, src.size());
2323
bvt round_to_zero=
2424
bv_utils.build_constant(ieee_floatt::ROUND_TO_ZERO, src.size());
25+
bvt round_to_away =
26+
bv_utils.build_constant(ieee_floatt::ROUND_TO_AWAY, src.size());
2527

2628
rounding_mode_bits.round_to_even=bv_utils.equal(src, round_to_even);
2729
rounding_mode_bits.round_to_plus_inf=bv_utils.equal(src, round_to_plus_inf);
2830
rounding_mode_bits.round_to_minus_inf=bv_utils.equal(src, round_to_minus_inf);
2931
rounding_mode_bits.round_to_zero=bv_utils.equal(src, round_to_zero);
32+
rounding_mode_bits.round_to_away = bv_utils.equal(src, round_to_away);
3033
}
3134

3235
bvt float_utilst::from_signed_integer(const bvt &src)
@@ -990,12 +993,18 @@ literalt float_utilst::fraction_rounding_decision(
990993
literalt round_to_zero=
991994
const_literal(false);
992995

996+
// round to away
997+
literalt round_to_away = prop.lor(rounding_least, sticky_bit);
998+
993999
// now select appropriate one
1000+
// clang-format off
9941001
return prop.lselect(rounding_mode_bits.round_to_even, round_to_even,
9951002
prop.lselect(rounding_mode_bits.round_to_plus_inf, round_to_plus_inf,
9961003
prop.lselect(rounding_mode_bits.round_to_minus_inf, round_to_minus_inf,
9971004
prop.lselect(rounding_mode_bits.round_to_zero, round_to_zero,
998-
prop.new_variable())))); // otherwise non-det
1005+
prop.lselect(rounding_mode_bits.round_to_away, round_to_away,
1006+
prop.new_variable()))))); // otherwise non-det
1007+
// clang-format on
9991008
}
10001009

10011010
void float_utilst::round_fraction(unbiased_floatt &result)

src/solvers/floatbv/float_utils.h

+7-2
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@ class float_utilst
2525
literalt round_to_zero;
2626
literalt round_to_plus_inf;
2727
literalt round_to_minus_inf;
28+
literalt round_to_away;
2829

2930
rounding_mode_bitst():
3031
round_to_even(const_literal(true)),
@@ -36,8 +37,8 @@ class float_utilst
3637

3738
void set(const ieee_floatt::rounding_modet mode)
3839
{
39-
round_to_even=round_to_zero=round_to_plus_inf=round_to_minus_inf=
40-
const_literal(false);
40+
round_to_even = round_to_zero = round_to_plus_inf = round_to_minus_inf =
41+
round_to_away = const_literal(false);
4142

4243
switch(mode)
4344
{
@@ -57,6 +58,10 @@ class float_utilst
5758
round_to_zero=const_literal(true);
5859
break;
5960

61+
case ieee_floatt::ROUND_TO_AWAY:
62+
round_to_away = const_literal(true);
63+
break;
64+
6065
case ieee_floatt::NONDETERMINISTIC:
6166
case ieee_floatt::UNKNOWN:
6267
UNREACHABLE;

src/solvers/smt2/smt2_conv.cpp

+9-3
Original file line numberDiff line numberDiff line change
@@ -3804,10 +3804,12 @@ void smt2_convt::convert_rounding_mode_FPA(const exprt &expr)
38043804
out << "roundTowardPositive";
38053805
else if(value==3)
38063806
out << "roundTowardZero";
3807+
else if(value == 4)
3808+
out << "roundNearestTiesToAway";
38073809
else
38083810
INVARIANT_WITH_DIAGNOSTICS(
38093811
false,
3810-
"Rounding mode should have value 0, 1, 2, or 3",
3812+
"Rounding mode should have value 0, 1, 2, 3, or 4",
38113813
id2string(cexpr.get_value()));
38123814
}
38133815
else
@@ -3827,10 +3829,14 @@ void smt2_convt::convert_rounding_mode_FPA(const exprt &expr)
38273829
convert_expr(expr);
38283830
out << ") roundTowardPositive ";
38293831

3832+
out << "(ite (= (_ bv3 " << width << ") ";
3833+
convert_expr(expr);
3834+
out << ") roundTowardZero ";
3835+
38303836
// TODO: add some kind of error checking here
3831-
out << "roundTowardZero";
3837+
out << "roundTowardAway";
38323838

3833-
out << ")))";
3839+
out << "))))";
38343840
}
38353841
}
38363842

src/solvers/smt2/smt2_parser.cpp

+3-2
Original file line numberDiff line numberDiff line change
@@ -1088,8 +1088,9 @@ void smt2_parsert::setup_expressions()
10881088
return from_integer(ieee_floatt::ROUND_TO_EVEN, unsignedbv_typet(32));
10891089
};
10901090

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

10951096
expressions["roundTowardPositive"] = [] {

src/util/ieee_float.cpp

+9
Original file line numberDiff line numberDiff line change
@@ -618,6 +618,11 @@ void ieee_floatt::align()
618618
else
619619
make_fltmax(); // positive
620620
break;
621+
622+
case ROUND_TO_AWAY:
623+
// round towards + or - infinity
624+
infinity_flag = true;
625+
break;
621626
}
622627

623628
return; // done
@@ -693,6 +698,10 @@ void ieee_floatt::divide_and_round(
693698
++dividend;
694699
break;
695700

701+
case ROUND_TO_AWAY:
702+
++dividend;
703+
break;
704+
696705
case NONDETERMINISTIC:
697706
case UNKNOWN:
698707
UNREACHABLE;

src/util/ieee_float.h

+10-4
Original file line numberDiff line numberDiff line change
@@ -117,13 +117,19 @@ class ieee_floatt
117117
public:
118118
// ROUND_TO_EVEN is also known as "round to nearest, ties to even", and
119119
// is the IEEE default.
120+
// ROUND_TO_AWAY is also known as "round to infinity".
120121
// The numbering below is what x86 uses in the control word and
121-
// what is recommended in C11 5.2.4.2.2
122+
// what is recommended in C11 5.2.4.2.2.
123+
// The numbering of ROUND_TO_AWAY is not specified in C11 5.2.4.2.2.
122124
enum rounding_modet
123125
{
124-
ROUND_TO_EVEN=0, ROUND_TO_MINUS_INF=1,
125-
ROUND_TO_PLUS_INF=2, ROUND_TO_ZERO=3,
126-
UNKNOWN, NONDETERMINISTIC
126+
ROUND_TO_EVEN = 0,
127+
ROUND_TO_MINUS_INF = 1,
128+
ROUND_TO_PLUS_INF = 2,
129+
ROUND_TO_ZERO = 3,
130+
ROUND_TO_AWAY = 4,
131+
UNKNOWN,
132+
NONDETERMINISTIC
127133
};
128134

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

0 commit comments

Comments
 (0)