@@ -129,20 +129,29 @@ void interval_domaint::transform(
129129
130130/* ******************************************************************\
131131
132- Function: interval_domaint::merge
132+ Function: interval_domaint::join
133133
134- Inputs:
134+ Inputs: The interval domain, b, to join to this domain.
135135
136- Outputs:
136+ Outputs: True if the join increases the set represented by *this,
137+ False if there is no change.
137138
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.
139150
140151\*******************************************************************/
141152
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)
146155{
147156 if (b.bottom )
148157 return false ;
@@ -527,3 +536,67 @@ exprt interval_domaint::make_expression(const symbol_exprt &src) const
527536 else
528537 return true_exprt ();
529538}
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