CBMC
boolbv_with.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/bitvector_expr.h>
11 #include <util/c_types.h>
12 #include <util/namespace.h>
13 #include <util/std_expr.h>
14 
15 #include "boolbv.h"
16 
18 {
19  auto &type = expr.type();
20 
21  if(
22  type.id() == ID_bv || type.id() == ID_unsignedbv ||
23  type.id() == ID_signedbv)
24  {
25  if(expr.operands().size() > 3)
26  {
27  std::size_t s = expr.operands().size();
28 
29  // strip off the trailing two operands
30  with_exprt tmp = expr;
31  tmp.operands().resize(s - 2);
32 
33  with_exprt new_with_expr(
34  tmp, expr.operands()[s - 2], expr.operands().back());
35 
36  // recursive call
37  return convert_with(new_with_expr);
38  }
39 
40  PRECONDITION(expr.operands().size() == 3);
41  if(expr.new_value().type().id() == ID_bool)
42  {
43  return convert_bv(
44  update_bit_exprt(expr.old(), expr.where(), expr.new_value()));
45  }
46  else
47  {
48  return convert_bv(
49  update_bits_exprt(expr.old(), expr.where(), expr.new_value()));
50  }
51  }
52 
53  bvt bv = convert_bv(expr.old());
54 
55  std::size_t width = boolbv_width(type);
56 
57  if(width==0)
58  {
59  // A zero-length array is acceptable:
60  return bvt{};
61  }
62 
64  bv.size() == width,
65  "unexpected operand 0 width",
67 
68  bvt prev_bv;
69  prev_bv.resize(width);
70 
71  const exprt::operandst &ops=expr.operands();
72 
73  for(std::size_t op_no=1; op_no<ops.size(); op_no+=2)
74  {
75  bv.swap(prev_bv);
76 
77  convert_with(expr.old().type(), ops[op_no], ops[op_no + 1], prev_bv, bv);
78  }
79 
80  return bv;
81 }
82 
84  const typet &type,
85  const exprt &where,
86  const exprt &new_value,
87  const bvt &prev_bv,
88  bvt &next_bv)
89 {
90  // we only do that on arrays, bitvectors, structs, and unions
91 
92  next_bv.resize(prev_bv.size());
93 
94  if(type.id()==ID_array)
95  return convert_with_array(
96  to_array_type(type), where, new_value, prev_bv, next_bv);
97  else if(type.id()==ID_bv ||
98  type.id()==ID_unsignedbv ||
99  type.id()==ID_signedbv)
100  {
101  // already done
102  PRECONDITION(false);
103  }
104  else if(type.id()==ID_struct)
105  return convert_with_struct(
106  to_struct_type(type), where, new_value, prev_bv, next_bv);
107  else if(type.id() == ID_struct_tag)
108  return convert_with(
110  where,
111  new_value,
112  prev_bv,
113  next_bv);
114  else if(type.id()==ID_union)
115  return convert_with_union(to_union_type(type), new_value, prev_bv, next_bv);
116  else if(type.id() == ID_union_tag)
117  return convert_with(
119  where,
120  new_value,
121  prev_bv,
122  next_bv);
123 
125  false, "unexpected with type", irep_pretty_diagnosticst{type});
126 }
127 
129  const array_typet &type,
130  const exprt &index,
131  const exprt &new_value,
132  const bvt &prev_bv,
133  bvt &next_bv)
134 {
135  // can't do this
137  !is_unbounded_array(type),
138  "convert_with_array called for unbounded array",
140 
141  const exprt &array_size=type.size();
142 
143  const auto size = numeric_cast<mp_integer>(array_size);
144 
146  size.has_value(),
147  "convert_with_array expects constant array size",
149 
150  const bvt &new_value_bv = convert_bv(new_value);
151 
153  *size * new_value_bv.size() == prev_bv.size(),
154  "convert_with_array: unexpected new_value operand width",
156 
157  // Is the index a constant?
158  if(const auto index_value_opt = numeric_cast<mp_integer>(index))
159  {
160  // Yes, it is!
161  next_bv=prev_bv;
162 
163  if(*index_value_opt >= 0 && *index_value_opt < *size) // bounds check
164  {
165  const std::size_t offset =
166  numeric_cast_v<std::size_t>(*index_value_opt * new_value_bv.size());
167 
168  for(std::size_t j = 0; j < new_value_bv.size(); j++)
169  next_bv[offset + j] = new_value_bv[j];
170  }
171 
172  return;
173  }
174 
175  typet counter_type = index.type();
176 
177  for(mp_integer i=0; i<size; i=i+1)
178  {
179  exprt counter=from_integer(i, counter_type);
180 
181  literalt eq_lit = convert(equal_exprt(index, counter));
182 
183  const std::size_t offset =
184  numeric_cast_v<std::size_t>(i * new_value_bv.size());
185 
186  for(std::size_t j = 0; j < new_value_bv.size(); j++)
187  next_bv[offset + j] =
188  prop.lselect(eq_lit, new_value_bv[j], prev_bv[offset + j]);
189  }
190 }
191 
193  const struct_typet &type,
194  const exprt &where,
195  const exprt &new_value,
196  const bvt &prev_bv,
197  bvt &next_bv)
198 {
199  next_bv=prev_bv;
200 
201  const bvt &new_value_bv = convert_bv(new_value);
202 
203  const irep_idt &component_name = where.get(ID_component_name);
204  const struct_typet::componentst &components=
205  type.components();
206 
207  std::size_t offset=0;
208 
209  for(const auto &c : components)
210  {
211  const typet &subtype = c.type();
212 
213  std::size_t sub_width=boolbv_width(subtype);
214 
215  if(c.get_name() == component_name)
216  {
218  subtype == new_value.type(),
219  "with/struct: component '" + id2string(component_name) +
220  "' type does not match",
221  irep_pretty_diagnosticst{subtype},
222  irep_pretty_diagnosticst{new_value.type()});
223 
225  sub_width == new_value_bv.size(),
226  "convert_with_struct: unexpected new_value operand width",
228 
229  for(std::size_t i=0; i<sub_width; i++)
230  next_bv[offset + i] = new_value_bv[i];
231 
232  break; // done
233  }
234 
235  offset+=sub_width;
236  }
237 }
238 
240  const union_typet &type,
241  const exprt &new_value,
242  const bvt &prev_bv,
243  bvt &next_bv)
244 {
245  next_bv=prev_bv;
246 
247  const bvt &new_value_bv = convert_bv(new_value);
248 
250  next_bv.size() >= new_value_bv.size(),
251  "convert_with_union: unexpected new_value operand width",
253 
254  endianness_mapt map_u = endianness_map(type);
255  endianness_mapt map_new_value = endianness_map(new_value.type());
256 
257  for(std::size_t i = 0; i < new_value_bv.size(); i++)
258  next_bv[map_u.map_bit(i)] = new_value_bv[map_new_value.map_bit(i)];
259 }
constant_exprt from_integer(const mp_integer &int_value, const typet &type)
API to expression classes for bitvectors.
const union_tag_typet & to_union_tag_type(const typet &type)
Cast a typet to a union_tag_typet.
Definition: c_types.h:224
const union_typet & to_union_type(const typet &type)
Cast a typet to a union_typet.
Definition: c_types.h:184
Arrays with given size.
Definition: std_types.h:807
const exprt & size() const
Definition: std_types.h:840
const namespacet & ns
Definition: arrays.h:56
virtual bvt convert_with(const with_exprt &expr)
Definition: boolbv_with.cpp:17
virtual const bvt & convert_bv(const exprt &expr, const std::optional< std::size_t > expected_width={})
Convert expression to vector of literalts, using an internal cache to speed up conversion if availabl...
Definition: boolbv.cpp:37
void convert_with_array(const array_typet &type, const exprt &index, const exprt &new_value, const bvt &prev_bv, bvt &next_bv)
bool is_unbounded_array(const typet &type) const override
Definition: boolbv.cpp:518
void convert_with_union(const union_typet &type, const exprt &new_value, const bvt &prev_bv, bvt &next_bv)
virtual endianness_mapt endianness_map(const typet &type, bool little_endian) const
Definition: boolbv.h:107
virtual std::size_t boolbv_width(const typet &type) const
Definition: boolbv.h:101
void convert_with_struct(const struct_typet &type, const exprt &where, const exprt &new_value, const bvt &prev_bv, bvt &next_bv)
dstringt has one field, an unsigned integer no which is an index into a static table of strings.
Definition: dstring.h:38
Maps a big-endian offset to a little-endian offset.
size_t map_bit(size_t bit) const
Equality.
Definition: std_expr.h:1361
Base class for all expressions.
Definition: expr.h:56
std::vector< exprt > operandst
Definition: expr.h:58
typet & type()
Return the type of the expression.
Definition: expr.h:84
operandst & operands()
Definition: expr.h:94
const irep_idt & get(const irep_idt &name) const
Definition: irep.cpp:44
const irep_idt & id() const
Definition: irep.h:384
const union_typet & follow_tag(const union_tag_typet &) const
Follow type tag of union type.
Definition: namespace.cpp:63
literalt convert(const exprt &expr) override
Convert a Boolean expression and return the corresponding literal.
virtual literalt lselect(literalt a, literalt b, literalt c)=0
Structure type, corresponds to C style structs.
Definition: std_types.h:231
const componentst & components() const
Definition: std_types.h:147
std::vector< componentt > componentst
Definition: std_types.h:140
The type of an expression, extends irept.
Definition: type.h:29
The union type.
Definition: c_types.h:147
Replaces a sub-range of a bit-vector operand.
Replaces a sub-range of a bit-vector operand.
Operator to update elements in structs and arrays.
Definition: std_expr.h:2471
exprt & old()
Definition: std_expr.h:2481
exprt & new_value()
Definition: std_expr.h:2501
exprt & where()
Definition: std_expr.h:2491
const std::string & id2string(const irep_idt &d)
Definition: irep.h:40
std::vector< literalt > bvt
Definition: literal.h:201
BigInt mp_integer
Definition: smt_terms.h:17
#define PRECONDITION(CONDITION)
Definition: invariant.h:463
#define DATA_INVARIANT_WITH_DIAGNOSTICS(CONDITION, REASON,...)
Definition: invariant.h:535
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 array_typet & to_array_type(const typet &type)
Cast a typet to an array_typet.
Definition: std_types.h:888
const struct_tag_typet & to_struct_tag_type(const typet &type)
Cast a typet to a struct_tag_typet.
Definition: std_types.h:518