cprover
simplify_expr_array.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 "simplify_expr_class.h"
10 
11 #include "arith_tools.h"
12 #include "byte_operators.h"
13 #include "pointer_offset_size.h"
14 #include "replace_expr.h"
15 #include "std_expr.h"
16 #include "string_constant.h"
17 
20 {
21  bool no_change = true;
22 
23  // copy
24  auto new_expr = expr;
25 
26  // references
27  auto &index = new_expr.index();
28  auto &array = new_expr.array();
29 
30  // extra arithmetic optimizations
31 
32  if(index.id() == ID_div)
33  {
34  const auto &index_div_expr = to_div_expr(index);
35 
36  if(
37  index_div_expr.dividend().id() == ID_mult &&
38  index_div_expr.dividend().operands().size() == 2 &&
39  to_mult_expr(index_div_expr.dividend()).op1() == index_div_expr.divisor())
40  {
41  // this rewrites (a*b)/b to a
42  index = to_mult_expr(index_div_expr.dividend()).op0();
43  no_change = false;
44  }
45  else if(
46  index_div_expr.dividend().id() == ID_mult &&
47  index_div_expr.dividend().operands().size() == 2 &&
48  to_mult_expr(index_div_expr.dividend()).op0() == index_div_expr.divisor())
49  {
50  // this rewrites (a*b)/a to b
51  index = to_mult_expr(index_div_expr.dividend()).op1();
52  no_change = false;
53  }
54  }
55 
56  if(array.id() == ID_array_comprehension)
57  {
58  // simplify (lambda i: e)(x) to e[i/x]
59 
60  const auto &comprehension = to_array_comprehension_expr(array);
61 
62  if(index.type() == comprehension.arg().type())
63  {
64  exprt tmp = comprehension.body();
65  replace_expr(comprehension.arg(), index, tmp);
66  return changed(simplify_rec(tmp));
67  }
68  }
69  else if(array.id()==ID_with)
70  {
71  // we have (a WITH [i:=e])[j]
72 
73  if(array.operands().size() != 3)
74  return unchanged(expr);
75 
76  const auto &with_expr = to_with_expr(array);
77 
78  if(with_expr.where() == index)
79  {
80  // simplify (e with [i:=v])[i] to v
81  return with_expr.new_value();
82  }
83  else
84  {
85  // Turn (a with i:=x)[j] into (i==j)?x:a[j].
86  // watch out that the type of i and j might be different.
87  const exprt rhs_casted =
88  typecast_exprt::conditional_cast(with_expr.where(), index.type());
89 
90  exprt equality_expr = simplify_inequality(equal_exprt(index, rhs_casted));
91 
92  exprt new_index_expr = simplify_index(
93  index_exprt(with_expr.old(), index, new_expr.type())); // recursive call
94 
95  if(equality_expr.is_true())
96  {
97  return with_expr.new_value();
98  }
99  else if(equality_expr.is_false())
100  {
101  return new_index_expr;
102  }
103 
104  if_exprt if_expr(equality_expr, with_expr.new_value(), new_index_expr);
105  return changed(simplify_if(if_expr));
106  }
107  }
108  else if(
109  array.id() == ID_constant || array.id() == ID_array ||
110  array.id() == ID_vector)
111  {
112  const auto i = numeric_cast<mp_integer>(index);
113 
114  if(!i.has_value())
115  {
116  }
117  else if(*i < 0 || *i >= array.operands().size())
118  {
119  // out of bounds
120  }
121  else
122  {
123  // ok
124  return array.operands()[numeric_cast_v<std::size_t>(*i)];
125  }
126  }
127  else if(array.id()==ID_string_constant)
128  {
129  const auto i = numeric_cast<mp_integer>(index);
130 
131  const std::string &value = id2string(to_string_constant(array).get_value());
132 
133  if(!i.has_value())
134  {
135  }
136  else if(*i < 0 || *i > value.size())
137  {
138  // out of bounds
139  }
140  else
141  {
142  // terminating zero?
143  const char v =
144  (*i == value.size()) ? 0 : value[numeric_cast_v<std::size_t>(*i)];
145  return from_integer(v, new_expr.type());
146  }
147  }
148  else if(array.id()==ID_array_of)
149  {
150  return to_array_of_expr(array).what();
151  }
152  else if(array.id() == ID_array_list)
153  {
154  // These are index/value pairs, alternating.
155  for(size_t i=0; i<array.operands().size()/2; i++)
156  {
157  exprt tmp_index = typecast_exprt(array.operands()[i * 2], index.type());
158  simplify(tmp_index);
159  if(tmp_index==index)
160  {
161  return array.operands()[i * 2 + 1];
162  }
163  }
164  }
165  else if(array.id()==ID_byte_extract_little_endian ||
166  array.id()==ID_byte_extract_big_endian)
167  {
168  const auto &byte_extract_expr = to_byte_extract_expr(array);
169 
170  if(array.type().id() == ID_array || array.type().id() == ID_vector)
171  {
172  optionalt<typet> subtype;
173  if(array.type().id() == ID_array)
174  subtype = to_array_type(array.type()).element_type();
175  else
176  subtype = to_vector_type(array.type()).element_type();
177 
178  // This rewrites byte_extract(s, o, array_type)[i]
179  // to byte_extract(s, o+offset, sub_type)
180 
181  auto sub_size = pointer_offset_size(*subtype, ns);
182  if(!sub_size.has_value())
183  return unchanged(expr);
184 
185  // add offset to index
186  exprt offset = simplify_mult(mult_exprt{
187  from_integer(*sub_size, byte_extract_expr.offset().type()), index});
188  exprt final_offset =
189  simplify_plus(plus_exprt(byte_extract_expr.offset(), offset));
190 
191  auto result_expr = byte_extract_expr;
192  result_expr.type() = expr.type();
193  result_expr.offset() = final_offset;
194 
195  return changed(simplify_byte_extract(result_expr));
196  }
197  }
198  else if(array.id()==ID_if)
199  {
200  const if_exprt &if_expr=to_if_expr(array);
201  exprt cond=if_expr.cond();
202 
203  index_exprt idx_false=to_index_expr(expr);
204  idx_false.array()=if_expr.false_case();
205 
206  new_expr.array() = if_expr.true_case();
207 
208  exprt result = if_exprt(cond, new_expr, idx_false, expr.type());
209  return changed(simplify_rec(result));
210  }
211 
212  if(no_change)
213  return unchanged(expr);
214  else
215  return std::move(new_expr);
216 }
constant_exprt from_integer(const mp_integer &int_value, const typet &type)
Definition: arith_tools.cpp:99
Expression classes for byte-level operators.
const byte_extract_exprt & to_byte_extract_expr(const exprt &expr)
exprt & what()
Definition: std_expr.h:1428
const typet & element_type() const
The type of the elements of the array.
Definition: std_types.h:777
Equality.
Definition: std_expr.h:1225
Base class for all expressions.
Definition: expr.h:54
bool is_true() const
Return whether the expression is a constant representing true.
Definition: expr.cpp:33
bool is_false() const
Return whether the expression is a constant representing false.
Definition: expr.cpp:42
typet & type()
Return the type of the expression.
Definition: expr.h:82
The trinary if-then-else operator.
Definition: std_expr.h:2226
exprt & true_case()
Definition: std_expr.h:2253
exprt & false_case()
Definition: std_expr.h:2263
exprt & cond()
Definition: std_expr.h:2243
Array index operator.
Definition: std_expr.h:1328
exprt & array()
Definition: std_expr.h:1353
exprt & index()
Definition: std_expr.h:1363
Binary multiplication Associativity is not specified.
Definition: std_expr.h:1019
exprt & op1()
Definition: std_expr.h:850
exprt & op0()
Definition: std_expr.h:844
The plus expression Associativity is not specified.
Definition: std_expr.h:914
const namespacet & ns
resultt simplify_byte_extract(const byte_extract_exprt &)
static resultt changed(resultt<> result)
resultt simplify_if(const if_exprt &)
resultt simplify_rec(const exprt &)
resultt simplify_mult(const mult_exprt &)
resultt simplify_inequality(const binary_relation_exprt &)
simplifies inequalities !=, <=, <, >=, >, and also ==
resultt simplify_index(const index_exprt &)
static resultt unchanged(exprt expr)
resultt simplify_plus(const plus_exprt &)
virtual bool simplify(exprt &expr)
Semantic type conversion.
Definition: std_expr.h:1920
static exprt conditional_cast(const exprt &expr, const typet &type)
Definition: std_expr.h:1928
const typet & element_type() const
The type of the elements of the vector.
Definition: std_types.h:1006
const std::string & id2string(const irep_idt &d)
Definition: irep.h:47
nonstd::optional< T > optionalt
Definition: optional.h:35
optionalt< mp_integer > pointer_offset_size(const typet &type, const namespacet &ns)
Compute the size of a type in bytes, rounding up to full bytes.
Pointer Logic.
bool replace_expr(const exprt &what, const exprt &by, exprt &dest)
API to expression classes.
const if_exprt & to_if_expr(const exprt &expr)
Cast an exprt to an if_exprt.
Definition: std_expr.h:2291
const array_comprehension_exprt & to_array_comprehension_expr(const exprt &expr)
Cast an exprt to a array_comprehension_exprt.
Definition: std_expr.h:3249
const div_exprt & to_div_expr(const exprt &expr)
Cast an exprt to a div_exprt.
Definition: std_expr.h:1113
const with_exprt & to_with_expr(const exprt &expr)
Cast an exprt to a with_exprt.
Definition: std_expr.h:2374
const array_of_exprt & to_array_of_expr(const exprt &expr)
Cast an exprt to an array_of_exprt.
Definition: std_expr.h:1456
const index_exprt & to_index_expr(const exprt &expr)
Cast an exprt to an index_exprt.
Definition: std_expr.h:1391
const mult_exprt & to_mult_expr(const exprt &expr)
Cast an exprt to a mult_exprt.
Definition: std_expr.h:1044
const vector_typet & to_vector_type(const typet &type)
Cast a typet to a vector_typet.
Definition: std_types.h:1040
const array_typet & to_array_type(const typet &type)
Cast a typet to an array_typet.
Definition: std_types.h:832
const string_constantt & to_string_constant(const exprt &expr)