CBMC
expr_util.cpp
Go to the documentation of this file.
1 /*******************************************************************\
2 
3 Module:
4 
5 Author: Daniel Kroening, kroening@kroening.com
6 
7 \*******************************************************************/
8 
9 #include "expr_util.h"
10 
11 #include "arith_tools.h"
12 #include "c_types.h"
13 #include "config.h"
14 #include "expr_iterator.h"
15 #include "namespace.h"
16 #include "pointer_expr.h"
17 #include "std_expr.h"
18 
19 #include <algorithm>
20 #include <unordered_set>
21 
22 bool is_assignable(const exprt &expr)
23 {
24  if(expr.id() == ID_index)
25  return is_assignable(to_index_expr(expr).array());
26  else if(expr.id() == ID_member)
27  return is_assignable(to_member_expr(expr).compound());
28  else if(expr.id() == ID_dereference)
29  return true;
30  else if(expr.id() == ID_symbol)
31  return true;
32  else
33  return false;
34 }
35 
36 exprt make_binary(const exprt &expr)
37 {
38  const exprt::operandst &operands=expr.operands();
39 
40  if(operands.size()<=2)
41  return expr;
42 
43  // types must be identical for make_binary to be safe to use
44  const typet &type=expr.type();
45 
46  exprt previous=operands.front();
47  PRECONDITION(previous.type()==type);
48 
49  for(exprt::operandst::const_iterator
50  it=++operands.begin();
51  it!=operands.end();
52  ++it)
53  {
54  PRECONDITION(it->type()==type);
55 
56  exprt tmp=expr;
57  tmp.operands().clear();
58  tmp.operands().resize(2);
59  to_binary_expr(tmp).op0().swap(previous);
60  to_binary_expr(tmp).op1() = *it;
61  previous.swap(tmp);
62  }
63 
64  return previous;
65 }
66 
68 {
69  const exprt::operandst &designator=src.designator();
70  PRECONDITION(!designator.empty());
71 
72  with_exprt result{exprt{}, exprt{}, exprt{}};
73  exprt *dest=&result;
74 
75  for(const auto &expr : designator)
76  {
77  with_exprt tmp{exprt{}, exprt{}, exprt{}};
78 
79  if(expr.id() == ID_index_designator)
80  {
81  tmp.where() = to_index_designator(expr).index();
82  }
83  else if(expr.id() == ID_member_designator)
84  {
85  // irep_idt component_name=
86  // to_member_designator(*it).get_component_name();
87  }
88  else
90 
91  *dest=tmp;
92  dest=&to_with_expr(*dest).new_value();
93  }
94 
95  return result;
96 }
97 
99  const exprt &src,
100  const namespacet &ns)
101 {
102  // We frequently need to check if a numerical type is not zero.
103  // We replace (_Bool)x by x!=0; use ieee_float_notequal for floats.
104  // Note that this returns a proper bool_typet(), not a C/C++ boolean.
105  // To get a C/C++ boolean, add a further typecast.
106 
107  const typet &src_type = src.type().id() == ID_c_enum_tag
108  ? ns.follow_tag(to_c_enum_tag_type(src.type()))
109  : src.type();
110 
111  if(src_type.id()==ID_bool) // already there
112  return src; // do nothing
113 
114  irep_idt id=
115  src_type.id()==ID_floatbv?ID_ieee_float_notequal:ID_notequal;
116 
117  exprt zero=from_integer(0, src_type);
118  // Use tag type if applicable:
119  zero.type() = src.type();
120 
121  binary_relation_exprt comparison(src, id, std::move(zero));
122  comparison.add_source_location()=src.source_location();
123 
124  return std::move(comparison);
125 }
126 
128 {
129  if(src.id() == ID_not)
130  return to_not_expr(src).op();
131  else if(src.is_true())
132  return false_exprt();
133  else if(src.is_false())
134  return true_exprt();
135  else
136  return not_exprt(src);
137 }
138 
140  const exprt &expr,
141  const std::function<bool(const exprt &)> &pred)
142 {
143  const auto it = std::find_if(expr.depth_begin(), expr.depth_end(), pred);
144  return it != expr.depth_end();
145 }
146 
147 bool has_subexpr(const exprt &src, const irep_idt &id)
148 {
149  return has_subexpr(
150  src, [&](const exprt &subexpr) { return subexpr.id() == id; });
151 }
152 
154  const typet &type,
155  const std::function<bool(const typet &)> &pred,
156  const namespacet &ns)
157 {
158  std::vector<std::reference_wrapper<const typet>> stack;
159  std::unordered_set<typet, irep_hash> visited;
160 
161  const auto push_if_not_visited = [&](const typet &t) {
162  if(visited.insert(t).second)
163  stack.emplace_back(t);
164  };
165 
166  push_if_not_visited(type);
167  while(!stack.empty())
168  {
169  const typet &top = stack.back().get();
170  stack.pop_back();
171 
172  if(pred(top))
173  return true;
174  else if(top.id() == ID_c_enum_tag)
175  push_if_not_visited(ns.follow_tag(to_c_enum_tag_type(top)));
176  else if(top.id() == ID_struct_tag)
177  push_if_not_visited(ns.follow_tag(to_struct_tag_type(top)));
178  else if(top.id() == ID_union_tag)
179  push_if_not_visited(ns.follow_tag(to_union_tag_type(top)));
180  else if(top.id() == ID_struct || top.id() == ID_union)
181  {
182  for(const auto &comp : to_struct_union_type(top).components())
183  push_if_not_visited(comp.type());
184  }
185  else
186  {
187  for(const auto &subtype : to_type_with_subtypes(top).subtypes())
188  push_if_not_visited(subtype);
189  }
190  }
191 
192  return false;
193 }
194 
195 bool has_subtype(const typet &type, const irep_idt &id, const namespacet &ns)
196 {
197  return has_subtype(
198  type, [&](const typet &subtype) { return subtype.id() == id; }, ns);
199 }
200 
201 if_exprt lift_if(const exprt &src, std::size_t operand_number)
202 {
203  PRECONDITION(operand_number<src.operands().size());
204  PRECONDITION(src.operands()[operand_number].id()==ID_if);
205 
206  const if_exprt if_expr=to_if_expr(src.operands()[operand_number]);
207  const exprt true_case=if_expr.true_case();
208  const exprt false_case=if_expr.false_case();
209 
210  if_exprt result(if_expr.cond(), src, src);
211  result.true_case().operands()[operand_number]=true_case;
212  result.false_case().operands()[operand_number]=false_case;
213 
214  return result;
215 }
216 
217 const exprt &skip_typecast(const exprt &expr)
218 {
219  if(expr.id()!=ID_typecast)
220  return expr;
221 
222  return skip_typecast(to_typecast_expr(expr).op());
223 }
224 
227 bool is_constantt::is_constant(const exprt &expr) const
228 {
229  if(expr.is_constant())
230  return true;
231 
232  if(expr.id() == ID_address_of)
233  {
234  return is_constant_address_of(to_address_of_expr(expr).object());
235  }
236  else if(
237  expr.id() == ID_typecast || expr.id() == ID_array_of ||
238  expr.id() == ID_plus || expr.id() == ID_mult || expr.id() == ID_array ||
239  expr.id() == ID_with || expr.id() == ID_struct || expr.id() == ID_union ||
240  expr.id() == ID_empty_union ||
241  // byte_update works, byte_extract may be out-of-bounds
242  expr.id() == ID_byte_update_big_endian ||
243  expr.id() == ID_byte_update_little_endian)
244  {
245  return std::all_of(
246  expr.operands().begin(), expr.operands().end(), [this](const exprt &e) {
247  return is_constant(e);
248  });
249  }
250 
251  return false;
252 }
253 
256 {
257  if(expr.id() == ID_symbol)
258  {
259  return true;
260  }
261  else if(expr.id() == ID_index)
262  {
263  const index_exprt &index_expr = to_index_expr(expr);
264 
265  return is_constant_address_of(index_expr.array()) &&
266  is_constant(index_expr.index());
267  }
268  else if(expr.id() == ID_member)
269  {
270  return is_constant_address_of(to_member_expr(expr).compound());
271  }
272  else if(expr.id() == ID_dereference)
273  {
274  const dereference_exprt &deref = to_dereference_expr(expr);
275 
276  return is_constant(deref.pointer());
277  }
278  else if(expr.id() == ID_string_constant)
279  return true;
280 
281  return false;
282 }
283 
285 {
286  if(value)
287  return true_exprt();
288  else
289  return false_exprt();
290 }
291 
293 {
294  PRECONDITION(a.type().id() == ID_bool && b.type().id() == ID_bool);
295  if(b.is_constant())
296  {
297  if(b.get(ID_value) == ID_false)
298  return false_exprt{};
299  return a;
300  }
301  if(a.is_constant())
302  {
303  if(a.get(ID_value) == ID_false)
304  return false_exprt{};
305  return b;
306  }
307  if(b.id() == ID_and)
308  {
309  b.add_to_operands(std::move(a));
310  return b;
311  }
312  return and_exprt{std::move(a), std::move(b)};
313 }
314 
316 {
317  if(expr.type().id() != ID_pointer)
318  return false;
319 
320  if(expr.get_value() == ID_NULL)
321  return true;
322 
323  // We used to support "0" (when NULL_is_zero), but really front-ends should
324  // resolve this and generate ID_NULL instead.
325 #if 0
327 #else
328  INVARIANT(
330  "front-end should use ID_NULL");
331  return false;
332 #endif
333 }
with_exprt
Operator to update elements in structs and arrays.
Definition: std_expr.h:2423
to_union_tag_type
const union_tag_typet & to_union_tag_type(const typet &type)
Cast a typet to a union_tag_typet.
Definition: c_types.h:202
UNREACHABLE
#define UNREACHABLE
This should be used to mark dead code.
Definition: invariant.h:503
dstringt
dstringt has one field, an unsigned integer no which is an index into a static table of strings.
Definition: dstring.h:36
make_and
exprt make_and(exprt a, exprt b)
Conjunction of two expressions.
Definition: expr_util.cpp:292
is_assignable
bool is_assignable(const exprt &expr)
Returns true iff the argument is one of the following:
Definition: expr_util.cpp:22
configt::ansi_ct::NULL_is_zero
bool NULL_is_zero
Definition: config.h:209
skip_typecast
const exprt & skip_typecast(const exprt &expr)
find the expression nested inside typecasts, if any
Definition: expr_util.cpp:217
has_subexpr
bool has_subexpr(const exprt &expr, const std::function< bool(const exprt &)> &pred)
returns true if the expression has a subexpression that satisfies pred
Definition: expr_util.cpp:139
exprt::depth_end
depth_iteratort depth_end()
Definition: expr.cpp:267
arith_tools.h
to_struct_union_type
const struct_union_typet & to_struct_union_type(const typet &type)
Cast a typet to a struct_union_typet.
Definition: std_types.h:214
to_dereference_expr
const dereference_exprt & to_dereference_expr(const exprt &expr)
Cast an exprt to a dereference_exprt.
Definition: pointer_expr.h:716
typet
The type of an expression, extends irept.
Definition: type.h:28
to_index_expr
const index_exprt & to_index_expr(const exprt &expr)
Cast an exprt to an index_exprt.
Definition: std_expr.h:1478
to_if_expr
const if_exprt & to_if_expr(const exprt &expr)
Cast an exprt to an if_exprt.
Definition: std_expr.h:2403
dereference_exprt
Operator to dereference a pointer.
Definition: pointer_expr.h:659
if_exprt
The trinary if-then-else operator.
Definition: std_expr.h:2322
is_constantt::is_constant_address_of
virtual bool is_constant_address_of(const exprt &) const
this function determines which reference-typed expressions are constant
Definition: expr_util.cpp:255
with_exprt::new_value
exprt & new_value()
Definition: std_expr.h:2454
and_exprt
Boolean AND.
Definition: std_expr.h:2070
to_type_with_subtypes
const type_with_subtypest & to_type_with_subtypes(const typet &type)
Definition: type.h:237
exprt
Base class for all expressions.
Definition: expr.h:55
namespace_baset::follow_tag
const union_typet & follow_tag(const union_tag_typet &) const
Follow type tag of union type.
Definition: namespace.cpp:63
lift_if
if_exprt lift_if(const exprt &src, std::size_t operand_number)
lift up an if_exprt one level
Definition: expr_util.cpp:201
exprt::is_true
bool is_true() const
Return whether the expression is a constant representing true.
Definition: expr.cpp:34
configt::ansi_c
struct configt::ansi_ct ansi_c
make_binary
exprt make_binary(const exprt &expr)
splits an expression with >=3 operands into nested binary expressions
Definition: expr_util.cpp:36
namespace.h
if_exprt::false_case
exprt & false_case()
Definition: std_expr.h:2360
exprt::is_false
bool is_false() const
Return whether the expression is a constant representing false.
Definition: expr.cpp:43
irept::get
const irep_idt & get(const irep_idt &name) const
Definition: irep.cpp:45
to_binary_expr
const binary_exprt & to_binary_expr(const exprt &expr)
Cast an exprt to a binary_exprt.
Definition: std_expr.h:660
namespacet
A namespacet is essentially one or two symbol tables bound together, to allow for symbol lookups in t...
Definition: namespace.h:90
is_constantt::is_constant
virtual bool is_constant(const exprt &) const
This function determines what expressions are to be propagated as "constants".
Definition: expr_util.cpp:227
exprt::type
typet & type()
Return the type of the expression.
Definition: expr.h:84
to_c_enum_tag_type
const c_enum_tag_typet & to_c_enum_tag_type(const typet &type)
Cast a typet to a c_enum_tag_typet.
Definition: c_types.h:344
PRECONDITION
#define PRECONDITION(CONDITION)
Definition: invariant.h:463
has_subtype
bool has_subtype(const typet &type, const std::function< bool(const typet &)> &pred, const namespacet &ns)
returns true if any of the contained types satisfies pred
Definition: expr_util.cpp:153
dereference_exprt::pointer
exprt & pointer()
Definition: pointer_expr.h:673
boolean_negate
exprt boolean_negate(const exprt &src)
negate a Boolean expression, possibly removing a not_exprt, and swapping false and true
Definition: expr_util.cpp:127
index_designatort::index
const exprt & index() const
Definition: std_expr.h:2511
pointer_expr.h
index_exprt::index
exprt & index()
Definition: std_expr.h:1450
index_exprt::array
exprt & array()
Definition: std_expr.h:1440
irept::swap
void swap(irept &irep)
Definition: irep.h:442
irept::id
const irep_idt & id() const
Definition: irep.h:396
to_struct_tag_type
const struct_tag_typet & to_struct_tag_type(const typet &type)
Cast a typet to a struct_tag_typet.
Definition: std_types.h:474
exprt::operandst
std::vector< exprt > operandst
Definition: expr.h:58
false_exprt
The Boolean constant false.
Definition: std_expr.h:3016
unary_exprt::op
const exprt & op() const
Definition: std_expr.h:326
to_with_expr
const with_exprt & to_with_expr(const exprt &expr)
Cast an exprt to a with_exprt.
Definition: std_expr.h:2486
update_exprt
Operator to update elements in structs and arrays.
Definition: std_expr.h:2607
update_exprt::designator
exprt::operandst & designator()
Definition: std_expr.h:2634
config
configt config
Definition: config.cpp:25
expr_util.h
Deprecated expression utility functions.
expr_iterator.h
if_exprt::true_case
exprt & true_case()
Definition: std_expr.h:2350
to_not_expr
const not_exprt & to_not_expr(const exprt &expr)
Cast an exprt to an not_exprt.
Definition: std_expr.h:2303
is_not_zero
exprt is_not_zero(const exprt &src, const namespacet &ns)
converts a scalar/float expression to C/C++ Booleans
Definition: expr_util.cpp:98
constant_exprt::value_is_zero_string
bool value_is_zero_string() const
Definition: std_expr.cpp:17
exprt::depth_begin
depth_iteratort depth_begin()
Definition: expr.cpp:265
from_integer
constant_exprt from_integer(const mp_integer &int_value, const typet &type)
Definition: arith_tools.cpp:100
to_typecast_expr
const typecast_exprt & to_typecast_expr(const exprt &expr)
Cast an exprt to a typecast_exprt.
Definition: std_expr.h:2051
exprt::is_constant
bool is_constant() const
Return whether the expression is a constant.
Definition: expr.cpp:27
if_exprt::cond
exprt & cond()
Definition: std_expr.h:2340
binary_relation_exprt
A base class for relations, i.e., binary predicates whose two operands have the same type.
Definition: std_expr.h:706
exprt::add_to_operands
void add_to_operands(const exprt &expr)
Add the given argument to the end of exprt's operands.
Definition: expr.h:162
config.h
to_member_expr
const member_exprt & to_member_expr(const exprt &expr)
Cast an exprt to a member_exprt.
Definition: std_expr.h:2886
make_boolean_expr
constant_exprt make_boolean_expr(bool value)
returns true_exprt if given true and false_exprt otherwise
Definition: expr_util.cpp:284
make_with_expr
with_exprt make_with_expr(const update_exprt &src)
converts an update expr into a (possibly nested) with expression
Definition: expr_util.cpp:67
to_address_of_expr
const address_of_exprt & to_address_of_expr(const exprt &expr)
Cast an exprt to an address_of_exprt.
Definition: pointer_expr.h:408
exprt::operands
operandst & operands()
Definition: expr.h:94
is_null_pointer
bool is_null_pointer(const constant_exprt &expr)
Returns true if expr has a pointer type and a value NULL; it also returns true when expr has value ze...
Definition: expr_util.cpp:315
index_exprt
Array index operator.
Definition: std_expr.h:1409
INVARIANT
#define INVARIANT(CONDITION, REASON)
This macro uses the wrapper function 'invariant_violated_string'.
Definition: invariant.h:423
exprt::add_source_location
source_locationt & add_source_location()
Definition: expr.h:216
true_exprt
The Boolean constant true.
Definition: std_expr.h:3007
constant_exprt
A constant literal expression.
Definition: std_expr.h:2941
binary_exprt::op1
exprt & op1()
Definition: expr.h:128
std_expr.h
constant_exprt::get_value
const irep_idt & get_value() const
Definition: std_expr.h:2950
exprt::source_location
const source_locationt & source_location() const
Definition: expr.h:211
c_types.h
binary_exprt::op0
exprt & op0()
Definition: expr.h:125
to_index_designator
const index_designatort & to_index_designator(const exprt &expr)
Cast an exprt to an index_designatort.
Definition: std_expr.h:2539
not_exprt
Boolean negation.
Definition: std_expr.h:2277