CBMC
boolbv_get.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 <util/arith_tools.h>
10 #include <util/c_types.h>
11 #include <util/namespace.h>
12 #include <util/simplify_expr.h>
13 #include <util/std_expr.h>
14 #include <util/threeval.h>
15 
16 #include "boolbv.h"
17 #include "boolbv_type.h"
18 
19 #include <iostream>
20 
21 exprt boolbvt::get(const exprt &expr) const
22 {
23  if(expr.id()==ID_symbol ||
24  expr.id()==ID_nondet_symbol)
25  {
26  const irep_idt &identifier=expr.get(ID_identifier);
27 
28  const auto map_entry_opt = map.get_map_entry(identifier);
29 
30  if(map_entry_opt.has_value())
31  {
32  const boolbv_mapt::map_entryt &map_entry = *map_entry_opt;
33  // an input expression must either be untyped (this is used for obtaining
34  // the value of clock symbols, which do not have a fixed type as the clock
35  // type is computed during symbolic execution) or match the type stored in
36  // the mapping
37  if(expr.type() == map_entry.type)
38  return bv_get_rec(expr, map_entry.literal_map, 0);
39  else
40  {
41  PRECONDITION(expr.type() == typet{});
42  exprt skeleton = expr;
43  skeleton.type() = map_entry.type;
44  return bv_get_rec(skeleton, map_entry.literal_map, 0);
45  }
46  }
47  }
48 
49  return SUB::get(expr);
50 }
51 
52 exprt boolbvt::bv_get_rec(const exprt &expr, const bvt &bv, std::size_t offset)
53  const
54 {
55  const typet &type = expr.type();
56 
57  if(type.id()==ID_bool)
58  {
59  PRECONDITION(bv.size() > offset);
60  // clang-format off
61  switch(prop.l_get(bv[offset]).get_value())
62  {
63  case tvt::tv_enumt::TV_FALSE: return false_exprt();
64  case tvt::tv_enumt::TV_TRUE: return true_exprt();
65  case tvt::tv_enumt::TV_UNKNOWN: return false_exprt(); // default
66  }
67  // clang-format on
68  }
69 
70  bvtypet bvtype=get_bvtype(type);
71 
72  if(bvtype==bvtypet::IS_UNKNOWN)
73  {
74  if(type.id()==ID_array)
75  {
76  const auto &array_type = to_array_type(type);
77 
78  if(is_unbounded_array(type))
79  return bv_get_unbounded_array(expr);
80 
81  const typet &subtype = array_type.element_type();
82  const auto &sub_width_opt = bv_width.get_width_opt(subtype);
83 
84  if(sub_width_opt.has_value() && *sub_width_opt > 0)
85  {
86  const std::size_t width = boolbv_width(type);
87 
88  std::size_t sub_width = *sub_width_opt;
89 
91  op.reserve(width/sub_width);
92 
93  for(std::size_t new_offset=0;
94  new_offset<width;
95  new_offset+=sub_width)
96  {
97  const index_exprt index{
98  expr,
99  from_integer(new_offset / sub_width, array_type.index_type())};
100  op.push_back(bv_get_rec(index, bv, offset + new_offset));
101  }
102 
103  exprt dest=exprt(ID_array, type);
104  dest.operands().swap(op);
105  return dest;
106  }
107  else
108  {
109  return array_exprt{{}, array_type};
110  }
111  }
112  else if(type.id() == ID_struct || type.id() == ID_struct_tag)
113  {
114  const struct_typet::componentst &components =
115  type.id() == ID_struct
116  ? to_struct_type(type).components()
118  std::size_t new_offset=0;
119  exprt::operandst op;
120  op.reserve(components.size());
121 
122  for(const auto &c : components)
123  {
124  const typet &subtype = c.type();
125 
126  const member_exprt member{expr, c.get_name(), subtype};
127  op.push_back(bv_get_rec(member, bv, offset + new_offset));
128 
129  new_offset += boolbv_width(subtype);
130  }
131 
132  return struct_exprt(std::move(op), type);
133  }
134  else if(type.id() == ID_union || type.id() == ID_union_tag)
135  {
136  const union_typet::componentst &components =
137  type.id() == ID_union
138  ? to_union_type(type).components()
140 
141  if(components.empty())
142  return empty_union_exprt(type);
143 
144  // Any idea that's better than just returning the first component?
145  std::size_t component_nr=0;
146 
147  const typet &subtype = components[component_nr].type();
148 
149  const member_exprt member{
150  expr, components[component_nr].get_name(), subtype};
151  return union_exprt(
152  components[component_nr].get_name(),
153  bv_get_rec(member, bv, offset),
154  type);
155  }
156  else if(type.id()==ID_vector)
157  {
158  const std::size_t width = boolbv_width(type);
159 
160  const auto &vector_type = to_vector_type(type);
161  const typet &element_type = vector_type.element_type();
162  std::size_t element_width = boolbv_width(element_type);
163  CHECK_RETURN(element_width > 0);
164 
165  if(element_width != 0 && width % element_width == 0)
166  {
167  std::size_t size = width / element_width;
168  vector_exprt value({}, vector_type);
169  value.reserve_operands(size);
170 
171  for(std::size_t i=0; i<size; i++)
172  {
173  const index_exprt index{expr,
174  from_integer(i, vector_type.index_type())};
175  value.operands().push_back(bv_get_rec(index, bv, i * element_width));
176  }
177 
178  return std::move(value);
179  }
180  }
181  else if(type.id()==ID_complex)
182  {
183  const std::size_t width = boolbv_width(type);
184 
185  const typet &subtype = to_complex_type(type).subtype();
186  const std::size_t sub_width = boolbv_width(subtype);
187  CHECK_RETURN(sub_width > 0);
189  width == sub_width * 2,
190  "complex type has two elements of equal bit width");
191 
192  return complex_exprt{
193  bv_get_rec(complex_real_exprt{expr}, bv, 0 * sub_width),
194  bv_get_rec(complex_imag_exprt{expr}, bv, 1 * sub_width),
195  to_complex_type(type)};
196  }
197  }
198 
199  const std::size_t width = boolbv_width(type);
200  PRECONDITION(bv.size() >= offset + width);
201 
202  // most significant bit first
203  std::string value;
204 
205  for(std::size_t bit_nr=offset; bit_nr<offset+width; bit_nr++)
206  {
207  char ch = '0';
208  // clang-format off
209  switch(prop.l_get(bv[bit_nr]).get_value())
210  {
211  case tvt::tv_enumt::TV_FALSE: ch = '0'; break;
212  case tvt::tv_enumt::TV_TRUE: ch = '1'; break;
213  case tvt::tv_enumt::TV_UNKNOWN: ch = '0'; break;
214  }
215  // clang-format on
216 
217  value=ch+value;
218  }
219 
220  switch(bvtype)
221  {
222  case bvtypet::IS_UNKNOWN:
223  PRECONDITION(type.id() == ID_string || type.id() == ID_empty);
224  if(type.id()==ID_string)
225  {
226  mp_integer int_value=binary2integer(value, false);
227  irep_idt s;
228  if(int_value>=string_numbering.size())
229  s=irep_idt();
230  else
231  s = string_numbering[numeric_cast_v<std::size_t>(int_value)];
232 
233  return constant_exprt(s, type);
234  }
235  else if(type.id() == ID_empty)
236  {
237  return constant_exprt{irep_idt(), type};
238  }
239  break;
240 
241  case bvtypet::IS_RANGE:
242  {
243  mp_integer int_value = binary2integer(value, false);
244  mp_integer from = string2integer(type.get_string(ID_from));
245 
246  return constant_exprt(integer2string(int_value + from), type);
247  break;
248  }
249 
253  case bvtypet::IS_C_BOOL:
254  case bvtypet::IS_FIXED:
255  case bvtypet::IS_FLOAT:
257  case bvtypet::IS_SIGNED:
258  case bvtypet::IS_BV:
259  case bvtypet::IS_C_ENUM:
260  {
261  const irep_idt bvrep = make_bvrep(
262  width, [&value](size_t i) { return value[value.size() - i - 1] == '1'; });
263  return constant_exprt(bvrep, type);
264  }
265  }
266 
267  UNREACHABLE;
268 }
269 
270 exprt boolbvt::bv_get(const bvt &bv, const typet &type) const
271 {
272  nil_exprt skeleton;
273  skeleton.type() = type;
274  return bv_get_rec(skeleton, bv, 0);
275 }
276 
278 {
279  if(expr.type().id()==ID_bool) // boolean?
280  return get(expr);
281 
282  // look up literals in cache
283  bv_cachet::const_iterator it=bv_cache.find(expr);
284  CHECK_RETURN(it != bv_cache.end());
285 
286  return bv_get(it->second, expr.type());
287 }
288 
290 {
291  // first, try to get size
292 
293  const typet &type=expr.type();
294  const exprt &size_expr=to_array_type(type).size();
295  exprt size=simplify_expr(get(size_expr), ns);
296 
297  // get the numeric value, unless it's infinity
298  mp_integer size_mpint = 0;
299 
300  if(size.is_not_nil() && size.id() != ID_infinity)
301  {
302  const auto size_opt = numeric_cast<mp_integer>(size);
303  if(size_opt.has_value() && *size_opt >= 0)
304  size_mpint = *size_opt;
305  }
306 
307  // search array indices
308 
309  typedef std::map<mp_integer, exprt> valuest;
310  valuest values;
311 
312  const auto opt_num = arrays.get_number(expr);
313  if(opt_num.has_value())
314  {
315  // get root
316  const auto number = arrays.find_number(*opt_num);
317 
318  assert(number<index_map.size());
319  index_mapt::const_iterator it=index_map.find(number);
320  assert(it!=index_map.end());
321  const index_sett &index_set=it->second;
322 
323  for(index_sett::const_iterator it1=
324  index_set.begin();
325  it1!=index_set.end();
326  it1++)
327  {
328  index_exprt index(expr, *it1);
329 
330  exprt value=bv_get_cache(index);
331  exprt index_value=bv_get_cache(*it1);
332 
333  if(!index_value.is_nil())
334  {
335  const auto index_mpint = numeric_cast<mp_integer>(index_value);
336 
337  if(index_mpint.has_value())
338  {
339  if(value.is_nil())
340  values[*index_mpint] =
341  exprt(ID_unknown, to_array_type(type).subtype());
342  else
343  values[*index_mpint] = value;
344  }
345  }
346  }
347  }
348 
349  exprt result;
350 
351  if(values.size() != size_mpint)
352  {
353  result = array_list_exprt({}, to_array_type(type));
354 
355  result.operands().reserve(values.size()*2);
356 
357  for(valuest::const_iterator it=values.begin();
358  it!=values.end();
359  it++)
360  {
361  exprt index=from_integer(it->first, size.type());
362  result.add_to_operands(std::move(index), exprt{it->second});
363  }
364  }
365  else
366  {
367  // set the size
368  result=exprt(ID_array, type);
369 
370  // allocate operands
371  std::size_t size_int = numeric_cast_v<std::size_t>(size_mpint);
372  result.operands().resize(size_int, exprt{ID_unknown});
373 
374  // search uninterpreted functions
375 
376  for(valuest::iterator it=values.begin();
377  it!=values.end();
378  it++)
379  if(it->first>=0 && it->first<size_mpint)
380  result.operands()[numeric_cast_v<std::size_t>(it->first)].swap(
381  it->second);
382  }
383 
384  return result;
385 }
386 
388  const bvt &bv,
389  std::size_t offset,
390  std::size_t width)
391 {
392  mp_integer value=0;
393  mp_integer weight=1;
394 
395  for(std::size_t bit_nr=offset; bit_nr<offset+width; bit_nr++)
396  {
397  assert(bit_nr<bv.size());
398  switch(prop.l_get(bv[bit_nr]).get_value())
399  {
400  case tvt::tv_enumt::TV_FALSE: break;
401  case tvt::tv_enumt::TV_TRUE: value+=weight; break;
402  case tvt::tv_enumt::TV_UNKNOWN: break;
403  default: assert(false);
404  }
405 
406  weight*=2;
407  }
408 
409  return value;
410 }
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
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
to_union_type
const union_typet & to_union_type(const typet &type)
Cast a typet to a union_typet.
Definition: c_types.h:162
boolbvt::bv_width
boolbv_widtht bv_width
Definition: boolbv.h:116
bvtypet::IS_SIGNED
@ IS_SIGNED
boolbvt::map
boolbv_mapt map
Definition: boolbv.h:123
mp_integer
BigInt mp_integer
Definition: smt_terms.h:17
arith_tools.h
make_bvrep
irep_idt make_bvrep(const std::size_t width, const std::function< bool(std::size_t)> f)
construct a bit-vector representation from a functor
Definition: arith_tools.cpp:306
to_struct_type
const struct_typet & to_struct_type(const typet &type)
Cast a typet to a struct_typet.
Definition: std_types.h:308
boolbvt::is_unbounded_array
bool is_unbounded_array(const typet &type) const override
Definition: boolbv.cpp:518
boolbvt::bv_get_rec
virtual exprt bv_get_rec(const exprt &expr, const bvt &bv, std::size_t offset) const
Definition: boolbv_get.cpp:52
CHECK_RETURN
#define CHECK_RETURN(CONDITION)
Definition: invariant.h:495
typet
The type of an expression, extends irept.
Definition: type.h:28
bvt
std::vector< literalt > bvt
Definition: literal.h:201
threeval.h
arrayst::index_map
index_mapt index_map
Definition: arrays.h:85
bvtypet::IS_FIXED
@ IS_FIXED
bvtypet::IS_C_BIT_FIELD
@ IS_C_BIT_FIELD
string2integer
const mp_integer string2integer(const std::string &n, unsigned base)
Definition: mp_arith.cpp:54
boolbv_mapt::map_entryt::literal_map
bvt literal_map
Definition: boolbv_map.h:33
complex_real_exprt
Real part of the expression describing a complex number.
Definition: std_expr.h:1925
boolbv_type.h
union_exprt
Union constructor from single element.
Definition: std_expr.h:1707
get_bvtype
bvtypet get_bvtype(const typet &type)
Definition: boolbv_type.cpp:13
exprt
Base class for all expressions.
Definition: expr.h:55
struct_union_typet::componentst
std::vector< componentt > componentst
Definition: std_types.h:140
namespace_baset::follow_tag
const union_typet & follow_tag(const union_tag_typet &) const
Follow type tag of union type.
Definition: namespace.cpp:63
bvtypet::IS_VERILOG_SIGNED
@ IS_VERILOG_SIGNED
irep_idt
dstringt irep_idt
Definition: irep.h:37
bvtypet::IS_RANGE
@ IS_RANGE
vector_exprt
Vector constructor from list of elements.
Definition: std_expr.h:1671
bvtypet::IS_UNSIGNED
@ IS_UNSIGNED
to_complex_type
const complex_typet & to_complex_type(const typet &type)
Cast a typet to a complex_typet.
Definition: std_types.h:1102
union_find::get_number
optionalt< number_type > get_number(const T &a) const
Definition: union_find.h:263
namespace.h
boolbv_widtht::get_width_opt
virtual optionalt< std::size_t > get_width_opt(const typet &type) const
Definition: boolbv_width.h:31
bvtypet::IS_BV
@ IS_BV
irept::get
const irep_idt & get(const irep_idt &name) const
Definition: irep.cpp:45
bvtypet
bvtypet
Definition: boolbv_type.h:16
bvtypet::IS_VERILOG_UNSIGNED
@ IS_VERILOG_UNSIGNED
struct_exprt
Struct constructor from list of elements.
Definition: std_expr.h:1818
array_typet::size
const exprt & size() const
Definition: std_types.h:800
boolbv_mapt::map_entryt
Definition: boolbv_map.h:29
exprt::type
typet & type()
Return the type of the expression.
Definition: expr.h:84
irept::is_not_nil
bool is_not_nil() const
Definition: irep.h:380
bvtypet::IS_FLOAT
@ IS_FLOAT
tvt::tv_enumt::TV_TRUE
@ TV_TRUE
union_find::find_number
size_type find_number(const_iterator it) const
Definition: union_find.h:201
boolbvt::bv_cache
bv_cachet bv_cache
Definition: boolbv.h:135
DATA_INVARIANT
#define DATA_INVARIANT(CONDITION, REASON)
This condition should be used to document that assumptions that are made on goto_functions,...
Definition: invariant.h:510
boolbvt::boolbv_width
virtual std::size_t boolbv_width(const typet &type) const
Definition: boolbv.h:102
bvtypet::IS_C_BOOL
@ IS_C_BOOL
PRECONDITION
#define PRECONDITION(CONDITION)
Definition: invariant.h:463
nullary_exprt::operands
operandst & operands()=delete
remove all operand methods
arrayst::ns
const namespacet & ns
Definition: arrays.h:56
nil_exprt
The NIL expression.
Definition: std_expr.h:3025
prop_conv_solvert::get
exprt get(const exprt &expr) const override
Return expr with variables replaced by values from satisfying assignment if available.
Definition: prop_conv_solver.cpp:477
simplify_expr
exprt simplify_expr(exprt src, const namespacet &ns)
Definition: simplify_expr.cpp:2931
arrayst::index_sett
std::set< exprt > index_sett
Definition: arrays.h:81
irept::get_string
const std::string & get_string(const irep_idt &name) const
Definition: irep.h:409
boolbvt::bv_get_cache
exprt bv_get_cache(const exprt &expr) const
Definition: boolbv_get.cpp:277
irept::is_nil
bool is_nil() const
Definition: irep.h:376
irept::id
const irep_idt & id() const
Definition: irep.h:396
empty_union_exprt
Union constructor to support unions without any member (a GCC/Clang feature).
Definition: std_expr.h:1773
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
complex_exprt
Complex constructor from a pair of numbers.
Definition: std_expr.h:1857
false_exprt
The Boolean constant false.
Definition: std_expr.h:3016
boolbvt::get_value
mp_integer get_value(const bvt &bv)
Definition: boolbv.h:90
boolbvt::bv_get_unbounded_array
virtual exprt bv_get_unbounded_array(const exprt &) const
Definition: boolbv_get.cpp:289
boolbv_mapt::get_map_entry
optionalt< std::reference_wrapper< const map_entryt > > get_map_entry(const irep_idt &identifier) const
Definition: boolbv_map.h:57
boolbv_mapt::map_entryt::type
typet type
Definition: boolbv_map.h:32
simplify_expr.h
numberingt::size
size_type size() const
Definition: numbering.h:66
member_exprt
Extract member of struct or union.
Definition: std_expr.h:2793
bvtypet::IS_C_ENUM
@ IS_C_ENUM
propt::l_get
virtual tvt l_get(literalt a) const =0
boolbvt::bv_get
exprt bv_get(const bvt &bv, const typet &type) const
Definition: boolbv_get.cpp:270
from_integer
constant_exprt from_integer(const mp_integer &int_value, const typet &type)
Definition: arith_tools.cpp:100
boolbvt::string_numbering
numberingt< irep_idt > string_numbering
Definition: boolbv.h:277
binary2integer
const mp_integer binary2integer(const std::string &n, bool is_signed)
convert binary string representation to mp_integer
Definition: mp_arith.cpp:117
complex_imag_exprt
Imaginary part of the expression describing a complex number.
Definition: std_expr.h:1970
to_array_type
const array_typet & to_array_type(const typet &type)
Cast a typet to an array_typet.
Definition: std_types.h:844
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
type_with_subtypet::subtype
const typet & subtype() const
Definition: type.h:172
tvt::tv_enumt::TV_UNKNOWN
@ TV_UNKNOWN
to_vector_type
const vector_typet & to_vector_type(const typet &type)
Cast a typet to a vector_typet.
Definition: std_types.h:1060
boolbv.h
array_list_exprt
Array constructor from a list of index-element pairs Operands are index/value pairs,...
Definition: std_expr.h:1618
exprt::operands
operandst & operands()
Definition: expr.h:94
arrayst::arrays
union_find< exprt, irep_hash > arrays
Definition: arrays.h:78
index_exprt
Array index operator.
Definition: std_expr.h:1409
tvt::get_value
tv_enumt get_value() const
Definition: threeval.h:40
true_exprt
The Boolean constant true.
Definition: std_expr.h:3007
constant_exprt
A constant literal expression.
Definition: std_expr.h:2941
exprt::reserve_operands
void reserve_operands(operandst::size_type n)
Definition: expr.h:150
tvt::tv_enumt::TV_FALSE
@ TV_FALSE
std_expr.h
array_exprt
Array constructor from list of elements.
Definition: std_expr.h:1562
c_types.h
boolbvt::get
exprt get(const exprt &expr) const override
Return expr with variables replaced by values from satisfying assignment if available.
Definition: boolbv_get.cpp:21
bvtypet::IS_UNKNOWN
@ IS_UNKNOWN
prop_conv_solvert::prop
propt & prop
Definition: prop_conv_solver.h:130
integer2string
const std::string integer2string(const mp_integer &n, unsigned base)
Definition: mp_arith.cpp:103