Skip to content

Conditionally simplify use of if-then-else conditions #8042

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 1 commit into
base: develop
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 16 additions & 0 deletions regression/cbmc/Pointer32/main.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
struct S
{
int len;
};

__CPROVER_bool nondet_bool();

int main()
{
struct S *s_p = 0;
struct S s;
if(nondet_bool())
s_p = &s;
s_p->len = s_p->len + 1;
__CPROVER_assert(0, "");
}
12 changes: 12 additions & 0 deletions regression/cbmc/Pointer32/test.desc
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
CORE paths-lifo-expected-failure
main.c
--show-vcc
main::1::s!0@1#2..len = .+ \? .+ : .+
^SIGNAL=0$
^EXIT=0$
--
main::1::s!0@1#2..len = .+ \? .+ \?
--
We should not find nested if-then-else expressions in the right-hand side
evaluating `len` when simplification works as intended. (With --paths lifo we do
not have any branching, so it is marked paths-lifo-expected-failure.)
6 changes: 5 additions & 1 deletion src/goto-symex/symex_assign.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ Author: Daniel Kroening, kroening@kroening.com
/// Symbolic Execution

#include "symex_assign.h"
#include <util/simplify_expr_class.h>

#include <util/byte_operators.h>
#include <util/expr_util.h>
Expand Down Expand Up @@ -203,7 +204,10 @@ void symex_assignt::assign_non_struct_symbol(
assignmentt assignment{lhs, full_lhs, l2_rhs};

if(symex_config.simplify_opt)
assignment.rhs = simplify_expr(std::move(assignment.rhs), ns);
{
simplify_exprt simp{ns, true};
simp.simplify(assignment.rhs);
}

const ssa_exprt l2_lhs = state
.assignment(
Expand Down
17 changes: 8 additions & 9 deletions src/util/simplify_expr.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3169,22 +3169,21 @@ simplify_exprt::resultt<> simplify_exprt::simplify_rec(const exprt &expr)
simplify_node_preorder_result.expr_changed;
}

#ifdef USE_LOCAL_REPLACE_MAP
exprt tmp = simplify_node_result.expr;
# if 1
replace_mapt::const_iterator it =
local_replace_map.find(simplify_node_result.expr);
if(it!=local_replace_map.end())
simplify_node_result = changed(it->second);
if(!local_replace_map.empty())
{
#if 1
replace_mapt::const_iterator it =
local_replace_map.find(simplify_node_result.expr);
if(it != local_replace_map.end())
simplify_node_result = changed(it->second);
# else
if(
!local_replace_map.empty() &&
!replace_expr(local_replace_map, simplify_node_result.expr))
{
simplify_node_result = changed(simplify_rec(simplify_node_result.expr));
}
# endif
#endif
}

if(!simplify_node_result.has_changed())
{
Expand Down
19 changes: 9 additions & 10 deletions src/util/simplify_expr_class.h
Original file line number Diff line number Diff line change
Expand Up @@ -20,10 +20,7 @@ Author: Daniel Kroening, kroening@kroening.com
#include "expr.h"
#include "mp_arith.h"
#include "type.h"
// #define USE_LOCAL_REPLACE_MAP
#ifdef USE_LOCAL_REPLACE_MAP
#include "replace_expr.h"
#endif

class abs_exprt;
class address_of_exprt;
Expand Down Expand Up @@ -80,11 +77,12 @@ class with_exprt;
class simplify_exprt
{
public:
explicit simplify_exprt(const namespacet &_ns):
do_simplify_if(true),
ns(_ns)
simplify_exprt(const namespacet &_ns, bool propagate_if_cond)
: do_simplify_if(propagate_if_cond),
ns(_ns)
#ifdef DEBUG_ON_DEMAND
, debug_on(false)
,
debug_on(false)
#endif
{
#ifdef DEBUG_ON_DEMAND
Expand All @@ -93,6 +91,10 @@ class simplify_exprt
#endif
}

explicit simplify_exprt(const namespacet &_ns) : simplify_exprt(_ns, false)
{
}

virtual ~simplify_exprt()
{
}
Expand Down Expand Up @@ -287,10 +289,7 @@ class simplify_exprt
#ifdef DEBUG_ON_DEMAND
bool debug_on;
#endif
#ifdef USE_LOCAL_REPLACE_MAP
replace_mapt local_replace_map;
#endif

};

#endif // CPROVER_UTIL_SIMPLIFY_EXPR_CLASS_H
116 changes: 57 additions & 59 deletions src/util/simplify_expr_if.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -254,17 +254,16 @@ simplify_exprt::simplify_if_preorder(const if_exprt &expr)
simplify_rec(r_cond.expr.is_true() ? truevalue : falsevalue));
}

