Skip to content

Commit 3eec1a7

Browse files
committed
Constant propagator: improve GOTO condition propagation
This was disabled due to unspecified problems with two-way constant prop (e.g. trying to propagate x => y and y => x when we have ASSUME(x == y) or IF x == y THEN GOTO ... Rather than try to fix those bugs, this provides a simpler implementation that only propagates from constants.
1 parent d20a12e commit 3eec1a7

File tree

3 files changed

+342
-39
lines changed

3 files changed

+342
-39
lines changed

src/analyses/constant_propagator.cpp

Lines changed: 64 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -113,15 +113,7 @@ void constant_propagator_domaint::transform(
113113
if(g.is_false())
114114
values.set_to_bottom();
115115
else
116-
{
117116
two_way_propagate_rec(g, ns, cp);
118-
// If two way propagate is enabled then it may be possible to detect
119-
// that the branch condition is infeasible and thus the domain should
120-
// be set to bottom. Without it the domain will only be set to bottom
121-
// if the guard expression is trivially (i.e. without context) false.
122-
INVARIANT(!values.is_bottom,
123-
"Without two-way propagation this should be impossible.");
124-
}
125117
}
126118
else if(from->is_dead())
127119
{
@@ -222,7 +214,7 @@ void constant_propagator_domaint::transform(
222214

223215

224216
/// handles equalities and conjunctions containing equalities
225-
bool constant_propagator_domaint::two_way_propagate_rec(
217+
void constant_propagator_domaint::two_way_propagate_rec(
226218
const exprt &expr,
227219
const namespacet &ns,
228220
const constant_propagator_ait *cp)
@@ -231,42 +223,79 @@ bool constant_propagator_domaint::two_way_propagate_rec(
231223
std::cout << "two_way_propagate_rec: " << format(expr) << '\n';
232224
#endif
233225

234-
bool change=false;
226+
// This used to attempt to propagate equalities both ways, but the original
227+
// author noted it is "buggy at the moment," so I only propagate constants
228+
// onto non-constants.
235229

236-
// this seems to be buggy at present
237-
#if 0
238230
if(expr.id()==ID_and)
239231
{
240-
// need a fixed point here to get the most out of it
241-
do
232+
forall_operands(it, expr)
233+
two_way_propagate_rec(*it, ns, cp);
234+
}
235+
else if(expr.id() == ID_not)
236+
{
237+
if(expr.op0().id() == ID_equal || expr.op0().id() == ID_notequal)
242238
{
243-
change = false;
244-
245-
forall_operands(it, expr)
246-
if(two_way_propagate_rec(*it, ns, cp))
247-
change=true;
239+
exprt subexpr = expr.op0();
240+
subexpr.id(subexpr.id() == ID_equal ? ID_notequal : ID_equal);
241+
two_way_propagate_rec(subexpr, ns, cp);
242+
}
243+
else if(expr.op0().id() == ID_symbol && expr.type() == bool_typet())
244+
{
245+
// Treat `IF !x` like `IF x == FALSE`:
246+
two_way_propagate_rec(equal_exprt(expr.op0(), false_exprt()), ns, cp);
248247
}
249-
while(change);
250248
}
251-
else if(expr.id()==ID_equal)
249+
else if(expr.id() == ID_symbol)
252250
{
253-
const exprt &lhs=expr.op0();
254-
const exprt &rhs=expr.op1();
255-
256-
// two-way propagation
257-
valuest copy_values=values;
258-
assign_rec(copy_values, lhs, rhs, ns);
259-
if(!values.is_constant(rhs) || values.is_constant(lhs))
260-
assign_rec(values, rhs, lhs, ns);
261-
change=values.meet(copy_values);
251+
if(expr.type() == bool_typet())
252+
{
253+
// Treat `IF x` like `IF x == TRUE`:
254+
two_way_propagate_rec(equal_exprt(expr, true_exprt()), ns, cp);
255+
}
262256
}
263-
#endif
257+
else if(expr.id() == ID_equal || expr.id() == ID_notequal)
258+
{
259+
exprt lhs = expr.op0();
260+
exprt rhs = expr.op1();
264261

265-
#ifdef DEBUG
266-
std::cout << "two_way_propagate_rec: " << change << '\n';
267-
#endif
262+
if(lhs.is_constant() && !rhs.is_constant())
263+
std::swap(lhs, rhs);
264+
265+
if(lhs.is_constant() || !rhs.is_constant())
266+
return;
268267

269-
return change;
268+
// (int)var xx 0 ==> var xx (_Bool)0 or similar
269+
// Note this is restricted to bools because in general turning a widening
270+
// into a narrowing typecast is not correct.
271+
if(lhs.id() == ID_typecast
272+
(lhs.op0().type().id() == ID_bool || lhs.op0().type().id() == ID_c_bool))
273+
{
274+
rhs = typecast_exprt(rhs, lhs.op0().type());
275+
simplify(rhs, ns);
276+
277+
lhs = lhs.op0();
278+
}
279+
280+
if(expr.id() == ID_notequal)
281+
{
282+
if(lhs.type().id() != ID_bool && lhs.type().id() != ID_c_bool)
283+
return;
284+
285+
// x != FALSE ==> x == TRUE
286+
287+
if(rhs.is_zero() || rhs.is_false())
288+
rhs = from_integer(1, rhs.type());
289+
else
290+
rhs = from_integer(0, rhs.type());
291+
292+
two_way_propagate_rec(equal_exprt(lhs, rhs), ns, cp);
293+
}
294+
else // expr.id() == ID_equal
295+
{
296+
assign_rec(values, lhs, rhs, ns, cp);
297+
}
298+
}
270299
}
271300

272301
/// Simplify the condition given context-sensitive knowledge from the abstract

src/analyses/constant_propagator.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -150,7 +150,7 @@ class constant_propagator_domaint:public ai_domain_baset
150150
const namespacet &ns,
151151
const constant_propagator_ait *cp);
152152

153-
bool two_way_propagate_rec(
153+
void two_way_propagate_rec(
154154
const exprt &expr,
155155
const namespacet &ns,
156156
const constant_propagator_ait *cp);

0 commit comments

Comments
 (0)