Skip to content

Commit d5cf916

Browse files
authored
Merge pull request #4406 from diffblue/non-rec-letify
replace recursion in letify_rec by loop [blocks: #4395]
2 parents ccd30dd + 7ed433f commit d5cf916

File tree

2 files changed

+35
-27
lines changed

2 files changed

+35
-27
lines changed

src/solvers/smt2/letify.cpp

Lines changed: 32 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -19,19 +19,22 @@ void letifyt::collect_bindings(
1919
seen_expressionst &map,
2020
std::vector<exprt> &let_order)
2121
{
22+
// do not letify things with no children
23+
if(expr.operands().empty())
24+
return;
25+
26+
// did we already see the expression?
2227
seen_expressionst::iterator entry = map.find(expr);
2328

2429
if(entry != map.end())
2530
{
31+
// yes, seen before, increase counter
2632
let_count_idt &count_id = entry->second;
2733
++(count_id.count);
2834
return;
2935
}
3036

31-
// do not letify things with no children
32-
if(expr.operands().empty())
33-
return;
34-
37+
// not seen before
3538
for(auto &op : expr.operands())
3639
collect_bindings(op, map, let_order);
3740

@@ -46,26 +49,32 @@ void letifyt::collect_bindings(
4649
let_order.push_back(expr);
4750
}
4851

49-
exprt letifyt::letify_rec(
52+
/// Construct a nested let expression for expressions
53+
/// in let_order that are used more than once
54+
exprt letifyt::letify(
5055
const exprt &expr,
51-
std::vector<exprt> &let_order,
52-
const seen_expressionst &map,
53-
std::size_t i)
56+
const std::vector<exprt> &let_order,
57+
const seen_expressionst &map)
5458
{
55-
if(i >= let_order.size())
56-
return substitute_let(expr, map);
59+
exprt result = substitute_let(expr, map);
5760

58-
exprt current = let_order[i];
59-
INVARIANT(
60-
map.find(current) != map.end(), "expression should have been seen already");
61+
// we build inside out, so go backwards in let order
62+
for(auto r_it = let_order.rbegin(); r_it != let_order.rend(); r_it++)
63+
{
64+
const exprt &current = *r_it;
6165

62-
if(map.find(current)->second.count < LET_COUNT)
63-
return letify_rec(expr, let_order, map, i + 1);
66+
auto m_it = map.find(current);
67+
PRECONDITION(m_it != map.end());
6468

65-
return let_exprt(
66-
map.find(current)->second.let_symbol,
67-
substitute_let(current, map),
68-
letify_rec(expr, let_order, map, i + 1));
69+
// Used more than once? Then a let pays off.
70+
if(m_it->second.count > 1)
71+
{
72+
result = let_exprt(
73+
m_it->second.let_symbol, substitute_let(current, map), result);
74+
}
75+
}
76+
77+
return result;
6978
}
7079

7180
exprt letifyt::operator()(const exprt &expr)
@@ -75,7 +84,7 @@ exprt letifyt::operator()(const exprt &expr)
7584

7685
collect_bindings(expr, map, let_order);
7786

78-
return letify_rec(expr, let_order, map, 0);
87+
return letify(expr, let_order, map);
7988
}
8089

8190
exprt letifyt::substitute_let(const exprt &expr, const seen_expressionst &map)
@@ -89,7 +98,9 @@ exprt letifyt::substitute_let(const exprt &expr, const seen_expressionst &map)
8998
{
9099
op.visit([&map](exprt &expr) {
91100
seen_expressionst::const_iterator it = map.find(expr);
92-
if(it != map.end() && it->second.count >= letifyt::LET_COUNT)
101+
102+
// replace subexpression by let symbol if used more than once
103+
if(it != map.end() && it->second.count > 1)
93104
expr = it->second.let_symbol;
94105
});
95106
}

src/solvers/smt2/letify.h

Lines changed: 3 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -22,8 +22,6 @@ class letifyt
2222
// to produce a fresh ID for each new let
2323
std::size_t let_id_count = 0;
2424

25-
static const std::size_t LET_COUNT = 2;
26-
2725
struct let_count_idt
2826
{
2927
let_count_idt(std::size_t _count, const symbol_exprt &_let_symbol)
@@ -46,11 +44,10 @@ class letifyt
4644
seen_expressionst &map,
4745
std::vector<exprt> &let_order);
4846

49-
static exprt letify_rec(
47+
static exprt letify(
5048
const exprt &expr,
51-
std::vector<exprt> &let_order,
52-
const seen_expressionst &map,
53-
std::size_t i);
49+
const std::vector<exprt> &let_order,
50+
const seen_expressionst &map);
5451

5552
static exprt substitute_let(const exprt &expr, const seen_expressionst &map);
5653
};

0 commit comments

Comments
 (0)