CBMC
Loading...
Searching...
No Matches
boolbv_get.cpp
Go to the documentation of this file.
1/*******************************************************************\
2
3Module:
4
5Author: 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 <algorithm>
20
21exprt 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 {
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
52exprt boolbvt::get_value(const exprt &expr) const
53{
54 // For non-boolean expressions that were converted to SAT variables,
55 // read the value directly from the SAT model.
56 if(!expr.is_boolean())
57 {
58 auto cache_it = bv_cache.find(expr);
59 if(cache_it != bv_cache.end())
60 return bv_get(cache_it->second, expr.type());
61 }
62
63 // For symbols, get() already reads from the SAT model.
64 if(expr.id() == ID_symbol || expr.id() == ID_nondet_symbol)
65 return get(expr);
66
67 // For booleans, read the propositional value.
68 if(expr.is_boolean())
69 {
70 auto value = get_bool(expr);
71 if(value.has_value())
72 return *value ? static_cast<exprt>(true_exprt()) : false_exprt();
73 }
74
75 // Recursively evaluate operands.
76 exprt tmp = expr;
77 for(auto &op : tmp.operands())
78 {
80 op.swap(tmp_op);
81 }
82 return tmp;
83}
84
85exprt boolbvt::bv_get_rec(const exprt &expr, const bvt &bv, std::size_t offset)
86 const
87{
88 const typet &type = expr.type();
89
90 if(type.id()==ID_bool)
91 {
92 PRECONDITION(bv.size() > offset);
93 // clang-format off
94 switch(prop.l_get(bv[offset]).get_value())
95 {
98 case tvt::tv_enumt::TV_UNKNOWN: return false_exprt(); // default
99 }
100 // clang-format on
101 }
102
104
106 {
107 if(type.id()==ID_array)
108 {
109 const auto &array_type = to_array_type(type);
110
111 if(is_unbounded_array(type))
112 return bv_get_unbounded_array(expr);
113
114 const typet &subtype = array_type.element_type();
115 const auto &sub_width_opt = bv_width.get_width_opt(subtype);
116
117 if(sub_width_opt.has_value() && *sub_width_opt > 0)
118 {
119 const std::size_t width = boolbv_width(type);
120
121 std::size_t sub_width = *sub_width_opt;
122
124 op.reserve(width/sub_width);
125
126 for(std::size_t new_offset=0;
127 new_offset<width;
129 {
130 const index_exprt index{
131 expr,
133 op.push_back(bv_get_rec(index, bv, offset + new_offset));
134 }
135
136 exprt dest=exprt(ID_array, type);
137 dest.operands().swap(op);
138 return dest;
139 }
140 else
141 {
142 return array_exprt{{}, array_type};
143 }
144 }
145 else if(type.id() == ID_struct || type.id() == ID_struct_tag)
146 {
147 const struct_typet::componentst &components =
148 type.id() == ID_struct
149 ? to_struct_type(type).components()
150 : ns.follow_tag(to_struct_tag_type(type)).components();
151 std::size_t new_offset=0;
153 op.reserve(components.size());
154
155 for(const auto &c : components)
156 {
157 const typet &subtype = c.type();
158
159 const member_exprt member{expr, c.get_name(), subtype};
160 op.push_back(bv_get_rec(member, bv, offset + new_offset));
161
162 new_offset += boolbv_width(subtype);
163 }
164
165 return struct_exprt(std::move(op), type);
166 }
167 else if(type.id() == ID_union || type.id() == ID_union_tag)
168 {
169 const union_typet::componentst &components =
170 type.id() == ID_union
171 ? to_union_type(type).components()
172 : ns.follow_tag(to_union_tag_type(type)).components();
173
174 if(components.empty())
175 return empty_union_exprt(type);
176
177 // Any idea that's better than just returning the first component?
178 std::size_t component_nr=0;
179
180 const typet &subtype = components[component_nr].type();
181
182 const member_exprt member{
183 expr, components[component_nr].get_name(), subtype};
184 return union_exprt(
185 components[component_nr].get_name(),
186 bv_get_rec(member, bv, offset),
187 type);
188 }
189 else if(type.id()==ID_complex)
190 {
191 const std::size_t width = boolbv_width(type);
192
193 const typet &subtype = to_complex_type(type).subtype();
194 const std::size_t sub_width = boolbv_width(subtype);
197 width == sub_width * 2,
198 "complex type has two elements of equal bit width");
199
200 return complex_exprt{
203 to_complex_type(type)};
204 }
205 }
206
207 const std::size_t width = boolbv_width(type);
208 PRECONDITION(bv.size() >= offset + width);
209
210 std::string value;
211 value.reserve(width);
212
213 for(std::size_t bit_nr=offset; bit_nr<offset+width; bit_nr++)
214 {
215 char ch = '0';
216 // clang-format off
217 switch(prop.l_get(bv[bit_nr]).get_value())
218 {
219 case tvt::tv_enumt::TV_FALSE: ch = '0'; break;
220 case tvt::tv_enumt::TV_TRUE: ch = '1'; break;
221 case tvt::tv_enumt::TV_UNKNOWN: ch = '0'; break;
222 }
223 // clang-format on
224
225 value += ch;
226 }
227
228 // The above collects bits starting with the least significant bit,
229 // but we need the most significant bit first.
230 std::reverse(value.begin(), value.end());
231
232 switch(bvtype)
233 {
236 type.id() == ID_string || type.id() == ID_empty ||
237 type.id() == ID_enumeration);
238 if(type.id()==ID_string)
239 {
240 mp_integer int_value=binary2integer(value, false);
241 irep_idt s;
243 s=irep_idt();
244 else
246
247 return constant_exprt(s, type);
248 }
249 else if(type.id() == ID_empty)
250 {
251 return constant_exprt{irep_idt(), type};
252 }
253 else if(type.id() == ID_enumeration)
254 {
255 auto &elements = to_enumeration_type(type).elements();
256 mp_integer int_value = binary2integer(value, false);
257 if(int_value >= elements.size())
258 return nil_exprt{};
259 else
260 return constant_exprt{
261 elements[numeric_cast_v<std::size_t>(int_value)].id(), type};
262 }
263 break;
264
266 {
267 mp_integer int_value = binary2integer(value, false);
269
271 break;
272 }
273
282 case bvtypet::IS_BV:
284 {
285 const irep_idt bvrep = make_bvrep(
286 width, [&value](size_t i) { return value[value.size() - i - 1] == '1'; });
287 return constant_exprt(bvrep, type);
288 }
289 }
290
292}
293
294exprt boolbvt::bv_get(const bvt &bv, const typet &type) const
295{
296 nil_exprt skeleton;
297 skeleton.type() = type;
298 return bv_get_rec(skeleton, bv, 0);
299}
300
302{
303 if(expr.is_boolean())
304 return get(expr);
305
306 // look up literals in cache
307 bv_cachet::const_iterator it=bv_cache.find(expr);
308 CHECK_RETURN(it != bv_cache.end());
309
310 return bv_get(it->second, expr.type());
311}
312
314{
315 // first, try to get size
316
317 const typet &type=expr.type();
318 const exprt &size_expr=to_array_type(type).size();
320
321 // get the numeric value, unless it's infinity
322 const auto size_opt = numeric_cast<mp_integer>(size);
323
324 // search array indices, and only use those applicable to a particular model
325 // (array theory may have seen other indices, which might only be live under a
326 // different model)
327
328 typedef std::map<mp_integer, exprt> valuest;
329 valuest values;
330
331 const auto opt_num = arrays.get_number(expr);
332 if(opt_num.has_value())
333 {
334 // get root
335 const auto number = arrays.find_number(*opt_num);
336
337 CHECK_RETURN(number < index_map.size());
338 index_mapt::const_iterator it=index_map.find(number);
339 CHECK_RETURN(it != index_map.end());
340 const index_sett &index_set=it->second;
341
342 for(index_sett::const_iterator it1=
343 index_set.begin();
344 it1!=index_set.end();
345 it1++)
346 {
347 index_exprt index(expr, *it1);
348
349 exprt value=bv_get_cache(index);
351
352 if(!index_value.is_nil())
353 {
355
356 if(
357 index_mpint.has_value() && *index_mpint >= 0 &&
358 (!size_opt.has_value() || *index_mpint < *size_opt))
359 {
360 if(value.is_nil())
361 values[*index_mpint] =
362 exprt(ID_unknown, to_array_type(type).element_type());
363 else
364 values[*index_mpint] = value;
365 }
366 }
367 }
368 }
369
370 exprt result;
371
372 if(!size_opt.has_value() || values.size() != *size_opt)
373 {
374 result = array_list_exprt({}, to_array_type(type));
375
376 result.operands().reserve(values.size()*2);
377
378 for(valuest::const_iterator it=values.begin();
379 it!=values.end();
380 it++)
381 {
382 exprt index=from_integer(it->first, size.type());
383 result.add_to_operands(std::move(index), exprt{it->second});
384 }
385 }
386 else
387 {
388 // set the size
389 result=exprt(ID_array, type);
390
391 // allocate operands
393 result.operands().resize(size_int, exprt{ID_unknown});
394
395 // search uninterpreted functions
396
397 for(valuest::iterator it=values.begin();
398 it!=values.end();
399 it++)
400 {
401 result.operands()[numeric_cast_v<std::size_t>(it->first)].swap(
402 it->second);
403 }
404 }
405
406 return result;
407}
408
410 const bvt &bv,
411 std::size_t offset,
412 std::size_t width)
413{
414 PRECONDITION(offset + width <= bv.size());
415
416 mp_integer value=0;
418
419 for(std::size_t bit_nr=offset; bit_nr<offset+width; bit_nr++)
420 {
421 switch(prop.l_get(bv[bit_nr]).get_value())
422 {
423 case tvt::tv_enumt::TV_FALSE: break;
424 case tvt::tv_enumt::TV_TRUE: value+=weight; break;
425 case tvt::tv_enumt::TV_UNKNOWN: break;
426 default:
428 }
429
430 weight*=2;
431 }
432
433 return value;
434}
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
constant_exprt from_integer(const mp_integer &int_value, const typet &type)
bvtypet get_bvtype(const typet &type)
bvtypet
Definition boolbv_type.h:17
@ IS_VERILOG_UNSIGNED
@ IS_VERILOG_SIGNED
@ IS_C_BIT_FIELD
const union_typet & to_union_type(const typet &type)
Cast a typet to a union_typet.
Definition c_types.h:184
const union_tag_typet & to_union_tag_type(const typet &type)
Cast a typet to a union_tag_typet.
Definition c_types.h:224
ait supplies three of the four components needed: an abstract interpreter (in this case handling func...
Definition ai.h:566
Array constructor from list of elements.
Definition std_expr.h:1560
Array constructor from a list of index-element pairs Operands are index/value pairs,...
Definition std_expr.h:1622
index_mapt index_map
Definition arrays.h:85
const namespacet & ns
Definition arrays.h:56
union_find< exprt, irep_hash > arrays
Definition arrays.h:78
std::set< exprt > index_sett
Definition arrays.h:81
std::optional< std::reference_wrapper< const map_entryt > > get_map_entry(const irep_idt &identifier) const
Definition boolbv_map.h:57
virtual std::optional< std::size_t > get_width_opt(const typet &type) const
bv_cachet bv_cache
Definition boolbv.h:138
bool is_unbounded_array(const typet &type) const override
Definition boolbv.cpp:539
exprt bv_get(const bvt &bv, const typet &type) const
numberingt< irep_idt > string_numbering
Definition boolbv.h:292
virtual exprt bv_get_unbounded_array(const exprt &) const
virtual exprt bv_get_rec(const exprt &expr, const bvt &bv, std::size_t offset) const
boolbv_widtht bv_width
Definition boolbv.h:119
exprt get(const exprt &expr) const override
Return expr with variables replaced by values from satisfying assignment if available.
exprt bv_get_cache(const exprt &expr) const
virtual std::size_t boolbv_width(const typet &type) const
Definition boolbv.h:105
mp_integer get_value(const bvt &bv)
Definition boolbv.h:93
boolbv_mapt map
Definition boolbv.h:126
Complex constructor from a pair of numbers.
Definition std_expr.h:1849
Imaginary part of the expression describing a complex number.
Definition std_expr.h:1947
Real part of the expression describing a complex number.
Definition std_expr.h:1910
A constant literal expression.
Definition std_expr.h:2997
virtual exprt get(const exprt &) const =0
Return expr with variables replaced by values from satisfying assignment if available.
dstringt has one field, an unsigned integer no which is an index into a static table of strings.
Definition dstring.h:38
Union constructor to support unions without any member (a GCC/Clang feature).
Definition std_expr.h:1773
Base class for all expressions.
Definition expr.h:57
std::vector< exprt > operandst
Definition expr.h:59
bool is_boolean() const
Return whether the expression represents a Boolean.
Definition expr.h:229
typet & type()
Return the type of the expression.
Definition expr.h:85
operandst & operands()
Definition expr.h:95
void add_to_operands(const exprt &expr)
Add the given argument to the end of exprt's operands.
Definition expr.h:171
The Boolean constant false.
Definition std_expr.h:3125
Array index operator.
Definition std_expr.h:1421
const irep_idt & get(const irep_idt &name) const
Definition irep.cpp:44
const irep_idt & id() const
Definition irep.h:388
bool is_nil() const
Definition irep.h:368
const std::string & get_string(const irep_idt &name) const
Definition irep.h:401
Extract member of struct or union.
Definition std_expr.h:2856
The NIL expression.
Definition std_expr.h:3134
size_type size() const
Definition numbering.h:66
virtual std::optional< bool > get_bool(const exprt &expr) const
Get a boolean value from the model if the formula is satisfiable.
virtual tvt l_get(literalt a) const =0
Struct constructor from list of elements.
Definition std_expr.h:1810
std::vector< componentt > componentst
Definition std_types.h:140
The Boolean constant true.
Definition std_expr.h:3116
The type of an expression, extends irept.
Definition type.h:29
Union constructor from single element.
Definition std_expr.h:1714
size_type find_number(const_iterator it) const
Definition union_find.h:201
std::optional< number_type > get_number(const T &a) const
Definition union_find.h:263
std::vector< literalt > bvt
Definition literal.h:201
const mp_integer binary2integer(const std::string &n, bool is_signed)
convert binary string representation to mp_integer
Definition mp_arith.cpp:117
const mp_integer string2integer(const std::string &n, unsigned base)
Definition mp_arith.cpp:54
const std::string integer2string(const mp_integer &n, unsigned base)
Definition mp_arith.cpp:103
exprt simplify_expr(exprt src, const namespacet &ns)
BigInt mp_integer
Definition smt_terms.h:17
#define CHECK_RETURN(CONDITION)
Definition invariant.h:495
#define UNREACHABLE
This should be used to mark dead code.
Definition invariant.h:525
#define DATA_INVARIANT(CONDITION, REASON)
This condition should be used to document that assumptions that are made on goto_functions,...
Definition invariant.h:534
#define PRECONDITION(CONDITION)
Definition invariant.h:463
API to expression classes.
const struct_typet & to_struct_type(const typet &type)
Cast a typet to a struct_typet.
Definition std_types.h:308
const enumeration_typet & to_enumeration_type(const typet &type)
Cast a typet to a enumeration_typet.
Definition std_types.h:568
const struct_tag_typet & to_struct_tag_type(const typet &type)
Cast a typet to a struct_tag_typet.
Definition std_types.h:518
const complex_typet & to_complex_type(const typet &type)
Cast a typet to a complex_typet.
Definition std_types.h:1158
const array_typet & to_array_type(const typet &type)
Cast a typet to an array_typet.
Definition std_types.h:888
dstringt irep_idt