GCC Code Coverage Report
Directory: . Exec Total Coverage
File: src/preprocessing/passes/bv_to_int.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, Gereon Kremer, Makai Mann
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
 * The BVToInt preprocessing pass
14
 *
15
 * Converts bit-vector formulas to integer formulas.
16
 * The conversion is implemented using a translation function Tr,
17
 * roughly described as follows:
18
 *
19
 * Tr(x) = fresh_x for every bit-vector variable x, where fresh_x is a fresh
20
 *         integer variable.
21
 * Tr(c) = the integer value of c, for any bit-vector constant c.
22
 * Tr((bvadd s t)) = Tr(s) + Tr(t) mod 2^k, where k is the bit width of
23
 *         s and t.
24
 * Similar transformations are done for bvmul, bvsub, bvudiv, bvurem, bvneg,
25
 *         bvnot, bvconcat, bvextract
26
 * Tr((_ zero_extend m) x) = Tr(x)
27
 * Tr((_ sign_extend m) x) = ite(msb(x)=0, x, 2^k*(2^m-1) + x))
28
 * explanation: if the msb is 0, this is the same as zero_extend,
29
 * which does not change the integer value.
30
 * If the msb is 1, then the result should correspond to
31
 * concat(1...1, x), with m 1's.
32
 * m 1's is 2^m-1, and multiplying it by x's width (k) moves it
33
 * to the front.
34
 *
35
 * Tr((bvand s t)) depends on the granularity, which is provided by the user
36
 * when enabling this preprocessing pass.
37
 * We divide s and t to blocks.
38
 * The size of each block is the granularity, and so the number of
39
 * blocks is:
40
 * bit width/granularity (rounded down).
41
 * We create an ITE that represents an arbitrary block,
42
 * and then create a sum by mutiplying each block by the
43
 * appropriate power of two.
44
 * More formally:
45
 * Let g denote the granularity.
46
 * Let k denote the bit width of s and t.
47
 * Let b denote floor(k/g) if k >= g, or just k otherwise.
48
 * Tr((bvand s t)) =
49
 * Sigma_{i=0}^{b-1}(bvand s[(i+1)*g, i*g] t[(i+1)*g, i*g])*2^(i*g)
50
 *
51
 * Similar transformations are done for bvor, bvxor, bvxnor, bvnand, bvnor.
52
 *
53
 * Tr((bvshl a b)) = ite(Tr(b) >= k, 0, Tr(a)*ITE), where k is the bit width of
54
 *         a and b, and ITE represents exponentiation up to k, that is:
55
 * ITE = ite(Tr(b)=0, 1, ite(Tr(b)=1), 2, ite(Tr(b)=2, 4, ...))
56
 * Similar transformations are done for bvlshr.
57
 *
58
 * Tr(a=b) = Tr(a)=Tr(b)
59
 * Tr((bvult a b)) = Tr(a) < Tr(b)
60
 * Similar transformations are done for bvule, bvugt, and bvuge.
61
 *
62
 * Bit-vector operators that are not listed above are either eliminated using
63
 * the function eliminationPass, or are not supported.
64
 *
65
 */
