Skip to content

Commit 409d6ef

Browse files
author
martin
committed
Implement ai_simplify for intervals.
1 parent 050cc59 commit 409d6ef

File tree

2 files changed

+94
-10
lines changed

2 files changed

+94
-10
lines changed

src/analyses/interval_domain.cpp

+81-8
Original file line numberDiff line numberDiff line change
@@ -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+
}

src/analyses/interval_domain.h

+13-2
Original file line numberDiff line numberDiff line change
@@ -40,10 +40,17 @@ class interval_domaint:public ai_domain_baset
4040
const ai_baset &ai,
4141
const namespacet &ns) const final;
4242

43+
protected:
44+
bool join(const interval_domaint &b);
45+
46+
public:
4347
bool merge(
4448
const interval_domaint &b,
4549
locationt from,
46-
locationt to);
50+
locationt to)
51+
{
52+
return join(b);
53+
}
4754

4855
// no states
4956
void make_bottom() final
@@ -85,7 +92,11 @@ class interval_domaint:public ai_domain_baset
8592
return bottom;
8693
}
8794

88-
private:
95+
virtual bool ai_simplify(
96+
exprt &condition,
97+
const namespacet &ns) const override;
98+
99+
protected:
89100
bool bottom;
90101

91102
typedef std::map<irep_idt, integer_intervalt> int_mapt;

0 commit comments

Comments
 (0)