if(do_simplify_if)
{
bool swap_branches = false;
bool swap_branches = false;

if(r_cond.expr.id() == ID_not)
{
r_cond = changed(to_not_expr(r_cond.expr).op());
swap_branches = true;
}
if(r_cond.expr.id() == ID_not)
{
r_cond = changed(to_not_expr(r_cond.expr).op());
swap_branches = true;
}

#ifdef USE_LOCAL_REPLACE_MAP
if(do_simplify_if)
{
replace_mapt map_before(local_replace_map);

// a ? b : c --> a ? b[a/true] : c
Expand All @@ -273,7 +272,10 @@ simplify_exprt::simplify_if_preorder(const if_exprt &expr)
for(const auto &op : r_cond.expr.operands())
{
if(op.id() == ID_not)
local_replace_map.insert(std::make_pair(op.op0(), false_exprt()));
{
local_replace_map.insert(
std::make_pair(to_not_expr(op).op(), false_exprt()));
}
else
local_replace_map.insert(std::make_pair(op, true_exprt()));
}
Expand All @@ -291,7 +293,10 @@ simplify_exprt::simplify_if_preorder(const if_exprt &expr)
for(const auto &op : r_cond.expr.operands())
{
if(op.id() == ID_not)
local_replace_map.insert(std::make_pair(op.op0(), true_exprt()));
{
local_replace_map.insert(
std::make_pair(to_not_expr(op).op(), true_exprt()));
}
else
local_replace_map.insert(std::make_pair(op, false_exprt()));
}
Expand All @@ -306,11 +311,13 @@ simplify_exprt::simplify_if_preorder(const if_exprt &expr)
if(swap_branches)
{
// tell build_if_expr to replace truevalue and falsevalue
r_truevalue.expr_changed = CHANGED;
r_falsevalue.expr_changed = CHANGED;
r_truevalue.expr_changed = resultt<>::CHANGED;
r_falsevalue.expr_changed = resultt<>::CHANGED;
}
return build_if_expr(expr, r_cond, r_truevalue, r_falsevalue);
#else
}
else
{
if(!swap_branches)
{
return build_if_expr(
Expand All @@ -324,12 +331,6 @@ simplify_exprt::simplify_if_preorder(const if_exprt &expr)
changed(simplify_rec(falsevalue)),
changed(simplify_rec(truevalue)));
}
#endif
}
else
{
return build_if_expr(
expr, r_cond, simplify_rec(truevalue), simplify_rec(falsevalue));
}
}

Expand All @@ -339,49 +340,46 @@ simplify_exprt::resultt<> simplify_exprt::simplify_if(const if_exprt &expr)
const exprt &truevalue = expr.true_case();
const exprt &falsevalue = expr.false_case();

if(do_simplify_if)
{
#if 0
no_change = simplify_if_cond(cond) && no_change;
no_change = simplify_if_branch(truevalue, falsevalue, cond) && no_change;
no_change = simplify_if_cond(cond) && no_change;
no_change = simplify_if_branch(truevalue, falsevalue, cond) && no_change;
#endif

if(expr.type() == bool_typet())
{
// a?b:c <-> (a && b) || (!a && c)
if(expr.type() == bool_typet())
{
// a?b:c <-> (a && b) || (!a && c)

if(truevalue.is_true() && falsevalue.is_false())
{
// a?1:0 <-> a
return cond;
}
else if(truevalue.is_false() && falsevalue.is_true())
{
// a?0:1 <-> !a
return changed(simplify_not(not_exprt(cond)));
}
else if(falsevalue.is_false())
{
// a?b:0 <-> a AND b
return changed(simplify_boolean(and_exprt(cond, truevalue)));
}
else if(falsevalue.is_true())
{
// a?b:1 <-> !a OR b
return changed(
simplify_boolean(or_exprt(simplify_not(not_exprt(cond)), truevalue)));
}
else if(truevalue.is_true())
{
// a?1:b <-> a||(!a && b) <-> a OR b
return changed(simplify_boolean(or_exprt(cond, falsevalue)));
}
else if(truevalue.is_false())
{
// a?0:b <-> !a && b
return changed(simplify_boolean(
and_exprt(simplify_not(not_exprt(cond)), falsevalue)));
}
if(truevalue.is_true() && falsevalue.is_false())
{
// a?1:0 <-> a
return cond;
}
else if(truevalue.is_false() && falsevalue.is_true())
{
// a?0:1 <-> !a
return changed(simplify_not(not_exprt(cond)));
}
else if(falsevalue.is_false())
{
// a?b:0 <-> a AND b
return changed(simplify_boolean(and_exprt(cond, truevalue)));
}
else if(falsevalue.is_true())
{
// a?b:1 <-> !a OR b
return changed(
simplify_boolean(or_exprt(simplify_not(not_exprt(cond)), truevalue)));
}
else if(truevalue.is_true())
{
// a?1:b <-> a||(!a && b) <-> a OR b
return changed(simplify_boolean(or_exprt(cond, falsevalue)));
}
else if(truevalue.is_false())
{
// a?0:b <-> !a && b
return changed(
simplify_boolean(and_exprt(simplify_not(not_exprt(cond)), falsevalue)));
}
}

Expand Down
Loading