66
67
#include "cvc5_private.h"
68
69
#ifndef __CVC5__PREPROCESSING__PASSES__BV_TO_INT_H
70
#define __CVC5__PREPROCESSING__PASSES__BV_TO_INT_H
71
72
#include "context/cdhashmap.h"
73
#include "context/cdhashset.h"
74
#include "preprocessing/preprocessing_pass.h"
75
#include "theory/arith/nl/iand_utils.h"
76
77
namespace cvc5 {
78
namespace preprocessing {
79
namespace passes {
80
81
using CDNodeMap = context::CDHashMap<Node, Node>;
82
83
19846
class BVToInt : public PreprocessingPass
84
{
85
 public:
86
  BVToInt(PreprocessingPassContext* preprocContext);
87
88
 protected:
89
  PreprocessingPassResult applyInternal(
90
      AssertionPipeline* assertionsToPreprocess) override;
91
  /**
92
   * A generic function that creates a logical shift node (either left or
93
   * right). a << b gets translated to a * 2^b mod 2^k, where k is the bit
94
   * width. a >> b gets translated to a div 2^b mod 2^k, where k is the bit
95
   * width. The exponentiation operation is translated to an ite for possible
96
   * values of the exponent, from 0 to k-1.
97
   * If the right operand of the shift is greater than k-1,
98
   * the result is 0.
99
   * @param children the two operands for the shift
100
   * @param bvsize the original bit widths of the operands
101
   *                (before translation to integers)
102
   * @param  isLeftShift true iff the desired operation is a left shift.
103
   * @return a node representing the shift.
104
   *
105
   */
106
  Node createShiftNode(std::vector<Node> children,
107
                       uint64_t bvsize,
108
                       bool isLeftShift);
109
110
  /**
111
   * Returns a node that represents the bitwise negation of n.
112
   */
113
  Node createBVNotNode(Node n, uint64_t bvsize);
114
115
  /**
116
   * The result is an integer term and is computed
117
   * according to the translation specified above.
118
   * @param n is a bit-vector term or formula to be translated.
119
   * @return integer node that corresponds to n.
120
   */
121
  Node bvToInt(Node n);
122
123
  /**
124
   * Whenever we introduce an integer variable that represents a bit-vector
125
   * variable, we need to guard the range of the newly introduced variable.
126
   * For bit width k, the constraint is 0 <= newVar < 2^k.
127
   * @param newVar the newly introduced integer variable
128
   * @param k the bit width of the original bit-vector variable.
129
   * @return a node representing the range constraint.
130
   */
131
  Node mkRangeConstraint(Node newVar, uint64_t k);
132
133
  /**
134
   * In the translation to integers, it is convenient to assume that certain
135
   * bit-vector operators do not occur in the original formula (e.g., repeat).
136
   * This function eliminates all these operators.
137
   */
138
  Node eliminationPass(Node n);
139
140
  /**
141
   * Some bit-vector operators (e.g., bvadd, bvand) are binary, but allow more
142
   * than two arguments as a syntactic sugar.
143
   * For example, we can have a node for (bvand x y z),
144
   * that represents (bvand (x (bvand y z))).
145
   * This function makes all such operators strictly binary.
146
   */
147
  Node makeBinary(Node n);
148
149
  /**
150
   * @param k A non-negative integer
151
   * @return A node that represents the constant 2^k
152
   */
153
  Node pow2(uint64_t k);
154
155
  /**
156
   * @param k A positive integer k
157
   * @return A node that represent the constant 2^k-1
158
   * For example, if k is 4, the result is a node representing the
159
   * constant 15.
160
   */
161
  Node maxInt(uint64_t k);
162
163
  /**
164
   * @param n A node representing an integer term
165
   * @param exponent A non-negative integer
166
   * @return A node representing (n mod (2^exponent))
167
   */
168
  Node modpow2(Node n, uint64_t exponent);
169
170
  bool childrenTypesChanged(Node n);
171
172
  /**
173
   * Add the range assertions collected in d_rangeAssertions
174
   * (using mkRangeConstraint) to the assertion pipeline.
175
   * If there are no range constraints, do nothing.
176
   * If there is a single range constraint, add it to the pipeline.
177
   * Otherwise, add all of them as a single conjunction
178
   */
179
  void addFinalizeRangeAssertions(AssertionPipeline* assertionsToPreprocess);
180
181
  /**
182
   * @param quantifiedNode a node whose main operator is forall/exists.
183
   * @return a node opbtained from quantifiedNode by:
184
   * 1. Replacing all bound BV variables by new bound integer variables.
185
   * 2. Add range constraints for the new variables, induced by the original
186
   * bit-width. These range constraints are added with "AND" in case of exists
187
   * and with "IMPLIES" in case of forall.
188
   */
189
  Node translateQuantifiedFormula(Node quantifiedNode);
190
191
  /**
192
   * Reconstructs a node whose main operator cannot be
193
   * translated to integers.
194
   * Reconstruction is done by casting to integers/bit-vectors
195
   * as needed.
196
   * For example, if node is (select A x) where A
197
   * is a bit-vector array, we do not change A to be
198
   * an integer array, even though x was translated
199
   * to integers.
200
   * In this case we cast x to (bv2nat x) during
201
   * the reconstruction.
202
   *
203
   * @param originalNode the node that we are reconstructing
204
   * @param resultType the desired type for the reconstruction
205
   * @param translated_children the children of originalNode
206
   *        after their translation to integers.
207
   * @return A node with originalNode's operator that has type resultType.
208
   */
209
  Node reconstructNode(Node originalNode,
210
                       TypeNode resultType,
211
                       const std::vector<Node>& translated_children);
212
213
  /**
214
   * A useful utility function.
215
   * if n is an integer and tn is bit-vector,
216
   * applies the IntToBitVector operator on n.
217
   * if n is a vit-vector and tn is integer,
218
   * applies BitVector_TO_NAT operator.
219
   * Otherwise, keeps n intact.
220
   */
221
  Node castToType(Node n, TypeNode tn);
222
223
  /**
224
   * When a UF f is translated to a UF g,
225
   * we add a define-fun command to the smt-engine
226
   * to relate between f and g.
227
   * We do the same when f and g are just variables.
228
   * This is useful, for example, when asking
229
   * for a model-value of a term that includes the
230
   * original UF f.
231
   * @param bvUF the original function or variable
232
   * @param intUF the translated function or variable
233
   */
234
  void defineBVUFAsIntUF(Node bvUF, Node intUF);
235
236
  /**
237
   * @param bvUF is an uninterpreted function symbol from the original formula
238
   * @return a fresh uninterpreted function symbol, obtained from bvUF
239
     by replacing every argument of type BV to an argument of type Integer,
240
     and the return type becomes integer in case it was BV.
241
   */
242
  Node translateFunctionSymbol(Node bvUF);
243
244
  /**
245
   * Performs the actual translation to integers for nodes
246
   * that have children.
247
   */
248
  Node translateWithChildren(Node original,
249
                             const std::vector<Node>& translated_children);
250
251
  /**
252
   * Performs the actual translation to integers for nodes
253
   * that don't have children (variables, constants, uninterpreted function
254
   * symbols).
255
   */
256
  Node translateNoChildren(Node original);
257
258
  /**
259
   * Caches for the different functions
260
   */
261
  CDNodeMap d_binarizeCache;
262
  CDNodeMap d_eliminationCache;
263
  CDNodeMap d_rebuildCache;
264
  CDNodeMap d_bvToIntCache;
265
266
  /**
267
   * Node manager that is used throughout the pass
268
   */
269
  NodeManager* d_nm;
270
271
  /**
272
   * A set of constraints of the form 0 <= x < 2^k
273
   * These are added for every new integer variable that we introduce.
274
   */
275
  context::CDHashSet<Node> d_rangeAssertions;
276
277
  /**
278
   * Useful constants
279
   */
280
  Node d_zero;
281
  Node d_one;
282
283
  /** helper class for handeling bvand translation */
284
  theory::arith::nl::IAndUtils d_iandUtils;
285
};
286
287
}  // namespace passes
288
}  // namespace preprocessing
289
}  // namespace cvc5
290
291
#endif /* __CVC5__PREPROCESSING__PASSES__BV_TO_INT_H */