GCC Code Coverage Report
Directory: . Exec Total Coverage
File: src/preprocessing/passes/bv_to_int.cpp Lines: 421 471 89.4 %
Date: 2021-05-22 Branches: 844 2045 41.3 %

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