CBMC
remove_complex.cpp
Go to the documentation of this file.
1 /*******************************************************************\
2 
3 Module: Remove 'complex' data type
4 
5 Author: Daniel Kroening
6 
7 Date: September 2014
8 
9 \*******************************************************************/
10 
13 
14 #include "remove_complex.h"
15 
16 #include <util/arith_tools.h>
17 #include <util/std_expr.h>
18 
19 #include "goto_model.h"
20 
21 static exprt complex_member(const exprt &expr, irep_idt id)
22 {
23  if(expr.id()==ID_struct && expr.operands().size()==2)
24  {
25  if(id==ID_real)
26  return to_binary_expr(expr).op0();
27  else if(id==ID_imag)
28  return to_binary_expr(expr).op1();
29  else
31  }
32  else
33  {
34  const struct_typet &struct_type=
35  to_struct_type(expr.type());
36  PRECONDITION(struct_type.components().size() == 2);
37  return member_exprt(expr, id, struct_type.components().front().type());
38  }
39 }
40 
41 static bool have_to_remove_complex(const typet &type);
42 
43 static bool have_to_remove_complex(const exprt &expr)
44 {
45  if(expr.id()==ID_typecast &&
46  to_typecast_expr(expr).op().type().id()==ID_complex &&
47  expr.type().id()!=ID_complex)
48  return true;
49 
50  if(expr.type().id()==ID_complex)
51  {
52  if(expr.id()==ID_plus || expr.id()==ID_minus ||
53  expr.id()==ID_mult || expr.id()==ID_div)
54  return true;
55  else if(expr.id()==ID_unary_minus)
56  return true;
57  else if(expr.id()==ID_complex)
58  return true;
59  else if(expr.id()==ID_typecast)
60  return true;
61  }
62 
63  if(expr.id()==ID_complex_real)
64  return true;
65  else if(expr.id()==ID_complex_imag)
66  return true;
67 
68  if(have_to_remove_complex(expr.type()))
69  return true;
70 
71  for(const auto &op : expr.operands())
72  {
74  return true;
75  }
76 
77  return false;
78 }
79 
80 static bool have_to_remove_complex(const typet &type)
81 {
82  if(type.id()==ID_struct || type.id()==ID_union)
83  {
84  for(const auto &c : to_struct_union_type(type).components())
85  if(have_to_remove_complex(c.type()))
86  return true;
87  }
88  else if(type.id()==ID_pointer ||
89  type.id()==ID_vector ||
90  type.id()==ID_array)
91  return have_to_remove_complex(to_type_with_subtype(type).subtype());
92  else if(type.id()==ID_complex)
93  return true;
94 
95  return false;
96 }
97 
99 static void remove_complex(typet &);
100 
101 static void remove_complex(exprt &expr)
102 {
103  if(!have_to_remove_complex(expr))
104  return;
105 
106  if(expr.id()==ID_typecast)
107  {
108  auto const &typecast_expr = to_typecast_expr(expr);
109  if(typecast_expr.op().type().id() == ID_complex)
110  {
111  if(typecast_expr.type().id() == ID_complex)
112  {
113  // complex to complex
114  }
115  else
116  {
117  // cast complex to non-complex is (T)__real__ x
118  complex_real_exprt complex_real_expr(typecast_expr.op());
119 
120  expr = typecast_exprt(complex_real_expr, typecast_expr.type());
121  }
122  }
123  }
124 
125  Forall_operands(it, expr)
126  remove_complex(*it);
127 
128  if(expr.type().id()==ID_complex)
129  {
130  if(expr.id()==ID_plus || expr.id()==ID_minus ||
131  expr.id()==ID_mult || expr.id()==ID_div)
132  {
133  // FIXME plus and mult are defined as n-ary operations
134  // rather than binary. This code assumes that they
135  // can only have exactly 2 operands, and it is not clear
136  // that it is safe to do so in this context
137  PRECONDITION(expr.operands().size() == 2);
138  // do component-wise:
139  // x+y -> complex(x.r+y.r,x.i+y.i)
140  struct_exprt struct_expr(
141  {binary_exprt(
142  complex_member(to_binary_expr(expr).op0(), ID_real),
143  expr.id(),
144  complex_member(to_binary_expr(expr).op1(), ID_real)),
145  binary_exprt(
146  complex_member(to_binary_expr(expr).op0(), ID_imag),
147  expr.id(),
148  complex_member(to_binary_expr(expr).op1(), ID_imag))},
149  expr.type());
150 
151  struct_expr.op0().add_source_location() = expr.source_location();
152  struct_expr.op1().add_source_location()=expr.source_location();
153 
154  expr=struct_expr;
155  }
156  else if(expr.id()==ID_unary_minus)
157  {
158  auto const &unary_minus_expr = to_unary_minus_expr(expr);
159  // do component-wise:
160  // -x -> complex(-x.r,-x.i)
161  struct_exprt struct_expr(
162  {unary_minus_exprt(complex_member(unary_minus_expr.op(), ID_real)),
163  unary_minus_exprt(complex_member(unary_minus_expr.op(), ID_imag))},
164  unary_minus_expr.type());
165 
166  struct_expr.op0().add_source_location() =
167  unary_minus_expr.source_location();
168 
169  struct_expr.op1().add_source_location() =
170  unary_minus_expr.source_location();
171 
172  expr=struct_expr;
173  }
174  else if(expr.id()==ID_complex)
175  {
176  auto const &complex_expr = to_complex_expr(expr);
177  auto struct_expr = struct_exprt(
178  {complex_expr.real(), complex_expr.imag()}, complex_expr.type());
179  struct_expr.add_source_location() = complex_expr.source_location();
180  expr.swap(struct_expr);
181  }
182  else if(expr.id()==ID_typecast)
183  {
184  auto const &typecast_expr = to_typecast_expr(expr);
185  typet subtype = to_complex_type(typecast_expr.type()).subtype();
186 
187  if(typecast_expr.op().type().id() == ID_struct)
188  {
189  // complex to complex -- do typecast per component
190 
191  struct_exprt struct_expr(
192  {typecast_exprt(complex_member(typecast_expr.op(), ID_real), subtype),
194  complex_member(typecast_expr.op(), ID_imag), subtype)},
195  typecast_expr.type());
196 
197  struct_expr.op0().add_source_location() =
198  typecast_expr.source_location();
199 
200  struct_expr.op1().add_source_location() =
201  typecast_expr.source_location();
202 
203  expr=struct_expr;
204  }
205  else
206  {
207  // non-complex to complex
208  struct_exprt struct_expr(
209  {typecast_exprt(typecast_expr.op(), subtype),
210  from_integer(0, subtype)},
211  typecast_expr.type());
212  struct_expr.add_source_location() = typecast_expr.source_location();
213 
214  expr=struct_expr;
215  }
216  }
217  }
218 
219  if(expr.id()==ID_complex_real)
220  {
221  expr = complex_member(to_complex_real_expr(expr).op(), ID_real);
222  }
223  else if(expr.id()==ID_complex_imag)
224  {
225  expr = complex_member(to_complex_imag_expr(expr).op(), ID_imag);
226  }
227 
228  remove_complex(expr.type());
229 }
230 
232 static void remove_complex(typet &type)
233 {
234  if(!have_to_remove_complex(type))
235  return;
236 
237  if(type.id()==ID_struct || type.id()==ID_union)
238  {
239  struct_union_typet &struct_union_type=
240  to_struct_union_type(type);
241  for(struct_union_typet::componentst::iterator
242  it=struct_union_type.components().begin();
243  it!=struct_union_type.components().end();
244  it++)
245  {
246  remove_complex(it->type());
247  }
248  }
249  else if(type.id()==ID_pointer ||
250  type.id()==ID_vector ||
251  type.id()==ID_array)
252  {
253  remove_complex(to_type_with_subtype(type).subtype());
254  }
255  else if(type.id()==ID_complex)
256  {
257  remove_complex(to_complex_type(type).subtype());
258 
259  // Replace by a struct with two members.
260  // The real part goes first.
261  struct_typet struct_type(
262  {{ID_real, to_complex_type(type).subtype()},
263  {ID_imag, to_complex_type(type).subtype()}});
264  struct_type.add_source_location()=type.source_location();
265 
266  type = std::move(struct_type);
267  }
268 }
269 
271 static void remove_complex(symbolt &symbol)
272 {
273  remove_complex(symbol.value);
274  remove_complex(symbol.type);
275 }
276 
278 static void remove_complex(symbol_table_baset &symbol_table)
279 {
280  for(auto it = symbol_table.begin(); it != symbol_table.end(); ++it)
281  remove_complex(it.get_writeable_symbol());
282 }
283 
285 static void remove_complex(
286  goto_functionst::goto_functiont &goto_function)
287 {
288  for(auto &i : goto_function.body.instructions)
289  i.transform([](exprt e) -> std::optional<exprt> {
291  {
292  remove_complex(e);
293  return e;
294  }
295  else
296  return {};
297  });
298 }
299 
301 static void remove_complex(goto_functionst &goto_functions)
302 {
303  for(auto &gf_entry : goto_functions.function_map)
304  remove_complex(gf_entry.second);
305 }
306 
309  symbol_table_baset &symbol_table,
310  goto_functionst &goto_functions)
311 {
312  remove_complex(symbol_table);
313  remove_complex(goto_functions);
314 }
315 
317 void remove_complex(goto_modelt &goto_model)
318 {
319  remove_complex(goto_model.symbol_table, goto_model.goto_functions);
320 }
constant_exprt from_integer(const mp_integer &int_value, const typet &type)
A base class for binary expressions.
Definition: std_expr.h:638
exprt & op1()
Definition: expr.h:136
exprt & op0()
Definition: expr.h:133
Real part of the expression describing a complex number.
Definition: std_expr.h:1979
dstringt has one field, an unsigned integer no which is an index into a static table of strings.
Definition: dstring.h:38
Base class for all expressions.
Definition: expr.h:56
source_locationt & add_source_location()
Definition: expr.h:236
const source_locationt & source_location() const
Definition: expr.h:231
typet & type()
Return the type of the expression.
Definition: expr.h:84
operandst & operands()
Definition: expr.h:94
A collection of goto functions.
function_mapt function_map
::goto_functiont goto_functiont
symbol_tablet symbol_table
Symbol table.
Definition: goto_model.h:31
goto_functionst goto_functions
GOTO functions.
Definition: goto_model.h:34
const irep_idt & id() const
Definition: irep.h:384
void swap(irept &irep)
Definition: irep.h:430
Extract member of struct or union.
Definition: std_expr.h:2841
exprt & op0()
Definition: std_expr.h:932
Struct constructor from list of elements.
Definition: std_expr.h:1872
Structure type, corresponds to C style structs.
Definition: std_types.h:231
Base type for structs and unions.
Definition: std_types.h:62
const componentst & components() const
Definition: std_types.h:147
The symbol table base class interface.
virtual iteratort begin()=0
virtual iteratort end()=0
Symbol table entry.
Definition: symbol.h:28
typet type
Type of symbol.
Definition: symbol.h:31
exprt value
Initial value of symbol.
Definition: symbol.h:34
const typet & subtype() const
Definition: type.h:187
Semantic type conversion.
Definition: std_expr.h:2068
The type of an expression, extends irept.
Definition: type.h:29
const source_locationt & source_location() const
Definition: type.h:72
source_locationt & add_source_location()
Definition: type.h:77
The unary minus expression.
Definition: std_expr.h:484
#define Forall_operands(it, expr)
Definition: expr.h:27
Symbol Table + CFG.
static void remove_complex(typet &)
removes complex data type
static bool have_to_remove_complex(const typet &type)
static exprt complex_member(const exprt &expr, irep_idt id)
Remove the 'complex' data type by compilation into structs.
#define UNREACHABLE
This should be used to mark dead code.
Definition: invariant.h:525
#define PRECONDITION(CONDITION)
Definition: invariant.h:463
API to expression classes.
const typecast_exprt & to_typecast_expr(const exprt &expr)
Cast an exprt to a typecast_exprt.
Definition: std_expr.h:2102
const complex_real_exprt & to_complex_real_expr(const exprt &expr)
Cast an exprt to a complex_real_exprt.
Definition: std_expr.h:2005
const unary_minus_exprt & to_unary_minus_expr(const exprt &expr)
Cast an exprt to a unary_minus_exprt.
Definition: std_expr.h:514
const binary_exprt & to_binary_expr(const exprt &expr)
Cast an exprt to a binary_exprt.
Definition: std_expr.h:715
const complex_exprt & to_complex_expr(const exprt &expr)
Cast an exprt to a complex_exprt.
Definition: std_expr.h:1960
const complex_imag_exprt & to_complex_imag_expr(const exprt &expr)
Cast an exprt to a complex_imag_exprt.
Definition: std_expr.h:2048
const struct_typet & to_struct_type(const typet &type)
Cast a typet to a struct_typet.
Definition: std_types.h:308
const complex_typet & to_complex_type(const typet &type)
Cast a typet to a complex_typet.
Definition: std_types.h:1146
const struct_union_typet & to_struct_union_type(const typet &type)
Cast a typet to a struct_union_typet.
Definition: std_types.h:214
const type_with_subtypet & to_type_with_subtype(const typet &type)
Definition: type.h:208