Skip to content

Commit fe7b88a

Browse files
author
Daniel Kroening
authored
Merge pull request #961 from martin-cs/goto-analyzer-5-part2
Goto analyzer 5 part2
2 parents 0713f0e + c64448b commit fe7b88a

File tree

8 files changed

+258
-26
lines changed

8 files changed

+258
-26
lines changed

src/analyses/ai.cpp

Lines changed: 99 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,9 @@ Author: Daniel Kroening, [email protected]
88

99
#include <cassert>
1010
#include <memory>
11+
#include <sstream>
1112

13+
#include <util/simplify_expr.h>
1214
#include <util/std_expr.h>
1315
#include <util/std_code.h>
1416

@@ -18,6 +20,103 @@ Author: Daniel Kroening, [email protected]
1820

1921
/*******************************************************************\
2022
23+
Function: ai_domain_baset::output_json
24+
25+
Inputs:
26+
27+
Outputs:
28+
29+
Purpose:
30+
31+
\*******************************************************************/
32+
33+
jsont ai_domain_baset::output_json(
34+
const ai_baset &ai,
35+
const namespacet &ns) const
36+
{
37+
std::ostringstream out;
38+
output(out, ai, ns);
39+
json_stringt json(out.str());
40+
return json;
41+
}
42+
43+
/*******************************************************************\
44+
45+
Function: ai_domain_baset::output_xml
46+
47+
Inputs:
48+
49+
Outputs:
50+
51+
Purpose:
52+
53+
\*******************************************************************/
54+
55+
xmlt ai_domain_baset::output_xml(
56+
const ai_baset &ai,
57+
const namespacet &ns) const
58+
{
59+
std::ostringstream out;
60+
output(out, ai, ns);
61+
xmlt xml("domain");
62+
xml.data=out.str();
63+
return xml;
64+
}
65+
66+
/*******************************************************************\
67+
68+
Function: variable_sensitivity_domaint::ai_simplify_lhs
69+
70+
Inputs:
71+
condition - the expression to simplify
72+
ns - the namespace
73+
74+
Outputs: True if condition did not change. False otherwise. condition
75+
will be updated with the simplified condition if it has worked
76+
77+
Purpose: Use the information in the domain to simplify the expression
78+
on the LHS of an assignment. This for example won't simplify symbols
79+
to their values, but does simplify indices in arrays, members of
80+
structs and dereferencing of pointers
81+
\*******************************************************************/
82+
83+
bool ai_domain_baset::ai_simplify_lhs(
84+
exprt &condition, const namespacet &ns) const
85+
{
86+
// Care must be taken here to give something that is still writable
87+
if(condition.id()==ID_index)
88+
{
89+
index_exprt ie=to_index_expr(condition);
90+
bool changed=ai_simplify(ie.index(), ns);
91+
if(changed)
92+
condition=simplify_expr(ie, ns);
93+
94+
return !changed;
95+
}
96+
else if(condition.id()==ID_dereference)
97+
{
98+
dereference_exprt de=to_dereference_expr(condition);
99+
bool changed=ai_simplify(de.pointer(), ns);
100+
if(changed)
101+
condition=simplify_expr(de, ns); // So *(&x) -> x
102+
103+
return !changed;
104+
}
105+
else if(condition.id()==ID_member)
106+
{
107+
member_exprt me=to_member_expr(condition);
108+
bool changed=ai_simplify_lhs(me.compound(), ns); // <-- lhs!
109+
if(changed)
110+
condition=simplify_expr(me, ns);
111+
112+
return !changed;
113+
}
114+
else
115+
return true;
116+
}
117+
118+
/*******************************************************************\
119+
21120
Function: ai_baset::output
22121
23122
Inputs:

src/analyses/ai.h

Lines changed: 20 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -11,10 +11,10 @@ Author: Daniel Kroening, [email protected]
1111

1212
#include <map>
1313
#include <iosfwd>
14-
#include <sstream>
1514

1615
#include <util/json.h>
1716
#include <util/xml.h>
17+
#include <util/expr.h>
1818

1919
#include <goto-programs/goto_model.h>
2020

@@ -59,24 +59,11 @@ class ai_domain_baset
5959

6060
virtual jsont output_json(
6161
const ai_baset &ai,
62-
const namespacet &ns) const
63-
{
64-
std::ostringstream out;
65-
output(out, ai, ns);
66-
json_stringt json(out.str());
67-
return json;
68-
}
62+
const namespacet &ns) const;
6963

7064
virtual xmlt output_xml(
7165
const ai_baset &ai,
72-
const namespacet &ns) const
73-
{
74-
std::ostringstream out;
75-
output(out, ai, ns);
76-
xmlt xml("domain");
77-
xml.data=out.str();
78-
return xml;
79-
}
66+
const namespacet &ns) const;
8067

8168
// no states
8269
virtual void make_bottom()=0;
@@ -94,6 +81,23 @@ class ai_domain_baset
9481
//
9582
// This computes the join between "this" and "b".
9683
// Return true if "this" has changed.
84+
85+
// This method allows an expression to be simplified / evaluated using the
86+
// current state. It is used to evaluate assertions and in program
87+
// simplification
88+
89+
// return true if unchanged
90+
virtual bool ai_simplify(
91+
exprt &condition,
92+
const namespacet &ns) const
93+
{
94+
return true;
95+
}
96+
97+
// Simplifies the expression but keeps it as an l-value
98+
virtual bool ai_simplify_lhs(
99+
exprt &condition,
100+
const namespacet &ns) const;
97101
};
98102

99103
// don't use me -- I am just a base class

src/analyses/constant_propagator.cpp

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -333,6 +333,29 @@ void constant_propagator_domaint::assign(
333333

334334
/*******************************************************************\
335335
336+
Function: constant_propagator_domaint::ai_simplify
337+
338+
Inputs: The condition to simplify and its namespace.
339+
340+
Outputs: The simplified condition.
341+
342+
Purpose: Simplify the condition given context-sensitive knowledge
343+
from the abstract state.
344+
345+
\*******************************************************************/
346+
347+
bool constant_propagator_domaint::ai_simplify(
348+
exprt &condition,
349+
const namespacet &ns) const
350+
{
351+
bool b=values.replace_const.replace(condition);
352+
b&=simplify(condition, ns);
353+
354+
return b;
355+
}
356+
357+
/*******************************************************************\
358+
336359
Function: constant_propagator_domaint::is_array_constant
337360
338361
Inputs:

src/analyses/constant_propagator.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,10 @@ class constant_propagator_domaint:public ai_domain_baset
3030
void make_entry() final { values.set_to_top(); }
3131
bool merge(const constant_propagator_domaint &, locationt, locationt);
3232

33+
virtual bool ai_simplify(
34+
exprt &condition,
35+
const namespacet &ns) const override;
36+
3337
struct valuest
3438
{
3539
public:

src/analyses/interval_domain.cpp

Lines changed: 81 additions & 8 deletions
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

Lines changed: 13 additions & 2 deletions
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;

src/goto-programs/remove_unreachable.cpp

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,19 @@ void remove_unreachable(goto_programt &goto_program)
5656
}
5757
}
5858

59+
/*******************************************************************\
60+
61+
Function: remove_unreachable
62+
63+
Inputs: The goto functions from which the unreachable functions are
64+
to be removed.
65+
66+
Outputs: None.
67+
68+
Purpose: Removes unreachable instructions from all functions.
69+
70+
\*******************************************************************/
71+
5972
void remove_unreachable(goto_functionst &goto_functions)
6073
{
6174
Forall_goto_functions(f_it, goto_functions)

src/util/replace_symbol.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,11 @@ class replace_symbolt
5656
type_map.clear();
5757
}
5858

59+
bool empty() const
60+
{
61+
return expr_map.empty() && type_map.empty();
62+
}
63+
5964
replace_symbolt();
6065
virtual ~replace_symbolt();
6166

0 commit comments

Comments
 (0)