CBMC
remove_vector.cpp
Go to the documentation of this file.
1 /*******************************************************************\
2 
3 Module: Remove 'vector' data type
4 
5 Author: Daniel Kroening
6 
7 Date: September 2014
8 
9 \*******************************************************************/
10 
13 
14 #include "remove_vector.h"
15 
16 #include <util/arith_tools.h>
17 #include <util/std_expr.h>
18 
19 #include <ansi-c/c_expr.h>
20 
21 #include "goto_model.h"
22 
23 static bool have_to_remove_vector(const typet &type);
24 
25 static bool have_to_remove_vector(const exprt &expr)
26 {
27  if(expr.type().id()==ID_vector)
28  {
29  if(
30  expr.id() == ID_plus || expr.id() == ID_minus || expr.id() == ID_mult ||
31  expr.id() == ID_div || expr.id() == ID_mod || expr.id() == ID_bitxor ||
32  expr.id() == ID_bitand || expr.id() == ID_bitor || expr.id() == ID_shl ||
33  expr.id() == ID_lshr || expr.id() == ID_ashr ||
34  expr.id() == ID_saturating_minus || expr.id() == ID_saturating_plus)
35  {
36  return true;
37  }
38  else if(expr.id()==ID_unary_minus || expr.id()==ID_bitnot)
39  return true;
40  else if(
41  expr.id() == ID_vector_equal || expr.id() == ID_vector_notequal ||
42  expr.id() == ID_vector_lt || expr.id() == ID_vector_le ||
43  expr.id() == ID_vector_gt || expr.id() == ID_vector_ge)
44  {
45  return true;
46  }
47  else if(expr.id() == ID_shuffle_vector)
48  return true;
49  else if(expr.id()==ID_vector)
50  return true;
51  }
52 
53  if(have_to_remove_vector(expr.type()))
54  return true;
55 
56  forall_operands(it, expr)
57  if(have_to_remove_vector(*it))
58  return true;
59 
60  return false;
61 }
62 
63 static bool have_to_remove_vector(const typet &type)
64 {
65  if(type.id()==ID_struct || type.id()==ID_union)
66  {
67  for(const auto &c : to_struct_union_type(type).components())
68  if(have_to_remove_vector(c.type()))
69  return true;
70  }
71  else if(type.id() == ID_code)
72  {
73  const code_typet &code_type = to_code_type(type);
74 
75  if(have_to_remove_vector(code_type.return_type()))
76  return true;
77  for(auto &parameter : code_type.parameters())
78  {
79  if(have_to_remove_vector(parameter.type()))
80  return true;
81  }
82  }
83  else if(type.id()==ID_pointer ||
84  type.id()==ID_complex ||
85  type.id()==ID_array)
86  return have_to_remove_vector(to_type_with_subtype(type).subtype());
87  else if(type.id()==ID_vector)
88  return true;
89 
90  return false;
91 }
92 
94 static void remove_vector(typet &);
95 
96 static void remove_vector(exprt &expr)
97 {
98  if(!have_to_remove_vector(expr))
99  return;
100 
101  if(expr.id() == ID_shuffle_vector)
102  {
103  exprt result = to_shuffle_vector_expr(expr).lower();
104  remove_vector(result);
105  expr.swap(result);
106  return;
107  }
108 
109  Forall_operands(it, expr)
110  remove_vector(*it);
111 
112  if(expr.type().id()==ID_vector)
113  {
114  if(
115  expr.id() == ID_plus || expr.id() == ID_minus || expr.id() == ID_mult ||
116  expr.id() == ID_div || expr.id() == ID_mod || expr.id() == ID_bitxor ||
117  expr.id() == ID_bitand || expr.id() == ID_bitor || expr.id() == ID_shl ||
118  expr.id() == ID_lshr || expr.id() == ID_ashr ||
119  expr.id() == ID_saturating_minus || expr.id() == ID_saturating_plus)
120  {
121  // FIXME plus, mult, bitxor, bitand and bitor are defined as n-ary
122  // operations rather than binary. This code assumes that they
123  // can only have exactly 2 operands, and it is not clear
124  // that it is safe to do so in this context
125  PRECONDITION(expr.operands().size() == 2);
126  auto const &binary_expr = to_binary_expr(expr);
127  remove_vector(expr.type());
128  array_typet array_type=to_array_type(expr.type());
129 
130  const mp_integer dimension =
131  numeric_cast_v<mp_integer>(to_constant_expr(array_type.size()));
132 
133  const typet subtype = array_type.element_type();
134  // do component-wise:
135  // x+y -> vector(x[0]+y[0],x[1]+y[1],...)
136  array_exprt array_expr({}, array_type);
137  array_expr.operands().resize(numeric_cast_v<std::size_t>(dimension));
138  array_expr.add_source_location() = expr.source_location();
139 
140  for(std::size_t i=0; i<array_expr.operands().size(); i++)
141  {
142  exprt index=from_integer(i, array_type.size().type());
143 
144  array_expr.operands()[i] = binary_exprt(
145  index_exprt(binary_expr.op0(), index, subtype),
146  binary_expr.id(),
147  index_exprt(binary_expr.op1(), index, subtype));
148  }
149 
150  expr=array_expr;
151  }
152  else if(expr.id()==ID_unary_minus || expr.id()==ID_bitnot)
153  {
154  auto const &unary_expr = to_unary_expr(expr);
155  remove_vector(expr.type());
156  array_typet array_type=to_array_type(expr.type());
157 
158  const mp_integer dimension =
159  numeric_cast_v<mp_integer>(to_constant_expr(array_type.size()));
160 
161  const typet subtype = array_type.element_type();
162  // do component-wise:
163  // -x -> vector(-x[0],-x[1],...)
164  array_exprt array_expr({}, array_type);
165  array_expr.operands().resize(numeric_cast_v<std::size_t>(dimension));
166  array_expr.add_source_location() = expr.source_location();
167 
168  for(std::size_t i=0; i<array_expr.operands().size(); i++)
169  {
170  exprt index=from_integer(i, array_type.size().type());
171 
172  array_expr.operands()[i] = unary_exprt(
173  unary_expr.id(), index_exprt(unary_expr.op(), index, subtype));
174  }
175 
176  expr=array_expr;
177  }
178  else if(
179  expr.id() == ID_vector_equal || expr.id() == ID_vector_notequal ||
180  expr.id() == ID_vector_lt || expr.id() == ID_vector_le ||
181  expr.id() == ID_vector_gt || expr.id() == ID_vector_ge)
182  {
183  // component-wise and generate 0 (false) or -1 (true)
184  // x ~ y -> vector(x[0] ~ y[0] ? -1 : 0, x[1] ~ y[1] ? -1 : 0, ...)
185 
186  auto const &binary_expr = to_binary_expr(expr);
187  const vector_typet &vector_type = to_vector_type(expr.type());
188  const auto dimension = numeric_cast_v<std::size_t>(vector_type.size());
189 
190  const typet &subtype = vector_type.element_type();
191  PRECONDITION(subtype.id() == ID_signedbv);
192  exprt minus_one = from_integer(-1, subtype);
193  exprt zero = from_integer(0, subtype);
194 
195  exprt::operandst operands;
196  operands.reserve(dimension);
197 
198  const bool is_float =
199  to_array_type(binary_expr.lhs().type()).element_type().id() ==
200  ID_floatbv;
201  irep_idt new_id;
202  if(binary_expr.id() == ID_vector_notequal)
203  {
204  if(is_float)
205  new_id = ID_ieee_float_notequal;
206  else
207  new_id = ID_notequal;
208  }
209  else if(binary_expr.id() == ID_vector_equal)
210  {
211  if(is_float)
212  new_id = ID_ieee_float_equal;
213  else
214  new_id = ID_equal;
215  }
216  else
217  {
218  // just strip the "vector-" prefix
219  new_id = id2string(binary_expr.id()).substr(7);
220  }
221 
222  for(std::size_t i = 0; i < dimension; ++i)
223  {
224  exprt index = from_integer(i, vector_type.size().type());
225 
226  operands.push_back(
227  if_exprt{binary_relation_exprt{index_exprt{binary_expr.lhs(), index},
228  new_id,
229  index_exprt{binary_expr.rhs(), index}},
230  minus_one,
231  zero});
232  }
233 
234  source_locationt source_location = expr.source_location();
235  expr = array_exprt{std::move(operands),
236  array_typet{subtype, vector_type.size()}};
237  expr.add_source_location() = std::move(source_location);
238  }
239  else if(expr.id()==ID_vector)
240  {
241  expr.id(ID_array);
242  }
243  else if(expr.id() == ID_typecast)
244  {
245  const auto &op = to_typecast_expr(expr).op();
246 
247  if(op.type().id() != ID_array)
248  {
249  // (vector-type) x ==> { x, x, ..., x }
250  remove_vector(expr.type());
251  array_typet array_type = to_array_type(expr.type());
252  const auto dimension =
253  numeric_cast_v<std::size_t>(to_constant_expr(array_type.size()));
254  exprt casted_op =
256  source_locationt source_location = expr.source_location();
257  expr = array_exprt(exprt::operandst(dimension, casted_op), array_type);
258  expr.add_source_location() = std::move(source_location);
259  }
260  else if(
261  expr.type().id() == ID_vector &&
262  to_vector_type(expr.type()).size() == to_array_type(op.type()).size())
263  {
264  // do component-wise typecast:
265  // (vector-type) x -> array((vector-sub-type)x[0], ...)
266  remove_vector(expr.type());
267  const array_typet &array_type = to_array_type(expr.type());
268  const std::size_t dimension =
269  numeric_cast_v<std::size_t>(to_constant_expr(array_type.size()));
270  const typet subtype = array_type.element_type();
271 
272  exprt::operandst elements;
273  elements.reserve(dimension);
274 
275  for(std::size_t i = 0; i < dimension; i++)
276  {
277  exprt index = from_integer(i, array_type.size().type());
278  elements.push_back(
279  typecast_exprt{index_exprt{op, std::move(index)}, subtype});
280  }
281 
282  array_exprt array_expr(std::move(elements), array_type);
283  array_expr.add_source_location() = expr.source_location();
284  expr.swap(array_expr);
285  }
286  }
287  }
288 
289  remove_vector(expr.type());
290 }
291 
293 static void remove_vector(typet &type)
294 {
295  if(!have_to_remove_vector(type))
296  return;
297 
298  if(type.id()==ID_struct || type.id()==ID_union)
299  {
300  struct_union_typet &struct_union_type=
301  to_struct_union_type(type);
302 
303  for(struct_union_typet::componentst::iterator
304  it=struct_union_type.components().begin();
305  it!=struct_union_type.components().end();
306  it++)
307  {
308  remove_vector(it->type());
309  }
310  }
311  else if(type.id() == ID_code)
312  {
313  code_typet &code_type = to_code_type(type);
314 
315  remove_vector(code_type.return_type());
316  for(auto &parameter : code_type.parameters())
317  remove_vector(parameter.type());
318  }
319  else if(type.id()==ID_pointer ||
320  type.id()==ID_complex ||
321  type.id()==ID_array)
322  {
323  remove_vector(to_type_with_subtype(type).subtype());
324  }
325  else if(type.id()==ID_vector)
326  {
327  vector_typet &vector_type=to_vector_type(type);
328 
329  remove_vector(vector_type.element_type());
330 
331  // Replace by an array with appropriate number of members.
332  array_typet array_type(vector_type.element_type(), vector_type.size());
333  array_type.add_source_location()=type.source_location();
334  type=array_type;
335  }
336 }
337 
339 static void remove_vector(symbolt &symbol)
340 {
341  remove_vector(symbol.value);
342  remove_vector(symbol.type);
343 }
344 
346 static void remove_vector(symbol_tablet &symbol_table)
347 {
348  for(const auto &named_symbol : symbol_table.symbols)
349  remove_vector(symbol_table.get_writeable_ref(named_symbol.first));
350 }
351 
354 {
355  for(auto &i : goto_function.body.instructions)
356  i.transform([](exprt e) -> optionalt<exprt> {
357  if(have_to_remove_vector(e))
358  {
359  remove_vector(e);
360  return e;
361  }
362  else
363  return {};
364  });
365 }
366 
368 static void remove_vector(goto_functionst &goto_functions)
369 {
370  for(auto &gf_entry : goto_functions.function_map)
371  remove_vector(gf_entry.second);
372 }
373 
376  symbol_tablet &symbol_table,
377  goto_functionst &goto_functions)
378 {
379  remove_vector(symbol_table);
380  remove_vector(goto_functions);
381 }
382 
384 void remove_vector(goto_modelt &goto_model)
385 {
386  remove_vector(goto_model.symbol_table, goto_model.goto_functions);
387 }
struct_union_typet::components
const componentst & components() const
Definition: std_types.h:147
dstringt
dstringt has one field, an unsigned integer no which is an index into a static table of strings.
Definition: dstring.h:36
typecast_exprt::conditional_cast
static exprt conditional_cast(const exprt &expr, const typet &type)
Definition: std_expr.h:2025
symbol_tablet
The symbol table.
Definition: symbol_table.h:13
to_unary_expr
const unary_exprt & to_unary_expr(const exprt &expr)
Cast an exprt to a unary_exprt.
Definition: std_expr.h:361
mp_integer
BigInt mp_integer
Definition: smt_terms.h:17
binary_exprt::rhs
exprt & rhs()
Definition: std_expr.h:623
Forall_operands
#define Forall_operands(it, expr)
Definition: expr.h:27
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
typet
The type of an expression, extends irept.
Definition: type.h:28
struct_union_typet
Base type for structs and unions.
Definition: std_types.h:61
symbolt::type
typet type
Type of symbol.
Definition: symbol.h:31
vector_typet::size
const constant_exprt & size() const
Definition: std_types.cpp:269
if_exprt
The trinary if-then-else operator.
Definition: std_expr.h:2322
to_type_with_subtype
const type_with_subtypet & to_type_with_subtype(const typet &type)
Definition: type.h:193
goto_model.h
exprt
Base class for all expressions.
Definition: expr.h:55
goto_modelt
Definition: goto_model.h:25
binary_exprt::lhs
exprt & lhs()
Definition: std_expr.h:613
unary_exprt
Generic base class for unary expressions.
Definition: std_expr.h:313
binary_exprt
A base class for binary expressions.
Definition: std_expr.h:582
vector_typet
The vector type.
Definition: std_types.h:1007
goto_functionst::function_map
function_mapt function_map
Definition: goto_functions.h:29
to_binary_expr
const binary_exprt & to_binary_expr(const exprt &expr)
Cast an exprt to a binary_exprt.
Definition: std_expr.h:660
remove_vector
static void remove_vector(typet &)
removes vector data type
Definition: remove_vector.cpp:293
array_typet::size
const exprt & size() const
Definition: std_types.h:800
exprt::type
typet & type()
Return the type of the expression.
Definition: expr.h:84
to_code_type
const code_typet & to_code_type(const typet &type)
Cast a typet to a code_typet.
Definition: std_types.h:744
vector_typet::element_type
const typet & element_type() const
The type of the elements of the vector.
Definition: std_types.h:1026
symbol_table_baset::get_writeable_ref
symbolt & get_writeable_ref(const irep_idt &name)
Find a symbol in the symbol table for read-write access.
Definition: symbol_table_base.h:121
id2string
const std::string & id2string(const irep_idt &d)
Definition: irep.h:47
forall_operands
#define forall_operands(it, expr)
Definition: expr.h:20
c_expr.h
PRECONDITION
#define PRECONDITION(CONDITION)
Definition: invariant.h:463
typet::source_location
const source_locationt & source_location() const
Definition: type.h:90
irept::swap
void swap(irept &irep)
Definition: irep.h:442
code_typet
Base type of functions.
Definition: std_types.h:538
to_shuffle_vector_expr
const shuffle_vector_exprt & to_shuffle_vector_expr(const exprt &expr)
Cast an exprt to a shuffle_vector_exprt.
Definition: c_expr.h:92
irept::id
const irep_idt & id() const
Definition: irep.h:396
exprt::operandst
std::vector< exprt > operandst
Definition: expr.h:58
unary_exprt::op
const exprt & op() const
Definition: std_expr.h:326
code_typet::parameters
const parameterst & parameters() const
Definition: std_types.h:655
typet::add_source_location
source_locationt & add_source_location()
Definition: type.h:95
optionalt
nonstd::optional< T > optionalt
Definition: optional.h:35
remove_vector.h
shuffle_vector_exprt::lower
vector_exprt lower() const
Definition: c_expr.cpp:34
source_locationt
Definition: source_location.h:18
goto_functionst::goto_functiont
::goto_functiont goto_functiont
Definition: goto_functions.h:27
goto_functionst
A collection of goto functions.
Definition: goto_functions.h:24
symbolt::value
exprt value
Initial value of symbol.
Definition: symbol.h:34
array_typet
Arrays with given size.
Definition: std_types.h:762
goto_modelt::goto_functions
goto_functionst goto_functions
GOTO functions.
Definition: goto_model.h:33
symbolt
Symbol table entry.
Definition: symbol.h:27
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
symbol_table_baset::symbols
const symbolst & symbols
Read-only field, used to look up symbols given their names.
Definition: symbol_table_base.h:30
binary_relation_exprt
A base class for relations, i.e., binary predicates whose two operands have the same type.
Definition: std_expr.h:706
to_array_type
const array_typet & to_array_type(const typet &type)
Cast a typet to an array_typet.
Definition: std_types.h:844
to_vector_type
const vector_typet & to_vector_type(const typet &type)
Cast a typet to a vector_typet.
Definition: std_types.h:1060
code_typet::return_type
const typet & return_type() const
Definition: std_types.h:645
exprt::operands
operandst & operands()
Definition: expr.h:94
index_exprt
Array index operator.
Definition: std_expr.h:1409
exprt::add_source_location
source_locationt & add_source_location()
Definition: expr.h:216
typecast_exprt
Semantic type conversion.
Definition: std_expr.h:2016
std_expr.h
exprt::source_location
const source_locationt & source_location() const
Definition: expr.h:211
goto_modelt::symbol_table
symbol_tablet symbol_table
Symbol table.
Definition: goto_model.h:30
array_exprt
Array constructor from list of elements.
Definition: std_expr.h:1562
have_to_remove_vector
static bool have_to_remove_vector(const typet &type)
Definition: remove_vector.cpp:63
array_typet::element_type
const typet & element_type() const
The type of the elements of the array.
Definition: std_types.h:785
to_constant_expr
const constant_exprt & to_constant_expr(const exprt &expr)
Cast an exprt to a constant_exprt.
Definition: std_expr.h:2992