GCC Code Coverage Report
Directory: . Exec Total Coverage
File: src/theory/bv/int_blaster.h Lines: 1 1 100.0 %
Date: 2021-09-07 Branches: 0 0 0.0 %

Line Exec Source
1
/******************************************************************************
2
 * Top contributors (to current version):
3
 *   Yoni Zohar
4
 *
5
 * This file is part of the cvc5 project.
6
 *
7
 * Copyright (c) 2009-2021 by the authors listed in the file AUTHORS
8
 * in the top-level source directory and their institutional affiliations.
9
 * All rights reserved.  See the file COPYING in the top-level source
10
 * directory for licensing information.
11
 * ****************************************************************************
12
 *
13
 * A translation utility from bit-vectors to integers.
14
 */
15
16
#include "cvc5_private.h"
17
18
#ifndef __CVC5__THEORY__BV__INT_BLASTER__H
19
#define __CVC5__THEORY__BV__INT_BLASTER__H
20
21
#include "context/cdhashmap.h"
22
#include "context/cdhashset.h"
23
#include "context/cdo.h"
24
#include "context/context.h"
25
#include "options/smt_options.h"
26
#include "theory/arith/nl/iand_utils.h"
27
28
namespace cvc5 {
29
30
/*
31
** Converts bit-vector formulas to integer formulas.
32
** The conversion is implemented using a translation function Tr,
33
** roughly described as follows:
34
**
35
** Tr(x) = fresh_x for every bit-vector variable x, where fresh_x is a fresh
36
**         integer variable.
37
** Tr(c) = the integer value of c, for any bit-vector constant c.
38
** Tr((bvadd s t)) = Tr(s) + Tr(t) mod 2^k, where k is the bit width of
39
**         s and t.
40
** Similar transformations are done for bvmul, bvsub, bvudiv, bvurem, bvneg,
41
**         bvnot, bvconcat, bvextract
42
** Tr((_ zero_extend m) x) = Tr(x)
43
** Tr((_ sign_extend m) x) = ite(msb(x)=0, x, 2^k*(2^m-1) + x))
44
** explanation: if the msb is 0, this is the same as zero_extend,
45
** which does not change the integer value.
46
** If the msb is 1, then the result should correspond to
47
** concat(1...1, x), with m 1's.
48
** m 1's is 2^m-1, and multiplying it by x's width (k) moves it
49
** to the front.
50
**
51
** Tr((bvand s t)) depends on the granularity, which is provided via an option.
52
** We divide s and t to blocks.
53
** The size of each block is the granularity, and so the number of
54
** blocks is:
55
** bit width/granularity (rounded down).
56
** We create an ITE that represents an arbitrary block,
57
** and then create a sum by mutiplying each block by the
58
** appropriate power of two.
59
** More formally:
60
** Let g denote the granularity.
61
** Let k denote the bit width of s and t.
62
** Let b denote floor(k/g) if k >= g, or just k otherwise.
63
** Tr((bvand s t)) =
64
** Sigma_{i=0}^{b-1}(bvand s[(i+1)*g, i*g] t[(i+1)*g, i*g])*2^(i*g)
65
**
66
** bvor, bvxor, bvxnor, bvnand, bvnor -- are eliminated and so bvand is the
67
*only bit-wise operator that is directly handled.
68
**
69
** Tr((bvshl a b)) = ite(Tr(b) >= k, 0, Tr(a)*ITE), where k is the bit width of
70
**         a and b, and ITE represents exponentiation up to k, that is:
71
** ITE = ite(Tr(b)=0, 1, ite(Tr(b)=1), 2, ite(Tr(b)=2, 4, ...))
72
** Similar transformations are done for bvlshr.
73
**
74
** Tr(a=b) = Tr(a)=Tr(b)
75
** Tr((bvult a b)) = Tr(a) < Tr(b)
76
** Similar transformations are done for bvule, bvugt, and bvuge.
77
** Tr((bvslt a b)) = Tr(uts(a)) < Tr(uts(b)),
78
** where uts is a function that transforms unsigned
79
** to signed representations. See more details
80
** in the documentation of the function uts.
81
** Similar transformations are done for the remaining comparators.
82
**
83
** Bit-vector operators that are not listed above are either
84
** eliminated using the BV rewriter,
85
** or go through the following default
86
** translation, that also works for non-bit-vector operators
87
** with result type BV:
88
** Tr((op t1 ... tn)) = (bv2nat (op (cast t1) ... (cast tn)))
89
** where (cast x) is ((_ nat2bv k) x) or just x,
90
** depending on the type of the corresponding argument of
91
** op.
92
**
93
**/
94
8
class IntBlaster
95
{
96
  using CDNodeMap = context::CDHashMap<Node, Node>;
97
98
 public:
99
  /**
100
   * Constructor.
101
   * @param context user context
102
   * @param mode bv-to-int translation mode
103
   * @param granularity bv-to-int translation granularity
104
   * @param introduceFreshIntVars determines whether bit-vector variables are
105
   * translated to integer variables, or are directly casted using `bv2nat`
106
   * operator. not purely bit-vector nodes.
107
   */
108
  IntBlaster(context::Context* context,
109
             options::SolveBVAsIntMode mode,
110
             uint64_t granluarity = 1,
111
             bool introduceFreshIntVars = true);
112
113
  /**
114
   * The result is an integer term and is computed
115
   * according to the translation specified above.
116
   * @param n is a bit-vector term or formula to be translated.
117
   * @param lemmas additional lemmas that are needed for the translation
118
   * to be sound. These are range constraints on introduced variables.
119
   * @param skolems a map in which the following information will be stored
120
   * during the run of intBlast: for each BV variable n, skolems[n] is its new
121
   * definition: ((_ nat2bv k) nn), where k is the bit-width of n, and nn is the
122
   * integer variable that corresponds to n.
123
   * For each UF f from BV to BV, skolems[f] is lambda x : BV[k] . ((_ nat2bv i)
124
   * ff((bv2nat x))), where k is the bit-width of the domain of f, i is the
125
   * bit-width of its range, and ff is a Int->Int function that corresponds to
126
   * f. For functions with other signatures this is similar
127
   * @return integer node that corresponds to n
128
   */
129
  Node intBlast(Node n,
130
                std::vector<Node>& lemmas,
131
                std::map<Node, Node>& skolems);
132
133
 protected:
134
  /**
135
   * A generic function that creates a logical shift node (either left or
136
   * right). a << b gets translated to a * 2^b mod 2^k, where k is the bit
137
   * width. a >> b gets translated to a div 2^b mod 2^k, where k is the bit
138
   * width. The exponentiation operation is translated to an ite for possible
139
   * values of the exponent, from 0 to k-1.
140
   * If the right operand of the shift is greater than k-1,
141
   * the result is 0.
142
   * @param children the two operands for the shift
143
   * @param bvsize the original bit widths of the operands
144
   *                (before translation to integers)
145
   * @param  isLeftShift true iff the desired operation is a left shift.
146
   * @return a node representing the shift.
147
   *
148
   */
149
  Node createShiftNode(std::vector<Node> children,
150
                       uint64_t bvsize,
151
                       bool isLeftShift);
152
153
  /** Adds the constraint 0 <= node < 2^size to lemmas */
154
  void addRangeConstraint(Node node, uint64_t size, std::vector<Node>& lemmas);
155
156
  /** Adds a constraint that encodes bitwise and */
157
  void addBitwiseConstraint(Node bitwiseConstraint, std::vector<Node>& lemmas);
158
159
  /** Returns a node that represents the bitwise negation of n. */
160
  Node createBVNotNode(Node n, uint64_t bvsize);
161
162
  /** Returns a node that represents the arithmetic negation of n. */
163
  Node createBVNegNode(Node n, uint64_t bvsize);
164
165
  /** Returns a node that represents the bitwise and of x and y, based on the
166
   * provided option. */
167
  Node createBVAndNode(Node x,
168
                       Node y,
169
                       uint64_t bvsize,
170
                       std::vector<Node>& lemmas);
171
172
  /** Returns a node that represents the bitwise or of x and y, by translation
173
   * to sum and bitwise and. */
174
  Node createBVOrNode(Node x,
175
                      Node y,
176
                      uint64_t bvsize,
177
                      std::vector<Node>& lemmas);
178
179
  /** Returns a node that represents the sum of x and y. */
180
  Node createBVAddNode(Node x, Node y, uint64_t bvsize);
181
182
  /** Returns a node that represents the difference of x and y. */
183
  Node createBVSubNode(Node x, Node y, uint64_t bvsize);
184
185
  /** Returns a node that represents the signed extension of x by amount. */
186
  Node createSignExtendNode(Node x, uint64_t bvsize, uint64_t amount);
187
188
  /**
189
   * Whenever we introduce an integer variable that represents a bit-vector
190
   * variable, we need to guard the range of the newly introduced variable.
191
   * For bit width k, the constraint is 0 <= newVar < 2^k.
192
   * @param newVar the newly introduced integer variable
193
   * @param k the bit width of the original bit-vector variable.
194
   * @return a node representing the range constraint.
195
   */
196
  Node mkRangeConstraint(Node newVar, uint64_t k);
197
198
  /**
199
   * Some bit-vector operators (e.g., bvadd, bvand) are binary, but allow more
200
   * than two arguments as a syntactic sugar.
201
   * For example, we can have a node for (bvand x y z),
202
   * that represents (bvand (x (bvand y z))).
203
   * This function locally binarizes these operators.
204
   * In the above example, this means that x,y,z
205
   * are not handled recursively, but will require a separate
206
   * call to the function.
207
   *
208
   */
209
  Node makeBinary(Node n);
210
211
  /**
212
   * @param k A non-negative integer
213
   * @return A node that represents the constant 2^k
214
   */
215
  Node pow2(uint64_t k);
216
217
  /**
218
   * @param k A positive integer k
219
   * @return A node that represent the constant 2^k-1
220
   * For example, if k is 4, the result is a node representing the
221
   * constant 15.
222
   */
223
  Node maxInt(uint64_t k);
224
225
  /**
226
   * @param n A node representing an integer term
227
   * @param exponent A non-negative integer
228
   * @return A node representing (n mod (2^exponent))
229
   */
230
  Node modpow2(Node n, uint64_t exponent);
231
232
  /**
233
   * Returns true iff the type of at least
234
   * one child of n was changed by the translation.
235
   */
236
  bool childrenTypesChanged(Node n);
237
238
  /**
239
   * @param quantifiedNode a node whose main operator is forall/exists.
240
   * @return a node opbtained from quantifiedNode by:
241
   * 1. Replacing all bound BV variables by new bound integer variables.
242
   * 2. Add range constraints for the new variables, induced by the original
243
   * bit-width. These range constraints are added with "AND" in case of exists
244
   * and with "IMPLIES" in case of forall.
245
   */
246
  Node translateQuantifiedFormula(Node quantifiedNode);
247
248
  /**
249
   * Reconstructs a node whose main operator cannot be
250
   * translated to integers.
251
   * Reconstruction is done by casting to integers/bit-vectors
252
   * as needed.
253
   * For example, if node is (select A x) where A
254
   * is a bit-vector array, we do not change A to be
255
   * an integer array, even though x was translated
256
   * to integers.
257
   * In this case we cast x to (bv2nat x) during
258
   * the reconstruction.
259
   *
260
   * @param originalNode the node that we are reconstructing
261
   * @param resultType the desired type for the reconstruction
262
   * @param translated_children the children of originalNode
263
   *        after their translation to integers.
264
   * @return A node with originalNode's operator that has type resultType.
265
   */
266
  Node reconstructNode(Node originalNode,
267
                       TypeNode resultType,
268
                       const std::vector<Node>& translated_children);
269
270
  /**
271
   * A useful utility function.
272
   * if n is an integer and tn is bit-vector,
273
   * applies the IntToBitVector operator on n.
274
   * if n is a bit-vector and tn is integer,
275
   * applies BitVector_TO_NAT operator.
276
   * Otherwise, keeps n intact.
277
   */
278
  Node castToType(Node n, TypeNode tn);
279
280
  /**
281
   * When a UF f is translated to a UF g,
282
   * we compute a definition
283
   * to relate between f and g.
284
   * We do the same when f and g are just variables.
285
   * This is useful, for example, when asking
286
   * for a model-value of a term that includes the
287
   * original UF f.
288
   *
289
   * For example: if bvUF is a BV variable x and
290
   * intUF is an integer variable xx,
291
   * the return value is ((_ nat2bv k) xx),
292
   * where k is the width of k.
293
   *
294
   * For another example: if bvUF is a BV to BV function
295
   * f and intUF is an integer to integer function ff,
296
   * the return value is:
297
   * lambda x : BV[k]. ((_ nat2bv k) (ff (bv2nat x))),
298
   * where k is the bit-width of the co-domain of f.
299
   *
300
   * @param bvUF the original function or variable
301
   * @param intUF the translated function or variable
302
   */
303
  Node defineBVUFAsIntUF(Node bvUF, Node intUF);
304
305
  /**
306
   * @param bvUF is an uninterpreted function symbol from the original formula
307
   * @return a fresh uninterpreted function symbol, obtained from bvUF
308
     by replacing every argument of type BV to an argument of type Integer,
309
     and the return type becomes integer in case it was BV.
310
   */
311
  Node translateFunctionSymbol(Node bvUF, std::map<Node, Node>& skolems);
312
313
  /**
314
   * returns an integer m such that the unsigned
315
   * binary representation of n is the same as the
316
   * signed binary representation of m.
317
   */
318
  Node uts(Node n, uint64_t bvsize);
319
320
  /**
321
   * Performs the actual translation to integers for nodes
322
   * that have children.
323
   */
324
  Node translateWithChildren(Node original,
325
                             const std::vector<Node>& translated_children,
326
                             std::vector<Node>& lemmas);
327
328
  /**
329
   * Performs the actual translation to integers for nodes
330
   * that don't have children (variables, constants, uninterpreted function
331
   * symbols).
332
   */
333
  Node translateNoChildren(Node original,
334
                           std::vector<Node>& lemmas,
335
                           std::map<Node, Node>& skolems);
336
337
  /** Caches for the different functions */
338
  CDNodeMap d_binarizeCache;
339
  CDNodeMap d_intblastCache;
340
341
  /** Node manager that is used throughout the pass */
342
  NodeManager* d_nm;
343
344
  /**
345
   * Range constraints of the form 0 <= x < 2^k
346
   * These are added for every new integer variable that we introduce.
347
   */
348
  context::CDHashSet<Node> d_rangeAssertions;
349
350
  /**
351
   * A set of "bitwise" equalities over integers for BITVECTOR_AND
352
   *   used in for options::SolveBVAsIntMode::BITWISE
353
   */
354
  context::CDHashSet<Node> d_bitwiseAssertions;
355
356
  /** Useful constants */
357
  Node d_zero;
358
  Node d_one;
359
360
  /** helper class for handeling bvand translation */
361
  theory::arith::nl::IAndUtils d_iandUtils;
362
363
  /** the mode for translation to integers */
364
  options::SolveBVAsIntMode d_mode;
365
366
  /** the granularity to use in the translation */
367
  uint64_t d_granularity;
368
369
  /** an SmtEngine for context */
370
  context::Context* d_context;
371
372
  /** true iff the translator should introduce
373
   * fresh integer variables for bit-vector variables.
374
   * Otherwise, we introduce a nat2bv term.
375
   */
376
  bool d_introduceFreshIntVars;
377
};
378
379
}  // namespace cvc5
380
381
#endif /* __CVC5__THEORY__BV__INT_BLASTER_H */