@@ -23,6 +23,10 @@ Author: Peter Schrammel
2323
2424#include < langapi/language_util.h>
2525#include < goto-programs/adjust_float_expressions.h>
26+ #include < util/ieee_float.h>
27+
28+ #include < algorithm>
29+ #include < array>
2630
2731void constant_propagator_domaint::assign_rec (
2832 valuest &values,
@@ -510,7 +514,46 @@ bool constant_propagator_domaint::try_evaluate(
510514 exprt &expr,
511515 const namespacet &ns) const
512516{
517+ const irep_idt ID_rounding_mode = CPROVER_PREFIX " rounding_mode" ;
513518 adjust_float_expressions (expr, ns);
519+
520+ // if the current rounding mode is top we can
521+ // still get a non-top result by trying all rounding
522+ // modes and checking if the results are all the same
523+ if (!values.is_constant (symbol_exprt (ID_rounding_mode)))
524+ {
525+ // NOLINTNEXTLINE (whitespace/braces)
526+ auto rounding_modes = std::array<ieee_floatt::rounding_modet, 4 >{
527+ // NOLINTNEXTLINE (whitespace/braces)
528+ {ieee_floatt::ROUND_TO_EVEN,
529+ ieee_floatt::ROUND_TO_ZERO,
530+ ieee_floatt::ROUND_TO_MINUS_INF,
531+ // NOLINTNEXTLINE (whitespace/braces)
532+ ieee_floatt::ROUND_TO_PLUS_INF}};
533+ // instead of 4, we could write rounding_modes.size() here
534+ // if we dropped Visual Studio 2013 support (no constexpr)
535+ std::array<exprt, 4 > possible_results;
536+ for (std::size_t i = 0 ; i < possible_results.size (); ++i)
537+ {
538+ constant_propagator_domaint child (*this );
539+ child.values .set_to (
540+ ID_rounding_mode, from_integer (rounding_modes[i], integer_typet ()));
541+ possible_results[i] = expr;
542+ if (child.try_evaluate (possible_results[i], ns))
543+ {
544+ return true ;
545+ }
546+ }
547+ for (auto const &possible_result : possible_results)
548+ {
549+ if (possible_result != possible_results.front ())
550+ {
551+ return true ;
552+ }
553+ }
554+ expr = possible_results.front ();
555+ return false ;
556+ }
514557 bool did_not_change_anything = values.replace_const .replace (expr);
515558 did_not_change_anything &= simplify (expr, ns);
516559 return did_not_change_anything;
0 commit comments