CBMC
All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Modules Pages
simplify_expr_if.cpp
Go to the documentation of this file.
1/*******************************************************************\
2
3Module:
4
5Author: Daniel Kroening, kroening@kroening.com
6
7\*******************************************************************/
8
10
11#include "arith_tools.h"
12#include "range.h"
13#include "std_expr.h"
14
16 exprt &expr,
17 const exprt &cond,
18 bool truth,
19 bool &new_truth)
20{
21 if(expr == cond)
22 {
24 return false;
25 }
26
27 if(truth && cond.id() == ID_lt && expr.id() == ID_lt)
28 {
29 const auto &cond_lt = to_binary_relation_expr(cond);
30 const auto &expr_lt = to_binary_relation_expr(expr);
31
32 if(
33 cond_lt.op0() == expr_lt.op0() && cond_lt.op1().is_constant() &&
34 expr_lt.op1().is_constant() &&
35 cond_lt.op1().type() == expr_lt.op1().type())
36 {
38
39 if(
42 {
43 if(i1 >= i2)
44 {
45 new_truth = true;
46 return false;
47 }
48 }
49 }
50
51 if(
52 cond_lt.op1() == expr_lt.op1() && cond_lt.op0().is_constant() &&
53 expr_lt.op0().is_constant() &&
54 cond_lt.op0().type() == expr_lt.op0().type())
55 {
57
58 if(
61 {
62 if(i1 <= i2)
63 {
64 new_truth = true;
65 return false;
66 }
67 }
68 }
69 }
70
71 return true;
72}
73
75 exprt &expr,
76 const exprt &cond,
77 bool truth)
78{
79 if(expr.is_boolean())
80 {
81 bool new_truth;
82
83 if(!simplify_if_implies(expr, cond, truth, new_truth))
84 {
85 if(new_truth)
86 {
87 expr = true_exprt();
88 return false;
89 }
90 else
91 {
92 expr = false_exprt();
93 return false;
94 }
95 }
96 }
97
98 bool no_change = true;
99
100 Forall_operands(it, expr)
102
103 return no_change;
104}
105
107{
108 for(const auto &op : cond.operands())
109 {
110 if(expr == op)
111 {
112 expr = true_exprt();
113 return false;
114 }
115 }
116
117 bool no_change = true;
118
119 Forall_operands(it, expr)
120 no_change = simplify_if_conj(*it, cond) && no_change;
121
122 return no_change;
123}
124
126{
127 for(const auto &op : cond.operands())
128 {
129 if(expr == op)
130 {
131 expr = false_exprt();
132 return false;
133 }
134 }
135
136 bool no_change = true;
137
138 Forall_operands(it, expr)
139 no_change = simplify_if_disj(*it, cond) && no_change;
140
141 return no_change;
142}
143
147 const exprt &cond)
148{
149 bool tno_change = true;
150 bool fno_change = true;
151
152 if(cond.id() == ID_and)
153 {
156 }
157 else if(cond.id() == ID_or)
158 {
161 }
162 else
163 {
166 }
167
168 if(!tno_change)
169 trueexpr = simplify_rec(trueexpr); // recursive call
170 if(!fno_change)
171 falseexpr = simplify_rec(falseexpr); // recursive call
172
173 return tno_change && fno_change;
174}
175
177{
178 bool no_change = true;
179 bool tmp = false;
180
181 while(!tmp)
182 {
183 tmp = true;
184
185 if(expr.id() == ID_and)
186 {
187 if(expr.has_operands())
188 {
189 exprt::operandst &operands = expr.operands();
190 for(exprt::operandst::iterator it1 = operands.begin();
191 it1 != operands.end();
192 it1++)
193 {
194 for(exprt::operandst::iterator it2 = operands.begin();
195 it2 != operands.end();
196 it2++)
197 {
198 if(it1 != it2)
199 tmp = simplify_if_recursive(*it1, *it2, true) && tmp;
200 }
201 }
202 }
203 }
204
205 if(!tmp)
206 expr = simplify_rec(expr); // recursive call
207
209 }
210
211 return no_change;
212}
213
215 const if_exprt &expr,
219{
220 if(
221 !cond.has_changed() && !truevalue.has_changed() &&
222 !falsevalue.has_changed())
223 {
226 }
227 else
228 {
229 if_exprt result = expr;
230 if(cond.has_changed())
231 result.cond() = std::move(cond.expr);
232 if(truevalue.has_changed())
233 result.true_case() = std::move(truevalue.expr);
234 if(falsevalue.has_changed())
235 result.false_case() = std::move(falsevalue.expr);
236 return result;
237 }
238}
239
242{
243 const exprt &cond = expr.cond();
244 const exprt &truevalue = expr.true_case();
245 const exprt &falsevalue = expr.false_case();
246
247 // we first want to look at the condition
248 auto r_cond = simplify_rec(cond);
249
250 // 1 ? a : b -> a and 0 ? a : b -> b
251 if(r_cond.expr.is_constant())
252 {
253 return changed(
254 simplify_rec(r_cond.expr.is_true() ? truevalue : falsevalue));
255 }
256
258 {
259 bool swap_branches = false;
260
261 if(r_cond.expr.id() == ID_not)
262 {
263 r_cond = changed(to_not_expr(r_cond.expr).op());
264 swap_branches = true;
265 }
266
267#ifdef USE_LOCAL_REPLACE_MAP
269
270 // a ? b : c --> a ? b[a/true] : c
271 if(r_cond.expr.id() == ID_and)
272 {
273 for(const auto &op : r_cond.expr.operands())
274 {
275 if(op.id() == ID_not)
276 local_replace_map.insert(std::make_pair(op.op0(), false_exprt()));
277 else
278 local_replace_map.insert(std::make_pair(op, true_exprt()));
279 }
280 }
281 else
282 local_replace_map.insert(std::make_pair(r_cond.expr, true_exprt()));
283
285
287
288 // a ? b : c --> a ? b : c[a/false]
289 if(r_cond.expr.id() == ID_or)
290 {
291 for(const auto &op : r_cond.expr.operands())
292 {
293 if(op.id() == ID_not)
294 local_replace_map.insert(std::make_pair(op.op0(), true_exprt()));
295 else
296 local_replace_map.insert(std::make_pair(op, false_exprt()));
297 }
298 }
299 else
300 local_replace_map.insert(std::make_pair(r_cond.expr, false_exprt()));
301
303
305
306 if(swap_branches)
307 {
308 // tell build_if_expr to replace truevalue and falsevalue
309 r_truevalue.expr_changed = CHANGED;
310 r_falsevalue.expr_changed = CHANGED;
311 }
313#else
314 if(!swap_branches)
315 {
316 return build_if_expr(
318 }
319 else
320 {
321 return build_if_expr(
322 expr,
323 r_cond,
326 }
327#endif
328 }
329 else
330 {
331 return build_if_expr(
333 }
334}
335
337{
338 const exprt &cond = expr.cond();
339 const exprt &truevalue = expr.true_case();
340 const exprt &falsevalue = expr.false_case();
341
343 {
344#if 0
347#endif
348
349 if(expr.type() == bool_typet())
350 {
351 // a?b:c <-> (a && b) || (!a && c)
352
353 if(truevalue.is_true() && falsevalue.is_false())
354 {
355 // a?1:0 <-> a
356 return cond;
357 }
358 else if(truevalue.is_false() && falsevalue.is_true())
359 {
360 // a?0:1 <-> !a
361 return changed(simplify_not(not_exprt(cond)));
362 }
363 else if(falsevalue.is_false())
364 {
365 // a?b:0 <-> a AND b
367 }
368 else if(falsevalue.is_true())
369 {
370 // a?b:1 <-> !a OR b
371 return changed(
373 }
374 else if(truevalue.is_true())
375 {
376 // a?1:b <-> a||(!a && b) <-> a OR b
378 }
379 else if(truevalue.is_false())
380 {
381 // a?0:b <-> !a && b
384 }
385 }
386 }
387
388 if(truevalue == falsevalue)
389 return truevalue;
390
391 // this pushes the if-then-else into struct and array constructors
392 if(
393 ((truevalue.id() == ID_struct && falsevalue.id() == ID_struct) ||
394 (truevalue.id() == ID_array && falsevalue.id() == ID_array)) &&
395 truevalue.operands().size() == falsevalue.operands().size())
396 {
397 exprt cond_copy = cond;
400
401 auto range_false = make_range(falsevalue_copy.operands());
402 auto range_true = make_range(truevalue_copy.operands());
403 auto new_expr = truevalue;
404 new_expr.operands().clear();
405
406 for(const auto &pair : range_true.zip(range_false))
407 {
408 new_expr.operands().push_back(
409 simplify_if(if_exprt(cond_copy, pair.first, pair.second)));
410 }
411
412 return std::move(new_expr);
413 }
414
415 return unchanged(expr);
416}
bool to_integer(const constant_exprt &expr, mp_integer &int_value)
Convert a constant expression expr to an arbitrary-precision integer.
virtual void clear()
Reset the abstract state.
Definition ai.h:265
ait supplies three of the four components needed: an abstract interpreter (in this case handling func...
Definition ai.h:562
Boolean AND.
Definition std_expr.h:2125
The Boolean type.
Definition std_types.h:36
Base class for all expressions.
Definition expr.h:56
std::vector< exprt > operandst
Definition expr.h:58
bool has_operands() const
Return true if there is at least one operand.
Definition expr.h:91
bool is_boolean() const
Return whether the expression represents a Boolean.
Definition expr.h:224
typet & type()
Return the type of the expression.
Definition expr.h:84
operandst & operands()
Definition expr.h:94
The Boolean constant false.
Definition std_expr.h:3199
The trinary if-then-else operator.
Definition std_expr.h:2497
exprt & cond()
Definition std_expr.h:2514
exprt & false_case()
Definition std_expr.h:2534
exprt & true_case()
Definition std_expr.h:2524
const irep_idt & id() const
Definition irep.h:388
Boolean negation.
Definition std_expr.h:2454
Boolean OR.
Definition std_expr.h:2270
bool simplify_if_conj(exprt &expr, const exprt &cond)
bool simplify_if_disj(exprt &expr, const exprt &cond)
static resultt changed(resultt<> result)
resultt simplify_if(const if_exprt &)
bool simplify_if_recursive(exprt &expr, const exprt &cond, bool truth)
resultt simplify_rec(const exprt &)
bool simplify_if_cond(exprt &expr)
resultt simplify_boolean(const exprt &)
bool simplify_if_branch(exprt &trueexpr, exprt &falseexpr, const exprt &cond)
resultt simplify_not(const not_exprt &)
static resultt unchanged(exprt expr)
resultt simplify_if_preorder(const if_exprt &expr)
bool simplify_if_implies(exprt &expr, const exprt &cond, bool truth, bool &new_truth)
The Boolean constant true.
Definition std_expr.h:3190
#define Forall_operands(it, expr)
Definition expr.h:27
Ranges: pair of begin and end iterators, which can be initialized from containers,...
ranget< iteratort > make_range(iteratort begin, iteratort end)
Definition range.h:522
std::unordered_map< exprt, exprt, irep_hash > replace_mapt
static simplify_exprt::resultt build_if_expr(const if_exprt &expr, simplify_exprt::resultt<> cond, simplify_exprt::resultt<> truevalue, simplify_exprt::resultt<> falsevalue)
API to expression classes.
const binary_relation_exprt & to_binary_relation_expr(const exprt &expr)
Cast an exprt to a binary_relation_exprt.
Definition std_expr.h:895
const constant_exprt & to_constant_expr(const exprt &expr)
Cast an exprt to a constant_exprt.
Definition std_expr.h:3172
const not_exprt & to_not_expr(const exprt &expr)
Cast an exprt to an not_exprt.
Definition std_expr.h:2479