CBMC
boolbv_add_sub.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 "boolbv.h"
10 
11 #include <util/bitvector_types.h>
12 #include <util/invariant.h>
13 
15 
17 {
19  expr.id() == ID_plus || expr.id() == ID_minus ||
20  expr.id() == "no-overflow-plus" || expr.id() == "no-overflow-minus");
21 
22  const typet &type = expr.type();
23 
24  if(
25  type.id() != ID_unsignedbv && type.id() != ID_signedbv &&
26  type.id() != ID_fixedbv && type.id() != ID_floatbv &&
27  type.id() != ID_range && type.id() != ID_complex)
28  {
29  return conversion_failed(expr);
30  }
31 
32  std::size_t width=boolbv_width(type);
33 
34  const exprt::operandst &operands=expr.operands();
35 
37  !operands.empty(),
38  "operator " + expr.id_string() + " takes at least one operand");
39 
40  const exprt &op0 = to_multi_ary_expr(expr).op0();
42  op0.type() == type, "add/sub with mixed types:\n" + expr.pretty());
43 
44  bvt bv = convert_bv(op0, width);
45 
46  bool subtract=(expr.id()==ID_minus ||
47  expr.id()=="no-overflow-minus");
48 
49  bool no_overflow=(expr.id()=="no-overflow-plus" ||
50  expr.id()=="no-overflow-minus");
51 
52  typet arithmetic_type =
53  type.id() == ID_complex ? to_type_with_subtype(type).subtype() : type;
54 
56  (arithmetic_type.id()==ID_signedbv ||
57  arithmetic_type.id()==ID_fixedbv)?bv_utilst::representationt::SIGNED:
59 
60  for(exprt::operandst::const_iterator
61  it=operands.begin()+1;
62  it!=operands.end(); it++)
63  {
65  it->type() == type, "add/sub with mixed types:\n" + expr.pretty());
66 
67  const bvt &op = convert_bv(*it, width);
68 
69  if(type.id() == ID_complex)
70  {
71  std::size_t sub_width =
72  boolbv_width(to_type_with_subtype(type).subtype());
73 
74  INVARIANT(
75  sub_width != 0, "complex elements shall have nonzero bit width");
76  INVARIANT(
77  width % sub_width == 0,
78  "total complex bit width shall be a multiple of the element bit width");
79 
80  std::size_t size=width/sub_width;
81  bv.resize(width);
82 
83  for(std::size_t i=0; i<size; i++)
84  {
85  bvt tmp_op;
86  tmp_op.resize(sub_width);
87 
88  for(std::size_t j=0; j<tmp_op.size(); j++)
89  {
90  const std::size_t index = i * sub_width + j;
91  INVARIANT(index < op.size(), "bit index shall be within bounds");
92  tmp_op[j] = op[index];
93  }
94 
95  bvt tmp_result;
96  tmp_result.resize(sub_width);
97 
98  for(std::size_t j=0; j<tmp_result.size(); j++)
99  {
100  const std::size_t index = i * sub_width + j;
101  INVARIANT(index < bv.size(), "bit index shall be within bounds");
102  tmp_result[j] = bv[index];
103  }
104 
105  if(to_type_with_subtype(type).subtype().id() == ID_floatbv)
106  {
107  // needs to change due to rounding mode
108  float_utilst float_utils(
109  prop, to_floatbv_type(to_type_with_subtype(type).subtype()));
110  tmp_result=float_utils.add_sub(tmp_result, tmp_op, subtract);
111  }
112  else
113  tmp_result=bv_utils.add_sub(tmp_result, tmp_op, subtract);
114 
115  INVARIANT(
116  tmp_result.size() == sub_width,
117  "applying the add/sub operation shall not change the bitwidth");
118 
119  for(std::size_t j=0; j<tmp_result.size(); j++)
120  {
121  const std::size_t index = i * sub_width + j;
122  INVARIANT(index < bv.size(), "bit index shall be within bounds");
123  bv[index] = tmp_result[j];
124  }
125  }
126  }
127  else if(type.id() == ID_range)
128  {
129  // add: lhs + from + rhs + from - from = lhs + rhs + from
130  // sub: lhs + from - (rhs + from) - from = lhs - rhs - from
131  mp_integer from = to_range_type(type).get_from();
132  bv = bv_utils.add_sub(bv, op, subtract);
133  bv = bv_utils.add_sub(
134  bv, bv_utils.build_constant(from, op.size()), subtract);
135  }
136  else if(type.id()==ID_floatbv)
137  {
138  // needs to change due to rounding mode
139  float_utilst float_utils(prop, to_floatbv_type(arithmetic_type));
140  bv=float_utils.add_sub(bv, op, subtract);
141  }
142  else if(no_overflow)
143  bv=bv_utils.add_sub_no_overflow(bv, op, subtract, rep);
144  else
145  bv=bv_utils.add_sub(bv, op, subtract);
146  }
147 
148  return bv;
149 }
150 
152 {
153  PRECONDITION(
154  expr.id() == ID_saturating_minus || expr.id() == ID_saturating_plus);
155 
156  const typet &type = expr.type();
157 
158  if(
159  type.id() != ID_unsignedbv && type.id() != ID_signedbv &&
160  type.id() != ID_fixedbv && type.id() != ID_complex)
161  {
162  return conversion_failed(expr);
163  }
164 
165  std::size_t width = boolbv_width(type);
166 
168  expr.lhs().type() == type && expr.rhs().type() == type,
169  "saturating add/sub with mixed types:\n" + expr.pretty());
170 
171  const bool subtract = expr.id() == ID_saturating_minus;
172 
173  typet arithmetic_type =
174  type.id() == ID_complex ? to_type_with_subtype(type).subtype() : type;
175 
177  (arithmetic_type.id() == ID_signedbv || arithmetic_type.id() == ID_fixedbv)
180 
181  bvt bv = convert_bv(expr.lhs(), width);
182  const bvt &op = convert_bv(expr.rhs(), width);
183 
184  if(type.id() != ID_complex)
185  return bv_utils.saturating_add_sub(bv, op, subtract, rep);
186 
187  std::size_t sub_width = boolbv_width(to_type_with_subtype(type).subtype());
188 
189  INVARIANT(sub_width != 0, "complex elements shall have nonzero bit width");
190  INVARIANT(
191  width % sub_width == 0,
192  "total complex bit width shall be a multiple of the element bit width");
193 
194  std::size_t size = width / sub_width;
195 
196  for(std::size_t i = 0; i < size; i++)
197  {
198  bvt tmp_op;
199  tmp_op.resize(sub_width);
200 
201  for(std::size_t j = 0; j < tmp_op.size(); j++)
202  {
203  const std::size_t index = i * sub_width + j;
204  INVARIANT(index < op.size(), "bit index shall be within bounds");
205  tmp_op[j] = op[index];
206  }
207 
208  bvt tmp_result;
209  tmp_result.resize(sub_width);
210 
211  for(std::size_t j = 0; j < tmp_result.size(); j++)
212  {
213  const std::size_t index = i * sub_width + j;
214  INVARIANT(index < bv.size(), "bit index shall be within bounds");
215  tmp_result[j] = bv[index];
216  }
217 
218  tmp_result = bv_utils.saturating_add_sub(tmp_result, tmp_op, subtract, rep);
219 
220  INVARIANT(
221  tmp_result.size() == sub_width,
222  "applying the add/sub operation shall not change the bitwidth");
223 
224  for(std::size_t j = 0; j < tmp_result.size(); j++)
225  {
226  const std::size_t index = i * sub_width + j;
227  INVARIANT(index < bv.size(), "bit index shall be within bounds");
228  bv[index] = tmp_result[j];
229  }
230  }
231 
232  return bv;
233 }
Pre-defined bitvector types.
const floatbv_typet & to_floatbv_type(const typet &type)
Cast a typet to a floatbv_typet.
A base class for binary expressions.
Definition: std_expr.h:638
exprt & lhs()
Definition: std_expr.h:668
exprt & rhs()
Definition: std_expr.h:678
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:39
virtual bvt convert_add_sub(const exprt &expr)
bv_utilst bv_utils
Definition: boolbv.h:117
virtual bvt convert_saturating_add_sub(const binary_exprt &expr)
bvt conversion_failed(const exprt &expr)
Print that the expression of x has failed conversion, then return a vector of x's width.
Definition: boolbv.cpp:94
virtual std::size_t boolbv_width(const typet &type) const
Definition: boolbv.h:102
bvt add_sub_no_overflow(const bvt &op0, const bvt &op1, bool subtract, representationt rep)
Definition: bv_utils.cpp:328
static bvt build_constant(const mp_integer &i, std::size_t width)
Definition: bv_utils.cpp:14
bvt add_sub(const bvt &op0, const bvt &op1, bool subtract)
Definition: bv_utils.cpp:337
representationt
Definition: bv_utils.h:28
bvt saturating_add_sub(const bvt &op0, const bvt &op1, bool subtract, representationt rep)
Definition: bv_utils.cpp:358
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
virtual bvt add_sub(const bvt &src1, const bvt &src2, bool subtract)
std::string pretty(unsigned indent=0, unsigned max_indent=0) const
Definition: irep.cpp:482
const std::string & id_string() const
Definition: irep.h:391
const irep_idt & id() const
Definition: irep.h:388
exprt & op0()
Definition: std_expr.h:932
mp_integer get_from() const
Definition: std_types.cpp:178
const typet & subtype() const
Definition: type.h:187
The type of an expression, extends irept.
Definition: type.h:29
std::vector< literalt > bvt
Definition: literal.h:201
BigInt mp_integer
Definition: smt_terms.h:17
#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
const multi_ary_exprt & to_multi_ary_expr(const exprt &expr)
Cast an exprt to a multi_ary_exprt.
Definition: std_expr.h:987
const range_typet & to_range_type(const typet &type)
Cast a typet to a range_typet.
Definition: std_types.h:1037
const type_with_subtypet & to_type_with_subtype(const typet &type)
Definition: type.h:208