@@ -129,20 +129,29 @@ void interval_domaint::transform(
129
129
130
130
/* ******************************************************************\
131
131
132
- Function: interval_domaint::merge
132
+ Function: interval_domaint::join
133
133
134
- Inputs:
134
+ Inputs: The interval domain, b, to join to this domain.
135
135
136
- Outputs:
136
+ Outputs: True if the join increases the set represented by *this,
137
+ False if there is no change.
137
138
138
- Purpose:
139
+ Purpose: Sets *this to the mathematical join between the two domains.
140
+ This can be thought of as an abstract version of union;
141
+ *this is increased so that it contains all of the values that
142
+ are represented by b as well as its original intervals.
143
+ The result is an overapproximation, for example:
144
+ "[0,1]".join("[3,4]") --> "[0,4]"
145
+ includes 2 which isn't in [0,1] or [3,4].
146
+
147
+ Join is used in several places, the most significant being
148
+ merge, which uses it to bring together two different paths
149
+ of analysis.
139
150
140
151
\*******************************************************************/
141
152
142
- bool interval_domaint::merge (
143
- const interval_domaint &b,
144
- locationt from,
145
- locationt to)
153
+ bool interval_domaint::join (
154
+ const interval_domaint &b)
146
155
{
147
156
if (b.bottom )
148
157
return false ;
@@ -527,3 +536,67 @@ exprt interval_domaint::make_expression(const symbol_exprt &src) const
527
536
else
528
537
return true_exprt ();
529
538
}
539
+
540
+ /* ******************************************************************\
541
+
542
+ Function: interval_domaint::simplify
543
+
544
+ Inputs: The expression to simplify.
545
+
546
+ Outputs: A simplified version of the expression.
547
+
548
+ Purpose: Uses the abstract state to simplify a given expression
549
+ using context-specific information.
550
+
551
+ \*******************************************************************/
552
+
553
+ /*
554
+ * This implementation is aimed at reducing assertions to true, particularly
555
+ * range checks for arrays and other bounds checks.
556
+ *
557
+ * Rather than work with the various kinds of exprt directly, we use assume,
558
+ * join and is_bottom. It is sufficient for the use case and avoids duplicating
559
+ * functionality that is in assume anyway.
560
+ *
561
+ * As some expressions (1<=a && a<=2) can be represented exactly as intervals
562
+ * and some can't (a<1 || a>2), the way these operations are used varies
563
+ * depending on the structure of the expression to try to give the best results.
564
+ * For example negating a disjunction makes it easier for assume to handle.
565
+ */
566
+
567
+ bool interval_domaint::ai_simplify (
568
+ exprt &condition,
569
+ const namespacet &ns) const
570
+ {
571
+ bool unchanged=true ;
572
+ interval_domaint d (*this );
573
+
574
+ // merge intervals to properly handle conjunction
575
+ if (condition.id ()==ID_and) // May be directly representable
576
+ {
577
+ interval_domaint a;
578
+ a.make_top (); // a is everything
579
+ a.assume (condition, ns); // Restrict a to an over-approximation
580
+ // of when condition is true
581
+ if (!a.join (d)) // If d (this) is included in a...
582
+ { // Then the condition is always true
583
+ unchanged=condition.is_true ();
584
+ condition.make_true ();
585
+ }
586
+ }
587
+ else if (condition.id ()==ID_symbol)
588
+ {
589
+ // TODO: we have to handle symbol expression
590
+ }
591
+ else // Less likely to be representable
592
+ {
593
+ d.assume (not_exprt (condition), ns); // Restrict to when condition is false
594
+ if (d.is_bottom ()) // If there there are none...
595
+ { // Then the condition is always true
596
+ unchanged=condition.is_true ();
597
+ condition.make_true ();
598
+ }
599
+ }
600
+
601
+ return unchanged;
602
+ }
0 commit comments