GCC Code Coverage Report
Directory: . Exec Total Coverage
File: src/preprocessing/passes/bv_to_int.cpp Lines: 425 475 89.5 %
Date: 2021-08-17 Branches: 844 2040 41.4 %

Line Exec Source
1
/******************************************************************************
2
 * Top contributors (to current version):
3
 *   Yoni Zohar, Andrew Reynolds, Andres Noetzli
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 operations into integer operations.
16
 *
17
 */
18
19
#include "preprocessing/passes/bv_to_int.h"
20
21
#include <cmath>
22
#include <sstream>
23
#include <string>
24
#include <unordered_map>
25
#include <vector>
26
27
#include "expr/node.h"
28
#include "expr/node_traversal.h"
29
#include "expr/skolem_manager.h"
30
#include "options/smt_options.h"
31
#include "options/uf_options.h"
32
#include "preprocessing/assertion_pipeline.h"
33
#include "preprocessing/preprocessing_pass_context.h"
34
#include "theory/bv/theory_bv_rewrite_rules_operator_elimination.h"
35
#include "theory/bv/theory_bv_rewrite_rules_simplification.h"
36
#include "theory/rewriter.h"
37
#include "util/bitvector.h"
38
#include "util/iand.h"
39
#include "util/rational.h"
40
41
namespace cvc5 {
42
namespace preprocessing {
43
namespace passes {
44
45
using namespace std;
46
using namespace cvc5::theory;
47
using namespace cvc5::theory::bv;
48
49
namespace {
50
51
1142
Rational intpow2(uint64_t b)
52
{
53
1142
  return Rational(Integer(2).pow(b), Integer(1));
54
}
55
56
} //end empty namespace
57
58
362
Node BVToInt::mkRangeConstraint(Node newVar, uint64_t k)
59
{
60
724
  Node lower = d_nm->mkNode(kind::LEQ, d_zero, newVar);
61
724
  Node upper = d_nm->mkNode(kind::LT, newVar, pow2(k));
62
724
  Node result = d_nm->mkNode(kind::AND, lower, upper);
63
724
  return Rewriter::rewrite(result);
64
}
65
66
42
Node BVToInt::maxInt(uint64_t k)
67
{
68
42
  Assert(k > 0);
69
84
  Rational max_value = intpow2(k) - 1;
70
84
  return d_nm->mkConst<Rational>(max_value);
71
}
72
73
1094
Node BVToInt::pow2(uint64_t k)
74
{
75
1094
  Assert(k >= 0);
76
1094
  return d_nm->mkConst<Rational>(intpow2(k));
77
}
78
79
4
Node BVToInt::modpow2(Node n, uint64_t exponent)
80
{
81
8
  Node p2 = d_nm->mkConst<Rational>(intpow2(exponent));
82
8
  return d_nm->mkNode(kind::INTS_MODULUS_TOTAL, n, p2);
83
}
84
85
/**
86
 * Binarizing n via post-order traversal.
87
 */
88
1202
Node BVToInt::makeBinary(Node n)
89
{
90
2435
  for (TNode current : NodeDfsIterable(n,
91
                                       VisitOrder::POSTORDER,
92
                                       // skip visited nodes
93
7152
                                       [this](TNode tn) {
94
7152
                                         return d_binarizeCache.find(tn)
95
7152
                                                != d_binarizeCache.end();
96
11991
                                       }))
97
  {
98
2435
    uint64_t numChildren = current.getNumChildren();
99
    /*
100
     * We already visited the sub-dag rooted at the current node,
101
     * and binarized all its children.
102
     * Now we binarize the current node itself.
103
     */
104
2435
    kind::Kind_t k = current.getKind();
105
2435
    if ((numChildren > 2)
106
10
        && (k == kind::BITVECTOR_ADD || k == kind::BITVECTOR_MULT
107
10
            || k == kind::BITVECTOR_AND || k == kind::BITVECTOR_OR
108
10
            || k == kind::BITVECTOR_XOR || k == kind::BITVECTOR_CONCAT))
109
    {
110
      // We only binarize bvadd, bvmul, bvand, bvor, bvxor, bvconcat
111
      Assert(d_binarizeCache.find(current[0]) != d_binarizeCache.end());
112
      Node result = d_binarizeCache[current[0]];
113
      for (uint64_t i = 1; i < numChildren; i++)
114
      {
115
        Assert(d_binarizeCache.find(current[i]) != d_binarizeCache.end());
116
        Node child = d_binarizeCache[current[i]];
117
        result = d_nm->mkNode(current.getKind(), result, child);
118
      }
119
      d_binarizeCache[current] = result;
120
    }
121
2435
    else if (numChildren > 0)
122
    {
123
      // current has children, but we do not binarize it
124
3138
      NodeBuilder builder(k);
125
1569
      if (current.getMetaKind() == kind::metakind::PARAMETERIZED)
126
      {
127
176
        builder << current.getOperator();
128
      }
129
4208
      for (Node child : current)
130
      {
131
2639
        builder << d_binarizeCache[child].get();
132
      }
133
1569
      d_binarizeCache[current] = builder.constructNode();
134
    }
135
    else
136
    {
137
      // current has no children
138
866
      d_binarizeCache[current] = current;
139
    }
140
  }
141
1202
  return d_binarizeCache[n];
142
}
143
144
/**
145
 * We traverse n and perform rewrites both on the way down and on the way up.
146
 * On the way down we rewrite the node but not it's children.
147
 * On the way up, we update the node's children to the rewritten ones.
148
 * For each sub-node, we perform rewrites to eliminate operators.
149
 * Then, the original children are added to toVisit stack so that we rewrite
150
 * them as well.
151
 */
152
601
Node BVToInt::eliminationPass(Node n)
153
{
154
1202
  std::vector<Node> toVisit;
155
601
  toVisit.push_back(n);
156
1202
  Node current;
157
11111
  while (!toVisit.empty())
158
  {
159
5255
    current = toVisit.back();
160
    // assert that the node is binarized
161
    // The following variable is only used in assertions
162
5255
    CVC5_UNUSED kind::Kind_t k = current.getKind();
163
5255
    uint64_t numChildren = current.getNumChildren();
164
5255
    Assert((numChildren == 2)
165
           || !(k == kind::BITVECTOR_ADD || k == kind::BITVECTOR_MULT
166
                || k == kind::BITVECTOR_AND || k == kind::BITVECTOR_OR
167
                || k == kind::BITVECTOR_XOR || k == kind::BITVECTOR_CONCAT));
168
5255
    toVisit.pop_back();
169
    bool inEliminationCache =
170
5255
        (d_eliminationCache.find(current) != d_eliminationCache.end());
171
    bool inRebuildCache =
172
5255
        (d_rebuildCache.find(current) != d_rebuildCache.end());
173
5255
    if (!inEliminationCache)
174
    {
175
      // current is not the elimination of any previously-visited node
176
      // current hasn't been eliminated yet.
177
      // eliminate operators from it using rewrite rules
178
      Node currentEliminated =
179
          FixpointRewriteStrategy<RewriteRule<UdivZero>,
180
                                  RewriteRule<SdivEliminateFewerBitwiseOps>,
181
                                  RewriteRule<SremEliminateFewerBitwiseOps>,
182
                                  RewriteRule<SmodEliminateFewerBitwiseOps>,
183
                                  RewriteRule<XnorEliminate>,
184
                                  RewriteRule<NandEliminate>,
185
                                  RewriteRule<NorEliminate>,
186
                                  RewriteRule<NegEliminate>,
187
                                  RewriteRule<XorEliminate>,
188
                                  RewriteRule<OrEliminate>,
189
                                  RewriteRule<SubEliminate>,
190
                                  RewriteRule<RepeatEliminate>,
191
                                  RewriteRule<RotateRightEliminate>,
192
                                  RewriteRule<RotateLeftEliminate>,
193
                                  RewriteRule<CompEliminate>,
194
                                  RewriteRule<SleEliminate>,
195
                                  RewriteRule<SltEliminate>,
196
                                  RewriteRule<SgtEliminate>,
197
4548
                                  RewriteRule<SgeEliminate>>::apply(current);
198
199
      // save in the cache
200
2274
      d_eliminationCache[current] = currentEliminated;
201
      // also assign the eliminated now to itself to avoid revisiting.
202
2274
      d_eliminationCache[currentEliminated] = currentEliminated;
203
      // put the eliminated node in the rebuild cache, but mark that it hasn't
204
      // yet been rebuilt by assigning null.
205
2274
      d_rebuildCache[currentEliminated] = Node();
206
      // Push the eliminated node to the stack
207
2274
      toVisit.push_back(currentEliminated);
208
      // Add the children to the stack for future processing.
209
2274
      toVisit.insert(
210
4548
          toVisit.end(), currentEliminated.begin(), currentEliminated.end());
211
    }
212
5255
    if (inRebuildCache)
213
    {
214
      // current was already added to the rebuild cache.
215
2981
      if (d_rebuildCache[current].get().isNull())
216
      {
217
        // current wasn't rebuilt yet.
218
2274
        numChildren = current.getNumChildren();
219
2274
        if (numChildren == 0)
220
        {
221
          // We only eliminate operators that are not nullary.
222
866
          d_rebuildCache[current] = current;
223
        }
224
        else
225
        {
226
          // The main operator is replaced, and the children
227
          // are replaced with their eliminated counterparts.
228
2816
          NodeBuilder builder(current.getKind());
229
1408
          if (current.getMetaKind() == kind::metakind::PARAMETERIZED)
230
          {
231
154
            builder << current.getOperator();
232
          }
233
3788
          for (Node child : current)
234
          {
235
2380
            Assert(d_eliminationCache.find(child) != d_eliminationCache.end());
236
4760
            Node eliminatedChild = d_eliminationCache[child];
237
2380
            Assert(d_rebuildCache.find(eliminatedChild) != d_eliminationCache.end());
238
2380
            Assert(!d_rebuildCache[eliminatedChild].get().isNull());
239
2380
            builder << d_rebuildCache[eliminatedChild].get();
240
          }
241
1408
          d_rebuildCache[current] = builder.constructNode();
242
        }
243
      }
244
    }
245
  }
246
601
  Assert(d_eliminationCache.find(n) != d_eliminationCache.end());
247
1202
  Node eliminated = d_eliminationCache[n];
248
601
  Assert(d_rebuildCache.find(eliminated) != d_rebuildCache.end());
249
601
  Assert(!d_rebuildCache[eliminated].get().isNull());
250
1202
  return d_rebuildCache[eliminated];
251
}
252
253
/**
254
 * Translate n to Integers via post-order traversal.
255
 */
256
601
Node BVToInt::bvToInt(Node n)
257
{
258
  // make sure the node is re-written before processing it.
259
601
  n = Rewriter::rewrite(n);
260
601
  n = makeBinary(n);
261
601
  n = eliminationPass(n);
262
  // binarize again, in case the elimination pass introduced
263
  // non-binary terms (as can happen by RepeatEliminate, for example).
264
601
  n = makeBinary(n);
265
1202
  vector<Node> toVisit;
266
601
  toVisit.push_back(n);
267
268
11247
  while (!toVisit.empty())
269
  {
270
10646
    Node current = toVisit.back();
271
5323
    uint64_t currentNumChildren = current.getNumChildren();
272
5323
    if (d_bvToIntCache.find(current) == d_bvToIntCache.end())
273
    {
274
      // This is the first time we visit this node and it is not in the cache.
275
      // We mark this node as visited but not translated by assiging
276
      // a null node to it.
277
2284
      d_bvToIntCache[current] = Node();
278
      // all the node's children are added to the stack to be visited
279
      // before visiting this node again.
280
2284
      toVisit.insert(toVisit.end(), current.begin(), current.end());
281
      // If this is a UF applicatinon, we also add the function to
282
      // toVisit.
283
2284
      if (current.getKind() == kind::APPLY_UF)
284
      {
285
60
        toVisit.push_back(current.getOperator());
286
      }
287
    }
288
    else
289
    {
290
      // We already visited and translated this node
291
3039
      if (!d_bvToIntCache[current].get().isNull())
292
      {
293
        // We are done computing the translation for current
294
755
        toVisit.pop_back();
295
      }
296
      else
297
      {
298
        // We are now visiting current on the way back up.
299
        // This is when we do the actual translation.
300
4568
        Node translation;
301
2284
        if (currentNumChildren == 0)
302
        {
303
878
          translation = translateNoChildren(current);
304
        }
305
        else
306
        {
307
          /**
308
           * The current node has children.
309
           * Since we are on the way back up,
310
           * these children were already translated.
311
           * We save their translation for easy access.
312
           * If the node's kind is APPLY_UF,
313
           * we also need to include the translated uninterpreted function in
314
           * this list.
315
           */
316
2812
          vector<Node> translated_children;
317
1406
          if (current.getKind() == kind::APPLY_UF)
318
          {
319
60
            translated_children.push_back(
320
120
                d_bvToIntCache[current.getOperator()]);
321
          }
322
3784
          for (uint64_t i = 0; i < currentNumChildren; i++)
323
          {
324
2378
            translated_children.push_back(d_bvToIntCache[current[i]]);
325
          }
326
1406
          translation = translateWithChildren(current, translated_children);
327
        }
328
        // Map the current node to its translation in the cache.
329
2284
        d_bvToIntCache[current] = translation;
330
        // Also map the translation to itself.
331
2284
        d_bvToIntCache[translation] = translation;
332
2284
        toVisit.pop_back();
333
      }
334
    }
335
  }
336
1202
  return d_bvToIntCache[n].get();
337
}
338
339
1406
Node BVToInt::translateWithChildren(Node original,
340
                                    const vector<Node>& translated_children)
341
{
342
  // The translation of the original node is determined by the kind of
343
  // the node.
344
1406
  kind::Kind_t oldKind = original.getKind();
345
  // ultbv and sltbv were supposed to be eliminated before this point.
346
1406
  Assert(oldKind != kind::BITVECTOR_ULTBV);
347
1406
  Assert(oldKind != kind::BITVECTOR_SLTBV);
348
  // The following variable will only be used in assertions.
349
1406
  CVC5_UNUSED uint64_t originalNumChildren = original.getNumChildren();
350
1406
  Node returnNode;
351
1406
  switch (oldKind)
352
  {
353
162
    case kind::BITVECTOR_ADD:
354
    {
355
162
      Assert(originalNumChildren == 2);
356
162
      uint64_t bvsize = original[0].getType().getBitVectorSize();
357
324
      Node plus = d_nm->mkNode(kind::PLUS, translated_children);
358
324
      Node p2 = pow2(bvsize);
359
162
      returnNode = d_nm->mkNode(kind::INTS_MODULUS_TOTAL, plus, p2);
360
162
      break;
361
    }
362
6
    case kind::BITVECTOR_MULT:
363
    {
364
6
      Assert(originalNumChildren == 2);
365
6
      uint64_t bvsize = original[0].getType().getBitVectorSize();
366
12
      Node mult = d_nm->mkNode(kind::MULT, translated_children);
367
12
      Node p2 = pow2(bvsize);
368
6
      returnNode = d_nm->mkNode(kind::INTS_MODULUS_TOTAL, mult, p2);
369
6
      break;
370
    }
371
8
    case kind::BITVECTOR_UDIV:
372
    {
373
8
      uint64_t bvsize = original[0].getType().getBitVectorSize();
374
      // we use an ITE for the case where the second operand is 0.
375
16
      Node pow2BvSize = pow2(bvsize);
376
      Node divNode =
377
16
          d_nm->mkNode(kind::INTS_DIVISION_TOTAL, translated_children);
378
40
      returnNode = d_nm->mkNode(
379
          kind::ITE,
380
16
          d_nm->mkNode(kind::EQUAL, translated_children[1], d_zero),
381
16
          d_nm->mkNode(kind::MINUS, pow2BvSize, d_one),
382
          divNode);
383
8
      break;
384
    }
385
    case kind::BITVECTOR_UREM:
386
    {
387
      // we use an ITE for the case where the second operand is 0.
388
      Node modNode =
389
          d_nm->mkNode(kind::INTS_MODULUS_TOTAL, translated_children);
390
      returnNode = d_nm->mkNode(
391
          kind::ITE,
392
          d_nm->mkNode(kind::EQUAL, translated_children[1], d_zero),
393
          translated_children[0],
394
          modNode);
395
      break;
396
    }
397
28
    case kind::BITVECTOR_NOT:
398
    {
399
28
      uint64_t bvsize = original[0].getType().getBitVectorSize();
400
      // we use a specified function to generate the node.
401
28
      returnNode = createBVNotNode(translated_children[0], bvsize);
402
28
      break;
403
    }
404
62
    case kind::BITVECTOR_TO_NAT:
405
    {
406
      // In this case, we already translated the child to integer.
407
      // So the result is the translated child.
408
62
      returnNode = translated_children[0];
409
62
      break;
410
    }
411
76
    case kind::INT_TO_BITVECTOR:
412
    {
413
      // ((_ int2bv n) t) ---> (mod t 2^n)
414
76
      size_t sz = original.getOperator().getConst<IntToBitVector>().d_size;
415
228
      returnNode = d_nm->mkNode(
416
228
          kind::INTS_MODULUS_TOTAL, translated_children[0], pow2(sz));
417
    }
418
76
    break;
419
41
    case kind::BITVECTOR_AND:
420
    {
421
      // We support three configurations:
422
      // 1. translating to IAND
423
      // 2. translating back to BV (using BITVECTOR_TO_NAT and INT_TO_BV
424
      // operators)
425
      // 3. translating into a sum
426
41
      uint64_t bvsize = original[0].getType().getBitVectorSize();
427
41
      if (options::solveBVAsInt() == options::SolveBVAsIntMode::IAND)
428
      {
429
34
        Node iAndOp = d_nm->mkConst(IntAnd(bvsize));
430
51
        returnNode = d_nm->mkNode(
431
34
            kind::IAND, iAndOp, translated_children[0], translated_children[1]);
432
      }
433
24
      else if (options::solveBVAsInt() == options::SolveBVAsIntMode::BV)
434
      {
435
        // translate the children back to BV
436
18
        Node intToBVOp = d_nm->mkConst<IntToBitVector>(IntToBitVector(bvsize));
437
18
        Node x = translated_children[0];
438
18
        Node y = translated_children[1];
439
18
        Node bvx = d_nm->mkNode(intToBVOp, x);
440
18
        Node bvy = d_nm->mkNode(intToBVOp, y);
441
        // perform bvand on the bit-vectors
442
18
        Node bvand = d_nm->mkNode(kind::BITVECTOR_AND, bvx, bvy);
443
        // translate the result to integers
444
9
        returnNode = d_nm->mkNode(kind::BITVECTOR_TO_NAT, bvand);
445
      }
446
      else
447
      {
448
15
        Assert(options::solveBVAsInt() == options::SolveBVAsIntMode::SUM);
449
        // Construct a sum of ites, based on granularity.
450
15
        Assert(translated_children.size() == 2);
451
15
        returnNode =
452
45
            d_iandUtils.createSumNode(translated_children[0],
453
15
                                      translated_children[1],
454
                                      bvsize,
455
                                      options::BVAndIntegerGranularity());
456
      }
457
41
      break;
458
    }
459
2
    case kind::BITVECTOR_SHL:
460
    {
461
      /**
462
       * a << b is a*2^b.
463
       * The exponentiation is simulated by an ite.
464
       * Only cases where b <= bit width are considered.
465
       * Otherwise, the result is 0.
466
       */
467
2
      uint64_t bvsize = original[0].getType().getBitVectorSize();
468
2
      returnNode = createShiftNode(translated_children, bvsize, true);
469
2
      break;
470
    }
471
82
    case kind::BITVECTOR_LSHR:
472
    {
473
      /**
474
       * a >> b is a div 2^b.
475
       * The exponentiation is simulated by an ite.
476
       * Only cases where b <= bit width are considered.
477
       * Otherwise, the result is 0.
478
       */
479
82
      uint64_t bvsize = original[0].getType().getBitVectorSize();
480
82
      returnNode = createShiftNode(translated_children, bvsize, false);
481
82
      break;
482
    }
483
6
    case kind::BITVECTOR_ASHR:
484
    {
485
      /*  From SMT-LIB2:
486
       *  (bvashr s t) abbreviates
487
       *     (ite (= ((_ extract |m-1| |m-1|) s) #b0)
488
       *          (bvlshr s t)
489
       *          (bvnot (bvlshr (bvnot s) t)))
490
       *
491
       *  Equivalently:
492
       *  (bvashr s t) abbreviates
493
       *      (ite (bvult s 100000...)
494
       *           (bvlshr s t)
495
       *           (bvnot (bvlshr (bvnot s) t)))
496
       *
497
       */
498
6
      uint64_t bvsize = original[0].getType().getBitVectorSize();
499
      // signed_min is 100000...
500
12
      Node signed_min = pow2(bvsize - 1);
501
      Node condition =
502
12
          d_nm->mkNode(kind::LT, translated_children[0], signed_min);
503
12
      Node thenNode = createShiftNode(translated_children, bvsize, false);
504
6
      vector<Node> children = {createBVNotNode(translated_children[0], bvsize),
505
12
                               translated_children[1]};
506
      Node elseNode =
507
12
          createBVNotNode(createShiftNode(children, bvsize, false), bvsize);
508
6
      returnNode = d_nm->mkNode(kind::ITE, condition, thenNode, elseNode);
509
6
      break;
510
    }
511
    case kind::BITVECTOR_ITE:
512
    {
513
      // Lifted to a boolean ite.
514
      Node cond = d_nm->mkNode(kind::EQUAL, translated_children[0], d_one);
515
      returnNode = d_nm->mkNode(
516
          kind::ITE, cond, translated_children[1], translated_children[2]);
517
      break;
518
    }
519
    case kind::BITVECTOR_ZERO_EXTEND:
520
    {
521
      returnNode = translated_children[0];
522
      break;
523
    }
524
8
    case kind::BITVECTOR_SIGN_EXTEND:
525
    {
526
8
      uint64_t bvsize = original[0].getType().getBitVectorSize();
527
16
      Node arg = translated_children[0];
528
8
      if (arg.isConst())
529
      {
530
        Rational c(arg.getConst<Rational>());
531
        Rational twoToKMinusOne(intpow2(bvsize - 1));
532
        uint64_t amount = bv::utils::getSignExtendAmount(original);
533
        /* if the msb is 0, this is like zero_extend.
534
         *  msb is 0 <-> the value is less than 2^{bvsize-1}
535
         */
536
        if (c < twoToKMinusOne || amount == 0)
537
        {
538
          returnNode = arg;
539
        }
540
        else
541
        {
542
          /* otherwise, we add the integer equivalent of
543
           * 11....1 `amount` times
544
           */
545
          Rational max_of_amount = intpow2(amount) - 1;
546
          Rational mul = max_of_amount * intpow2(bvsize);
547
          Rational sum = mul + c;
548
          returnNode = d_nm->mkConst(sum);
549
        }
550
      }
551
      else
552
      {
553
8
        uint64_t amount = bv::utils::getSignExtendAmount(original);
554
8
        if (amount == 0)
555
        {
556
6
          returnNode = translated_children[0];
557
        }
558
        else
559
        {
560
4
          Rational twoToKMinusOne(intpow2(bvsize - 1));
561
4
          Node minSigned = d_nm->mkConst(twoToKMinusOne);
562
          /* condition checks whether the msb is 1.
563
           * This holds when the integer value is smaller than
564
           * 100...0, which is 2^{bvsize-1}.
565
           */
566
4
          Node condition = d_nm->mkNode(kind::LT, arg, minSigned);
567
4
          Node thenResult = arg;
568
4
          Node left = maxInt(amount);
569
4
          Node mul = d_nm->mkNode(kind::MULT, left, pow2(bvsize));
570
4
          Node sum = d_nm->mkNode(kind::PLUS, mul, arg);
571
4
          Node elseResult = sum;
572
4
          Node ite = d_nm->mkNode(kind::ITE, condition, thenResult, elseResult);
573
2
          returnNode = ite;
574
        }
575
      }
576
8
      break;
577
    }
578
8
    case kind::BITVECTOR_CONCAT:
579
    {
580
      // (concat a b) translates to a*2^k+b, k being the bitwidth of b.
581
8
      uint64_t bvsizeRight = original[1].getType().getBitVectorSize();
582
16
      Node pow2BvSizeRight = pow2(bvsizeRight);
583
      Node a =
584
16
          d_nm->mkNode(kind::MULT, translated_children[0], pow2BvSizeRight);
585
16
      Node b = translated_children[1];
586
8
      returnNode = d_nm->mkNode(kind::PLUS, a, b);
587
8
      break;
588
    }
589
4
    case kind::BITVECTOR_EXTRACT:
590
    {
591
      // ((_ extract i j) a) is a / 2^j mod 2^{i-j+1}
592
      // original = a[i:j]
593
4
      uint64_t i = bv::utils::getExtractHigh(original);
594
4
      uint64_t j = bv::utils::getExtractLow(original);
595
4
      Assert(i >= j);
596
4
      Node div = d_nm->mkNode(
597
8
          kind::INTS_DIVISION_TOTAL, translated_children[0], pow2(j));
598
4
      returnNode = modpow2(div, i - j + 1);
599
4
      break;
600
    }
601
255
    case kind::EQUAL:
602
    {
603
255
      returnNode = d_nm->mkNode(kind::EQUAL, translated_children);
604
255
      break;
605
    }
606
128
    case kind::BITVECTOR_ULT:
607
    {
608
128
      returnNode = d_nm->mkNode(kind::LT, translated_children);
609
128
      break;
610
    }
611
    case kind::BITVECTOR_ULE:
612
    {
613
      returnNode = d_nm->mkNode(kind::LEQ, translated_children);
614
      break;
615
    }
616
    case kind::BITVECTOR_UGT:
617
    {
618
      returnNode = d_nm->mkNode(kind::GT, translated_children);
619
      break;
620
    }
621
    case kind::BITVECTOR_UGE:
622
    {
623
      returnNode = d_nm->mkNode(kind::GEQ, translated_children);
624
      break;
625
    }
626
    case kind::LT:
627
    {
628
      returnNode = d_nm->mkNode(kind::LT, translated_children);
629
      break;
630
    }
631
    case kind::LEQ:
632
    {
633
      returnNode = d_nm->mkNode(kind::LEQ, translated_children);
634
      break;
635
    }
636
    case kind::GT:
637
    {
638
      returnNode = d_nm->mkNode(kind::GT, translated_children);
639
      break;
640
    }
641
56
    case kind::GEQ:
642
    {
643
56
      returnNode = d_nm->mkNode(kind::GEQ, translated_children);
644
56
      break;
645
    }
646
2
    case kind::ITE:
647
    {
648
2
      returnNode = d_nm->mkNode(oldKind, translated_children);
649
2
      break;
650
    }
651
60
    case kind::APPLY_UF:
652
    {
653
      /**
654
       * higher order logic allows comparing between functions
655
       * The translation does not support this,
656
       * as the translated functions may be different outside
657
       * of the bounds that were relevant for the original
658
       * bit-vectors.
659
       */
660
60
      if (childrenTypesChanged(original) && options::ufHo())
661
      {
662
        throw TypeCheckingExceptionPrivate(
663
            original,
664
            string("Cannot translate to Int: ") + original.toString());
665
      }
666
      // Insert the translated application term to the cache
667
60
      returnNode = d_nm->mkNode(kind::APPLY_UF, translated_children);
668
      // Add range constraints if necessary.
669
      // If the original range was a BV sort, the original application of
670
      // the function Must be within the range determined by the
671
      // bitwidth.
672
60
      if (original.getType().isBitVector())
673
      {
674
20
        d_rangeAssertions.insert(mkRangeConstraint(
675
20
            returnNode, original.getType().getBitVectorSize()));
676
      }
677
60
      break;
678
    }
679
47
    case kind::BOUND_VAR_LIST:
680
    {
681
47
      returnNode = d_nm->mkNode(oldKind, translated_children);
682
47
      break;
683
    }
684
47
    case kind::FORALL:
685
    {
686
47
      returnNode = translateQuantifiedFormula(original);
687
47
      break;
688
    }
689
318
    default:
690
    {
691
318
      Assert(oldKind != kind::EXISTS);  // Exists is eliminated by the rewriter.
692
      // In the default case, we have reached an operator that we do not
693
      // translate directly to integers. The children whose types have
694
      // changed from bv to int should be adjusted back to bv and then
695
      // this term is reconstructed.
696
636
      TypeNode resultingType;
697
318
      if (original.getType().isBitVector())
698
      {
699
4
        resultingType = d_nm->integerType();
700
      }
701
      else
702
      {
703
314
        resultingType = original.getType();
704
      }
705
      Node reconstruction =
706
636
          reconstructNode(original, resultingType, translated_children);
707
318
      returnNode = reconstruction;
708
318
      break;
709
    }
710
  }
711
1406
  Trace("bv-to-int-debug") << "original: " << original << endl;
712
1406
  Trace("bv-to-int-debug") << "returnNode: " << returnNode << endl;
713
1406
  return returnNode;
714
}
715
716
878
Node BVToInt::translateNoChildren(Node original)
717
{
718
878
  SkolemManager* sm = d_nm->getSkolemManager();
719
878
  Node translation;
720
878
  Assert(original.isVar() || original.isConst());
721
878
  if (original.isVar())
722
  {
723
482
    if (original.getType().isBitVector())
724
    {
725
      // For bit-vector variables, we create fresh integer variables.
726
352
      if (original.getKind() == kind::BOUND_VARIABLE)
727
      {
728
        // Range constraints for the bound integer variables are not added now.
729
        // they will be added once the quantifier itself is handled.
730
94
        std::stringstream ss;
731
47
        ss << original;
732
47
        translation = d_nm->mkBoundVar(ss.str() + "_int", d_nm->integerType());
733
      }
734
      else
735
      {
736
        // New integer variables  that are not bound (symbolic constants)
737
        // are added together with range constraints induced by the
738
        // bit-width of the original bit-vector variables.
739
        Node newVar = sm->mkDummySkolem("__bvToInt_var",
740
610
                                        d_nm->integerType(),
741
                                        "Variable introduced in bvToInt "
742
                                        "pass instead of original variable "
743
1220
                                            + original.toString());
744
305
        uint64_t bvsize = original.getType().getBitVectorSize();
745
305
        translation = newVar;
746
305
        d_rangeAssertions.insert(mkRangeConstraint(newVar, bvsize));
747
305
        defineBVUFAsIntUF(original, newVar);
748
      }
749
    }
750
130
    else if (original.getType().isFunction())
751
    {
752
36
      translation = translateFunctionSymbol(original);
753
    }
754
    else
755
    {
756
      // variables other than bit-vector variables and function symbols
757
      // are left intact
758
94
      translation = original;
759
    }
760
  }
761
  else
762
  {
763
    // original is a const
764
396
    if (original.getKind() == kind::CONST_BITVECTOR)
765
    {
766
      // Bit-vector constants are transformed into their integer value.
767
308
      BitVector constant(original.getConst<BitVector>());
768
308
      Integer c = constant.toInteger();
769
154
      translation = d_nm->mkConst<Rational>(c);
770
    }
771
    else
772
    {
773
      // Other constants stay the same.
774
242
      translation = original;
775
    }
776
  }
777
878
  return translation;
778
}
779
780
36
Node BVToInt::translateFunctionSymbol(Node bvUF)
781
{
782
  // construct the new function symbol.
783
36
  Node intUF;
784
72
  TypeNode tn = bvUF.getType();
785
72
  TypeNode bvRange = tn.getRangeType();
786
  // The function symbol has not been converted yet
787
72
  vector<TypeNode> bvDomain = tn.getArgTypes();
788
72
  vector<TypeNode> intDomain;
789
  /**
790
   * if the original range is a bit-vector sort,
791
   * the new range should be an integer sort.
792
   * Otherwise, we keep the original range.
793
   * Similarly for the domains.
794
   */
795
72
  TypeNode intRange = bvRange.isBitVector() ? d_nm->integerType() : bvRange;
796
74
  for (TypeNode d : bvDomain)
797
  {
798
38
    intDomain.push_back(d.isBitVector() ? d_nm->integerType() : d);
799
  }
800
36
  SkolemManager* sm = d_nm->getSkolemManager();
801
72
  ostringstream os;
802
36
  os << "__bvToInt_fun_" << bvUF << "_int";
803
108
  intUF = sm->mkDummySkolem(
804
72
      os.str(), d_nm->mkFunctionType(intDomain, intRange), "bv2int function");
805
  // introduce a `define-fun` in the smt-engine to keep
806
  // the correspondence between the original
807
  // function symbol and the new one.
808
36
  defineBVUFAsIntUF(bvUF, intUF);
809
72
  return intUF;
810
}
811
812
341
void BVToInt::defineBVUFAsIntUF(Node bvUF, Node intUF)
813
{
814
  // The resulting term
815
682
  Node result;
816
  // The type of the resulting term
817
682
  TypeNode resultType;
818
  // symbolic arguments of original function
819
682
  vector<Node> args;
820
341
  if (!bvUF.getType().isFunction()) {
821
    // bvUF is a variable.
822
    // in this case, the result is just the original term
823
    // (it will be casted later if needed)
824
305
    result = intUF;
825
305
    resultType = bvUF.getType();
826
  } else {
827
    // bvUF is a function with arguments
828
    // The arguments need to be casted as well.
829
72
    TypeNode tn = bvUF.getType();
830
36
    resultType = tn.getRangeType();
831
72
    vector<TypeNode> bvDomain = tn.getArgTypes();
832
    // children of the new symbolic application
833
72
    vector<Node> achildren;
834
36
    achildren.push_back(intUF);
835
36
    int i = 0;
836
74
    for (const TypeNode& d : bvDomain)
837
    {
838
      // Each bit-vector argument is casted to a natural number
839
      // Other arguments are left intact.
840
76
      Node fresh_bound_var = d_nm->mkBoundVar(d);
841
38
      args.push_back(fresh_bound_var);
842
76
      Node castedArg = args[i];
843
38
      if (d.isBitVector())
844
      {
845
29
        castedArg = castToType(castedArg, d_nm->integerType());
846
      }
847
38
      achildren.push_back(castedArg);
848
38
      i++;
849
    }
850
36
    result = d_nm->mkNode(kind::APPLY_UF, achildren);
851
  }
852
  // If the result is BV, it needs to be casted back.
853
341
  result = castToType(result, resultType);
854
  // add the substitution to the preprocessing context, which ensures the
855
  // model for bvUF is correct, as well as substituting it in the input
856
  // assertions when necessary.
857
341
  if (!args.empty())
858
  {
859
108
    result = d_nm->mkNode(
860
72
        kind::LAMBDA, d_nm->mkNode(kind::BOUND_VAR_LIST, args), result);
861
  }
862
341
  d_preprocContext->addSubstitution(bvUF, result);
863
341
}
864
865
60
bool BVToInt::childrenTypesChanged(Node n)
866
{
867
60
  bool result = false;
868
72
  for (const Node& child : n)
869
  {
870
72
    TypeNode originalType = child.getType();
871
72
    TypeNode newType = d_bvToIntCache[child].get().getType();
872
60
    if (!newType.isSubtypeOf(originalType))
873
    {
874
48
      result = true;
875
48
      break;
876
    }
877
  }
878
60
  return result;
879
}
880
881
1169
Node BVToInt::castToType(Node n, TypeNode tn)
882
{
883
  // If there is no reason to cast, return the
884
  // original node.
885
1169
  if (n.getType().isSubtypeOf(tn))
886
  {
887
819
    return n;
888
  }
889
  // We only case int to bv or vice verse.
890
350
  Assert((n.getType().isBitVector() && tn.isInteger())
891
         || (n.getType().isInteger() && tn.isBitVector()));
892
350
  if (n.getType().isInteger())
893
  {
894
317
    Assert(tn.isBitVector());
895
317
    unsigned bvsize = tn.getBitVectorSize();
896
634
    Node intToBVOp = d_nm->mkConst<IntToBitVector>(IntToBitVector(bvsize));
897
317
    return d_nm->mkNode(intToBVOp, n);
898
  }
899
33
  Assert(n.getType().isBitVector());
900
33
  Assert(tn.isInteger());
901
33
  return d_nm->mkNode(kind::BITVECTOR_TO_NAT, n);
902
}
903
904
318
Node BVToInt::reconstructNode(Node originalNode,
905
                              TypeNode resultType,
906
                              const vector<Node>& translated_children)
907
{
908
  // first, we adjust the children of the node as needed.
909
  // re-construct the term with the adjusted children.
910
318
  kind::Kind_t oldKind = originalNode.getKind();
911
636
  NodeBuilder builder(oldKind);
912
318
  if (originalNode.getMetaKind() == kind::metakind::PARAMETERIZED)
913
  {
914
4
    builder << originalNode.getOperator();
915
  }
916
799
  for (size_t i = 0; i < originalNode.getNumChildren(); i++)
917
  {
918
962
    Node originalChild = originalNode[i];
919
962
    Node translatedChild = translated_children[i];
920
962
    Node adjustedChild = castToType(translatedChild, originalChild.getType());
921
481
    builder << adjustedChild;
922
  }
923
318
  Node reconstruction = builder.constructNode();
924
  // cast to tn in case the reconstruction is a bit-vector.
925
318
  reconstruction = castToType(reconstruction, resultType);
926
636
  return reconstruction;
927
}
928
929
9850
BVToInt::BVToInt(PreprocessingPassContext* preprocContext)
930
    : PreprocessingPass(preprocContext, "bv-to-int"),
931
      d_binarizeCache(preprocContext->getUserContext()),
932
      d_eliminationCache(preprocContext->getUserContext()),
933
      d_rebuildCache(preprocContext->getUserContext()),
934
      d_bvToIntCache(preprocContext->getUserContext()),
935
9850
      d_rangeAssertions(preprocContext->getUserContext())
936
{
937
9850
  d_nm = NodeManager::currentNM();
938
9850
  d_zero = d_nm->mkConst<Rational>(0);
939
9850
  d_one = d_nm->mkConst<Rational>(1);
940
9850
};
941
942
205
PreprocessingPassResult BVToInt::applyInternal(
943
    AssertionPipeline* assertionsToPreprocess)
944
{
945
806
  for (uint64_t i = 0; i < assertionsToPreprocess->size(); ++i)
946
  {
947
1202
    Node bvNode = (*assertionsToPreprocess)[i];
948
1202
    Node intNode = bvToInt(bvNode);
949
1202
    Node rwNode = Rewriter::rewrite(intNode);
950
601
    Trace("bv-to-int-debug") << "bv node: " << bvNode << std::endl;
951
601
    Trace("bv-to-int-debug") << "int node: " << intNode << std::endl;
952
601
    Trace("bv-to-int-debug") << "rw node: " << rwNode << std::endl;
953
601
    assertionsToPreprocess->replace(i, rwNode);
954
  }
955
205
  addFinalizeRangeAssertions(assertionsToPreprocess);
956
205
  return PreprocessingPassResult::NO_CONFLICT;
957
}
958
959
205
void BVToInt::addFinalizeRangeAssertions(
960
    AssertionPipeline* assertionsToPreprocess)
961
{
962
  // collect the range assertions from d_rangeAssertions
963
  // (which is a context-dependent set)
964
  // into a vector.
965
410
  vector<Node> vec_range;
966
205
  vec_range.assign(d_rangeAssertions.key_begin(), d_rangeAssertions.key_end());
967
  // conjoin all range assertions and add the conjunction
968
  // as a new assertion
969
410
  Node rangeAssertions = Rewriter::rewrite(d_nm->mkAnd(vec_range));
970
205
  assertionsToPreprocess->push_back(rangeAssertions);
971
410
  Trace("bv-to-int-debug") << "range constraints: "
972
205
                           << rangeAssertions.toString() << std::endl;
973
205
}
974
975
96
Node BVToInt::createShiftNode(vector<Node> children,
976
                              uint64_t bvsize,
977
                              bool isLeftShift)
978
{
979
  /**
980
   * from SMT-LIB:
981
   * [[(bvshl s t)]] := nat2bv[m](bv2nat([[s]]) * 2^(bv2nat([[t]])))
982
   * [[(bvlshr s t)]] := nat2bv[m](bv2nat([[s]]) div 2^(bv2nat([[t]])))
983
   * Since we don't have exponentiation, we use an ite.
984
   * Important note: below we use INTS_DIVISION_TOTAL, which is safe here
985
   * because we divide by 2^... which is never 0.
986
   */
987
192
  Node x = children[0];
988
192
  Node y = children[1];
989
  // shifting by const is eliminated by the theory rewriter
990
96
  Assert(!y.isConst());
991
96
  Node ite = d_zero;
992
192
  Node body;
993
540
  for (uint64_t i = 0; i < bvsize; i++)
994
  {
995
444
    if (isLeftShift)
996
    {
997
64
      body = d_nm->mkNode(kind::INTS_MODULUS_TOTAL,
998
32
                          d_nm->mkNode(kind::MULT, x, pow2(i)),
999
32
                          pow2(bvsize));
1000
    }
1001
    else
1002
    {
1003
428
      body = d_nm->mkNode(kind::INTS_DIVISION_TOTAL, x, pow2(i));
1004
    }
1005
1332
    ite = d_nm->mkNode(kind::ITE,
1006
888
                       d_nm->mkNode(kind::EQUAL, y, d_nm->mkConst<Rational>(i)),
1007
                       body,
1008
                       ite);
1009
  }
1010
192
  return ite;
1011
}
1012
1013
47
Node BVToInt::translateQuantifiedFormula(Node quantifiedNode)
1014
{
1015
47
  kind::Kind_t k = quantifiedNode.getKind();
1016
94
  Node boundVarList = quantifiedNode[0];
1017
47
  Assert(boundVarList.getKind() == kind::BOUND_VAR_LIST);
1018
  // Since bit-vector variables are being translated to
1019
  // integer variables, we need to substitute the new ones
1020
  // for the old ones.
1021
94
  vector<Node> oldBoundVars;
1022
94
  vector<Node> newBoundVars;
1023
94
  vector<Node> rangeConstraints;
1024
94
  for (Node bv : quantifiedNode[0])
1025
  {
1026
47
    oldBoundVars.push_back(bv);
1027
47
    if (bv.getType().isBitVector())
1028
    {
1029
      // bit-vector variables are replaced by integer ones.
1030
      // the new variables induce range constraints based on the
1031
      // original bit-width.
1032
94
      Node newBoundVar = d_bvToIntCache[bv];
1033
47
      newBoundVars.push_back(newBoundVar);
1034
47
      rangeConstraints.push_back(
1035
94
          mkRangeConstraint(newBoundVar, bv.getType().getBitVectorSize()));
1036
    }
1037
    else
1038
    {
1039
      // variables that are not bit-vectors are not changed
1040
      newBoundVars.push_back(bv);
1041
    }
1042
  }
1043
1044
  // the body of the quantifier
1045
94
  Node matrix = d_bvToIntCache[quantifiedNode[1]];
1046
  // make the substitution
1047
47
  matrix = matrix.substitute(oldBoundVars.begin(),
1048
                             oldBoundVars.end(),
1049
                             newBoundVars.begin(),
1050
                             newBoundVars.end());
1051
  // A node to represent all the range constraints.
1052
94
  Node ranges = d_nm->mkAnd(rangeConstraints);
1053
  // Add the range constraints to the body of the quantifier.
1054
  // For "exists", this is added conjunctively
1055
  // For "forall", this is added to the left side of an implication.
1056
47
  matrix = d_nm->mkNode(
1057
      k == kind::FORALL ? kind::IMPLIES : kind::AND, ranges, matrix);
1058
  // create the new quantified formula and return it.
1059
94
  Node newBoundVarsList = d_nm->mkNode(kind::BOUND_VAR_LIST, newBoundVars);
1060
47
  Node result = d_nm->mkNode(kind::FORALL, newBoundVarsList, matrix);
1061
94
  return result;
1062
}
1063
1064
40
Node BVToInt::createBVNotNode(Node n, uint64_t bvsize)
1065
{
1066
40
  return d_nm->mkNode(kind::MINUS, maxInt(bvsize), n);
1067
}
1068
1069
}  // namespace passes
1070
}  // namespace preprocessing
1071
29337
}  // namespace cvc5