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 |
19676 |
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 */ |