@@ -16,13 +16,17 @@ Author: Peter Schrammel
16
16
#include < util/format_expr.h>
17
17
#endif
18
18
19
+ #include < util/ieee_float.h>
19
20
#include < util/find_symbols.h>
20
21
#include < util/arith_tools.h>
21
22
#include < util/simplify_expr.h>
22
23
#include < util/cprover_prefix.h>
23
24
24
25
#include < langapi/language_util.h>
25
26
27
+ #include < algorithm>
28
+ #include < array>
29
+
26
30
void constant_propagator_domaint::assign_rec (
27
31
valuest &values,
28
32
const exprt &lhs,
@@ -35,8 +39,7 @@ void constant_propagator_domaint::assign_rec(
35
39
const symbol_exprt &s=to_symbol_expr (lhs);
36
40
37
41
exprt tmp=rhs;
38
- values.replace_const (tmp);
39
- simplify (tmp, ns);
42
+ partial_evaluate (tmp, ns);
40
43
41
44
if (tmp.is_constant ())
42
45
values.set_to (s, tmp);
@@ -99,10 +102,10 @@ void constant_propagator_domaint::transform(
99
102
// Comparing iterators is safe as the target must be within the same list
100
103
// of instructions because this is a GOTO.
101
104
if (from->get_target ()==to)
102
- g= simplify_expr ( from->guard , ns) ;
105
+ g = from->guard ;
103
106
else
104
- g= simplify_expr ( not_exprt (from->guard ), ns );
105
-
107
+ g = not_exprt (from->guard );
108
+ partial_evaluate (g, ns);
106
109
if (g.is_false ())
107
110
values.set_to_bottom ();
108
111
else
@@ -269,10 +272,7 @@ bool constant_propagator_domaint::ai_simplify(
269
272
exprt &condition,
270
273
const namespacet &ns) const
271
274
{
272
- bool b=values.replace_const .replace (condition);
273
- b&=simplify (condition, ns);
274
-
275
- return b;
275
+ return partial_evaluate (condition, ns);
276
276
}
277
277
278
278
@@ -504,6 +504,74 @@ bool constant_propagator_domaint::merge(
504
504
return values.merge (other.values );
505
505
}
506
506
507
+ // / Attempt to evaluate expression using domain knowledge
508
+ // / This function changes the expression that is passed into it.
509
+ // / \param expr The expression to evaluate
510
+ // / \param ns The namespace for symbols in the expression
511
+ // / \return True if the expression is unchanged, false otherwise
512
+ bool constant_propagator_domaint::partial_evaluate (
513
+ exprt &expr,
514
+ const namespacet &ns) const
515
+ {
516
+ // if the current rounding mode is top we can
517
+ // still get a non-top result by trying all rounding
518
+ // modes and checking if the results are all the same
519
+ if (!values.is_constant (symbol_exprt (ID_cprover_rounding_mode_str)))
520
+ {
521
+ return partial_evaluate_with_all_rounding_modes (expr, ns);
522
+ }
523
+ return replace_constants_and_simplify (expr, ns);
524
+ }
525
+
526
+ // / Attempt to evaluate an expression in all rounding modes.
527
+ // /
528
+ // / If the result is the same for all rounding modes, change
529
+ // / expr to that result and return false. Otherwise, return true.
530
+ bool constant_propagator_domaint::partial_evaluate_with_all_rounding_modes (
531
+ exprt &expr,
532
+ const namespacet &ns) const
533
+ { // NOLINTNEXTLINE (whitespace/braces)
534
+ auto rounding_modes = std::array<ieee_floatt::rounding_modet, 4 >{
535
+ // NOLINTNEXTLINE (whitespace/braces)
536
+ {ieee_floatt::ROUND_TO_EVEN,
537
+ ieee_floatt::ROUND_TO_ZERO,
538
+ ieee_floatt::ROUND_TO_MINUS_INF,
539
+ // NOLINTNEXTLINE (whitespace/braces)
540
+ ieee_floatt::ROUND_TO_PLUS_INF}};
541
+ exprt first_result;
542
+ for (std::size_t i = 0 ; i < rounding_modes.size (); ++i)
543
+ {
544
+ constant_propagator_domaint child (*this );
545
+ child.values .set_to (
546
+ ID_cprover_rounding_mode_str,
547
+ from_integer (rounding_modes[i], integer_typet ()));
548
+ exprt result = expr;
549
+ if (child.replace_constants_and_simplify (result, ns))
550
+ {
551
+ return true ;
552
+ }
553
+ else if (i == 0 )
554
+ {
555
+ first_result = result;
556
+ }
557
+ else if (result != first_result)
558
+ {
559
+ return true ;
560
+ }
561
+ }
562
+ expr = first_result;
563
+ return false ;
564
+ }
565
+
566
+ bool constant_propagator_domaint::replace_constants_and_simplify (
567
+ exprt &expr,
568
+ const namespacet &ns) const
569
+ {
570
+ bool did_not_change_anything = values.replace_const .replace (expr);
571
+ did_not_change_anything &= simplify (expr, ns);
572
+ return did_not_change_anything;
573
+ }
574
+
507
575
void constant_propagator_ait::replace (
508
576
goto_functionst &goto_functions,
509
577
const namespacet &ns)
@@ -529,38 +597,34 @@ void constant_propagator_ait::replace(
529
597
530
598
if (it->is_goto () || it->is_assume () || it->is_assert ())
531
599
{
532
- s_it->second .values .replace_const (it->guard );
533
- simplify (it->guard , ns);
600
+ s_it->second .partial_evaluate (it->guard , ns);
534
601
}
535
602
else if (it->is_assign ())
536
603
{
537
604
exprt &rhs=to_code_assign (it->code ).rhs ();
538
- s_it->second .values .replace_const (rhs);
539
- simplify (rhs, ns);
605
+ s_it->second .partial_evaluate (rhs, ns);
540
606
if (rhs.id ()==ID_constant)
541
607
rhs.add_source_location ()=it->code .op0 ().source_location ();
542
608
}
543
609
else if (it->is_function_call ())
544
610
{
545
- s_it->second .values .replace_const (
546
- to_code_function_call (it->code ).function ());
547
-
548
- simplify (to_code_function_call (it->code ).function (), ns);
611
+ exprt &function = to_code_function_call (it->code ).function ();
612
+ s_it->second .partial_evaluate (function, ns);
549
613
550
614
exprt::operandst &args=
551
615
to_code_function_call (it->code ).arguments ();
552
616
553
- for (exprt::operandst::iterator o_it=args.begin ();
554
- o_it!=args.end (); ++o_it)
617
+ for (auto &arg : args)
555
618
{
556
- s_it->second .values .replace_const (*o_it);
557
- simplify (*o_it, ns);
619
+ s_it->second .partial_evaluate (arg, ns);
558
620
}
559
621
}
560
622
else if (it->is_other ())
561
623
{
562
624
if (it->code .get_statement ()==ID_expression)
563
- s_it->second .values .replace_const (it->code );
625
+ {
626
+ s_it->second .partial_evaluate (it->code , ns);
627
+ }
564
628
}
565
629
}
566
630
}
0 commit comments