GCC Code Coverage Report
Directory: . Exec Total Coverage
File: src/preprocessing/passes/bv_to_int.cpp Lines: 430 480 89.6 %
Date: 2021-09-29 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
526
Rational intpow2(uint64_t b)
52
{
53
526
  return Rational(Integer(2).pow(b), Integer(1));
54
}
55
56
} //end empty namespace
57
58
198
Node BVToInt::mkRangeConstraint(Node newVar, uint64_t k)
59
{
60
396
  Node lower = d_nm->mkNode(kind::LEQ, d_zero, newVar);
61
396
  Node upper = d_nm->mkNode(kind::LT, newVar, pow2(k));
62
396
  Node result = d_nm->mkNode(kind::AND, lower, upper);
63
396
  return rewrite(result);
64
}
65
66
24
Node BVToInt::maxInt(uint64_t k)
67
{
68
24
  Assert(k > 0);
69
48
  Rational max_value = intpow2(k) - 1;
70
48
  return d_nm->mkConst<Rational>(max_value);
71
}
72
73
496
Node BVToInt::pow2(uint64_t k)
74
{
75
496
  Assert(k >= 0);
76
496
  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
578
Node BVToInt::makeBinary(Node n)
89
{
90
1175
  for (TNode current : NodeDfsIterable(n,
91
                                       VisitOrder::POSTORDER,
92
                                       // skip visited nodes
93
3438
                                       [this](TNode tn) {
94
3438
                                         return d_binarizeCache.find(tn)
95
3438
                                                != d_binarizeCache.end();
96
5769
                                       }))
97
  {
98
1175
    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
1175
    kind::Kind_t k = current.getKind();
105
1175
    if ((numChildren > 2)
106
4
        && (k == kind::BITVECTOR_ADD || k == kind::BITVECTOR_MULT
107
4
            || k == kind::BITVECTOR_AND || k == kind::BITVECTOR_OR
108
4
            || 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
1175
    else if (numChildren > 0)
122
    {
123
      // current has children, but we do not binarize it
124
1522
      NodeBuilder builder(k);
125
761
      if (current.getMetaKind() == kind::metakind::PARAMETERIZED)
126
      {
127
79
        builder << current.getOperator();
128
      }
129
2042
      for (Node child : current)
130
      {
131
1281
        builder << d_binarizeCache[child].get();
132
      }
133
761
      d_binarizeCache[current] = builder.constructNode();
134
    }
135
    else
136
    {
137
      // current has no children
138
414
      d_binarizeCache[current] = current;
139
    }
140
  }
141
578
  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
289
Node BVToInt::eliminationPass(Node n)
153
{
154
578
  std::vector<Node> toVisit;
155
289
  toVisit.push_back(n);
156
578
  Node current;
157
5253
  while (!toVisit.empty())
158
  {
159
2482
    current = toVisit.back();
160
    // assert that the node is binarized
161
    // The following variable is only used in assertions
162
2482
    CVC5_UNUSED kind::Kind_t k = current.getKind();
163
2482
    uint64_t numChildren = current.getNumChildren();
164
2482
    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
2482
    toVisit.pop_back();
169
    bool inEliminationCache =
170
2482
        (d_eliminationCache.find(current) != d_eliminationCache.end());
171
    bool inRebuildCache =
172
2482
        (d_rebuildCache.find(current) != d_rebuildCache.end());
173
2482
    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
2148
                                  RewriteRule<SgeEliminate>>::apply(current);
198
199
      // save in the cache
200
1074
      d_eliminationCache[current] = currentEliminated;
201
      // also assign the eliminated now to itself to avoid revisiting.
202
1074
      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
1074
      d_rebuildCache[currentEliminated] = Node();
206
      // Push the eliminated node to the stack
207
1074
      toVisit.push_back(currentEliminated);
208
      // Add the children to the stack for future processing.
209
1074
      toVisit.insert(
210
2148
          toVisit.end(), currentEliminated.begin(), currentEliminated.end());
211
    }
212
2482
    if (inRebuildCache)
213
    {
214
      // current was already added to the rebuild cache.
215
1408
      if (d_rebuildCache[current].get().isNull())
216
      {
217
        // current wasn't rebuilt yet.
218
1074
        numChildren = current.getNumChildren();
219
1074
        if (numChildren == 0)
220
        {
221
          // We only eliminate operators that are not nullary.
222
414
          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
1320
          NodeBuilder builder(current.getKind());
229
660
          if (current.getMetaKind() == kind::metakind::PARAMETERIZED)
230
          {
231
67
            builder << current.getOperator();
232
          }
233
1779
          for (Node child : current)
234
          {
235
1119
            Assert(d_eliminationCache.find(child) != d_eliminationCache.end());
236
2238
            Node eliminatedChild = d_eliminationCache[child];
237
1119
            Assert(d_rebuildCache.find(eliminatedChild) != d_eliminationCache.end());
238
1119
            Assert(!d_rebuildCache[eliminatedChild].get().isNull());
239
1119
            builder << d_rebuildCache[eliminatedChild].get();
240
          }
241
660
          d_rebuildCache[current] = builder.constructNode();
242
        }
243
      }
244
    }
245
  }
246
289
  Assert(d_eliminationCache.find(n) != d_eliminationCache.end());
247
578
  Node eliminated = d_eliminationCache[n];
248
289
  Assert(d_rebuildCache.find(eliminated) != d_rebuildCache.end());
249
289
  Assert(!d_rebuildCache[eliminated].get().isNull());
250
578
  return d_rebuildCache[eliminated];
251
}
252
253
/**
254
 * Translate n to Integers via post-order traversal.
255
 */
256
289
Node BVToInt::bvToInt(Node n)
257
{
258
  // make sure the node is re-written before processing it.
259
289
  n = rewrite(n);
260
289
  n = makeBinary(n);
261
289
  n = eliminationPass(n);
262
  // binarize again, in case the elimination pass introduced
263
  // non-binary terms (as can happen by RepeatEliminate, for example).
264
289
  n = makeBinary(n);
265
578
  vector<Node> toVisit;
266
289
  toVisit.push_back(n);
267
268
5347
  while (!toVisit.empty())
269
  {
270
5058
    Node current = toVisit.back();
271
2529
    uint64_t currentNumChildren = current.getNumChildren();
272
2529
    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
1085
      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
1085
      toVisit.insert(toVisit.end(), current.begin(), current.end());
281
      // If this is a UF applicatinon, we also add the function to
282
      // toVisit.
283
1085
      if (current.getKind() == kind::APPLY_UF)
284
      {
285
38
        toVisit.push_back(current.getOperator());
286
      }
287
    }
288
    else
289
    {
290
      // We already visited and translated this node
291
1444
      if (!d_bvToIntCache[current].get().isNull())
292
      {
293
        // We are done computing the translation for current
294
359
        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
2170
        Node translation;
301
1085
        if (currentNumChildren == 0)
302
        {
303
427
          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
1316
          vector<Node> translated_children;
317
658
          if (current.getKind() == kind::APPLY_UF)
318
          {
319
38
            translated_children.push_back(
320
76
                d_bvToIntCache[current.getOperator()]);
321
          }
322
1775
          for (uint64_t i = 0; i < currentNumChildren; i++)
323
          {
324
1117
            translated_children.push_back(d_bvToIntCache[current[i]]);
325
          }
326
658
          translation = translateWithChildren(current, translated_children);
327
        }
328
        // Map the current node to its translation in the cache.
329
1085
        d_bvToIntCache[current] = translation;
330
        // Also map the translation to itself.
331
1085
        d_bvToIntCache[translation] = translation;
332
1085
        toVisit.pop_back();
333
      }
334
    }
335
  }
336
578
  return d_bvToIntCache[n].get();
337
}
338
339
658
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
658
  kind::Kind_t oldKind = original.getKind();
345
  // ultbv and sltbv were supposed to be eliminated before this point.
346
658
  Assert(oldKind != kind::BITVECTOR_ULTBV);
347
658
  Assert(oldKind != kind::BITVECTOR_SLTBV);
348
  // The following variable will only be used in assertions.
349
658
  CVC5_UNUSED uint64_t originalNumChildren = original.getNumChildren();
350
658
  Node returnNode;
351
658
  switch (oldKind)
352
  {
353
86
    case kind::BITVECTOR_ADD:
354
    {
355
86
      Assert(originalNumChildren == 2);
356
86
      uint64_t bvsize = original[0].getType().getBitVectorSize();
357
172
      Node plus = d_nm->mkNode(kind::PLUS, translated_children);
358
172
      Node p2 = pow2(bvsize);
359
86
      returnNode = d_nm->mkNode(kind::INTS_MODULUS_TOTAL, plus, p2);
360
86
      break;
361
    }
362
4
    case kind::BITVECTOR_MULT:
363
    {
364
4
      Assert(originalNumChildren == 2);
365
4
      uint64_t bvsize = original[0].getType().getBitVectorSize();
366
8
      Node mult = d_nm->mkNode(kind::MULT, translated_children);
367
8
      Node p2 = pow2(bvsize);
368
4
      returnNode = d_nm->mkNode(kind::INTS_MODULUS_TOTAL, mult, p2);
369
4
      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
16
    case kind::BITVECTOR_NOT:
398
    {
399
16
      uint64_t bvsize = original[0].getType().getBitVectorSize();
400
      // we use a specified function to generate the node.
401
16
      returnNode = createBVNotNode(translated_children[0], bvsize);
402
16
      break;
403
    }
404
18
    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
18
      returnNode = translated_children[0];
409
18
      break;
410
    }
411
14
    case kind::INT_TO_BITVECTOR:
412
    {
413
      // ((_ int2bv n) t) ---> (mod t 2^n)
414
14
      size_t sz = original.getOperator().getConst<IntToBitVector>().d_size;
415
42
      returnNode = d_nm->mkNode(
416
42
          kind::INTS_MODULUS_TOTAL, translated_children[0], pow2(sz));
417
    }
418
14
    break;
419
23
    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
23
      uint64_t bvsize = original[0].getType().getBitVectorSize();
427
23
      if (options().smt.solveBVAsInt == options::SolveBVAsIntMode::IAND)
428
      {
429
18
        Node iAndOp = d_nm->mkConst(IntAnd(bvsize));
430
27
        returnNode = d_nm->mkNode(
431
18
            kind::IAND, iAndOp, translated_children[0], translated_children[1]);
432
      }
433
14
      else if (options().smt.solveBVAsInt == options::SolveBVAsIntMode::BV)
434
      {
435
        // translate the children back to BV
436
12
        Node intToBVOp = d_nm->mkConst<IntToBitVector>(IntToBitVector(bvsize));
437
12
        Node x = translated_children[0];
438
12
        Node y = translated_children[1];
439
12
        Node bvx = d_nm->mkNode(intToBVOp, x);
440
12
        Node bvy = d_nm->mkNode(intToBVOp, y);
441
        // perform bvand on the bit-vectors
442
12
        Node bvand = d_nm->mkNode(kind::BITVECTOR_AND, bvx, bvy);
443
        // translate the result to integers
444
6
        returnNode = d_nm->mkNode(kind::BITVECTOR_TO_NAT, bvand);
445
      }
446
      else
447
      {
448
8
        Assert(options().smt.solveBVAsInt == options::SolveBVAsIntMode::SUM);
449
        // Construct a sum of ites, based on granularity.
450
8
        Assert(translated_children.size() == 2);
451
8
        returnNode =
452
32
            d_iandUtils.createSumNode(translated_children[0],
453
8
                                      translated_children[1],
454
                                      bvsize,
455
8
                                      options().smt.BVAndIntegerGranularity);
456
      }
457
23
      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
25
    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
25
      uint64_t bvsize = original[0].getType().getBitVectorSize();
480
25
      returnNode = createShiftNode(translated_children, bvsize, false);
481
25
      break;
482
    }
483
3
    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
3
      uint64_t bvsize = original[0].getType().getBitVectorSize();
499
      // signed_min is 100000...
500
6
      Node signed_min = pow2(bvsize - 1);
501
      Node condition =
502
6
          d_nm->mkNode(kind::LT, translated_children[0], signed_min);
503
6
      Node thenNode = createShiftNode(translated_children, bvsize, false);
504
3
      vector<Node> children = {createBVNotNode(translated_children[0], bvsize),
505
6
                               translated_children[1]};
506
      Node elseNode =
507
6
          createBVNotNode(createShiftNode(children, bvsize, false), bvsize);
508
3
      returnNode = d_nm->mkNode(kind::ITE, condition, thenNode, elseNode);
509
3
      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
5
    case kind::BITVECTOR_CONCAT:
579
    {
580
      // (concat a b) translates to a*2^k+b, k being the bitwidth of b.
581
5
      uint64_t bvsizeRight = original[1].getType().getBitVectorSize();
582
10
      Node pow2BvSizeRight = pow2(bvsizeRight);
583
      Node a =
584
10
          d_nm->mkNode(kind::MULT, translated_children[0], pow2BvSizeRight);
585
10
      Node b = translated_children[1];
586
5
      returnNode = d_nm->mkNode(kind::PLUS, a, b);
587
5
      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
122
    case kind::EQUAL:
602
    {
603
122
      returnNode = d_nm->mkNode(kind::EQUAL, translated_children);
604
122
      break;
605
    }
606
57
    case kind::BITVECTOR_ULT:
607
    {
608
57
      returnNode = d_nm->mkNode(kind::LT, translated_children);
609
57
      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
20
    case kind::GEQ:
642
    {
643
20
      returnNode = d_nm->mkNode(kind::GEQ, translated_children);
644
20
      break;
645
    }
646
1
    case kind::ITE:
647
    {
648
1
      returnNode = d_nm->mkNode(oldKind, translated_children);
649
1
      break;
650
    }
651
38
    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
38
      if (childrenTypesChanged(original) && options().uf.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
38
      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
38
      if (original.getType().isBitVector())
673
      {
674
16
        d_rangeAssertions.insert(mkRangeConstraint(
675
16
            returnNode, original.getType().getBitVectorSize()));
676
      }
677
38
      break;
678
    }
679
23
    case kind::BOUND_VAR_LIST:
680
    {
681
23
      returnNode = d_nm->mkNode(oldKind, translated_children);
682
23
      break;
683
    }
684
23
    case kind::FORALL:
685
    {
686
23
      returnNode = translateQuantifiedFormula(original);
687
23
      break;
688
    }
689
158
    default:
690
    {
691
158
      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
316
      TypeNode resultingType;
697
158
      if (original.getType().isBitVector())
698
      {
699
4
        resultingType = d_nm->integerType();
700
      }
701
      else
702
      {
703
154
        resultingType = original.getType();
704
      }
705
      Node reconstruction =
706
316
          reconstructNode(original, resultingType, translated_children);
707
158
      returnNode = reconstruction;
708
158
      break;
709
    }
710
  }
711
658
  Trace("bv-to-int-debug") << "original: " << original << endl;
712
658
  Trace("bv-to-int-debug") << "returnNode: " << returnNode << endl;
713
658
  return returnNode;
714
}
715
716
427
Node BVToInt::translateNoChildren(Node original)
717
{
718
427
  SkolemManager* sm = d_nm->getSkolemManager();
719
427
  Node translation;
720
427
  Assert(original.isVar() || original.isConst());
721
427
  if (original.isVar())
722
  {
723
243
    if (original.getType().isBitVector())
724
    {
725
      // For bit-vector variables, we create fresh integer variables.
726
190
      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
46
        std::stringstream ss;
731
23
        ss << original;
732
23
        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
334
                                        d_nm->integerType(),
741
                                        "Variable introduced in bvToInt "
742
                                        "pass instead of original variable "
743
668
                                            + original.toString());
744
167
        uint64_t bvsize = original.getType().getBitVectorSize();
745
167
        translation = newVar;
746
167
        d_rangeAssertions.insert(mkRangeConstraint(newVar, bvsize));
747
167
        defineBVUFAsIntUF(original, newVar);
748
      }
749
    }
750
53
    else if (original.getType().isFunction())
751
    {
752
25
      translation = translateFunctionSymbol(original);
753
    }
754
    else
755
    {
756
      // variables other than bit-vector variables and function symbols
757
      // are left intact
758
28
      translation = original;
759
    }
760
  }
761
  else
762
  {
763
    // original is a const
764
184
    if (original.getKind() == kind::CONST_BITVECTOR)
765
    {
766
      // Bit-vector constants are transformed into their integer value.
767
150
      BitVector constant(original.getConst<BitVector>());
768
150
      Integer c = constant.toInteger();
769
75
      translation = d_nm->mkConst<Rational>(c);
770
    }
771
    else
772
    {
773
      // Other constants stay the same.
774
109
      translation = original;
775
    }
776
  }
777
427
  return translation;
778
}
779
780
25
Node BVToInt::translateFunctionSymbol(Node bvUF)
781
{
782
  // construct the new function symbol.
783
25
  Node intUF;
784
50
  TypeNode tn = bvUF.getType();
785
50
  TypeNode bvRange = tn.getRangeType();
786
  // The function symbol has not been converted yet
787
50
  vector<TypeNode> bvDomain = tn.getArgTypes();
788
50
  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
50
  TypeNode intRange = bvRange.isBitVector() ? d_nm->integerType() : bvRange;
796
51
  for (TypeNode d : bvDomain)
797
  {
798
26
    intDomain.push_back(d.isBitVector() ? d_nm->integerType() : d);
799
  }
800
25
  SkolemManager* sm = d_nm->getSkolemManager();
801
50
  ostringstream os;
802
25
  os << "__bvToInt_fun_" << bvUF << "_int";
803
75
  intUF = sm->mkDummySkolem(
804
50
      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
25
  defineBVUFAsIntUF(bvUF, intUF);
809
50
  return intUF;
810
}
811
812
192
void BVToInt::defineBVUFAsIntUF(Node bvUF, Node intUF)
813
{
814
  // The resulting term
815
384
  Node result;
816
  // The type of the resulting term
817
384
  TypeNode resultType;
818
  // symbolic arguments of original function
819
384
  vector<Node> args;
820
192
  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
167
    result = intUF;
825
167
    resultType = bvUF.getType();
826
  } else {
827
    // bvUF is a function with arguments
828
    // The arguments need to be casted as well.
829
50
    TypeNode tn = bvUF.getType();
830
25
    resultType = tn.getRangeType();
831
50
    vector<TypeNode> bvDomain = tn.getArgTypes();
832
    // children of the new symbolic application
833
50
    vector<Node> achildren;
834
25
    achildren.push_back(intUF);
835
25
    int i = 0;
836
51
    for (const TypeNode& d : bvDomain)
837
    {
838
      // Each bit-vector argument is casted to a natural number
839
      // Other arguments are left intact.
840
52
      Node fresh_bound_var = d_nm->mkBoundVar(d);
841
26
      args.push_back(fresh_bound_var);
842
52
      Node castedArg = args[i];
843
26
      if (d.isBitVector())
844
      {
845
20
        castedArg = castToType(castedArg, d_nm->integerType());
846
      }
847
26
      achildren.push_back(castedArg);
848
26
      i++;
849
    }
850
25
    result = d_nm->mkNode(kind::APPLY_UF, achildren);
851
  }
852
  // If the result is BV, it needs to be casted back.
853
192
  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
192
  if (!args.empty())
858
  {
859
75
    result = d_nm->mkNode(
860
50
        kind::LAMBDA, d_nm->mkNode(kind::BOUND_VAR_LIST, args), result);
861
  }
862
192
  d_preprocContext->addSubstitution(bvUF, result);
863
192
}
864
865
38
bool BVToInt::childrenTypesChanged(Node n)
866
{
867
38
  bool result = false;
868
44
  for (const Node& child : n)
869
  {
870
44
    TypeNode originalType = child.getType();
871
44
    TypeNode newType = d_bvToIntCache[child].get().getType();
872
38
    if (!newType.isSubtypeOf(originalType))
873
    {
874
32
      result = true;
875
32
      break;
876
    }
877
  }
878
38
  return result;
879
}
880
881
605
Node BVToInt::castToType(Node n, TypeNode tn)
882
{
883
  // If there is no reason to cast, return the
884
  // original node.
885
605
  if (n.getType().isSubtypeOf(tn))
886
  {
887
403
    return n;
888
  }
889
  // We only case int to bv or vice verse.
890
202
  Assert((n.getType().isBitVector() && tn.isInteger())
891
         || (n.getType().isInteger() && tn.isBitVector()));
892
202
  if (n.getType().isInteger())
893
  {
894
178
    Assert(tn.isBitVector());
895
178
    unsigned bvsize = tn.getBitVectorSize();
896
356
    Node intToBVOp = d_nm->mkConst<IntToBitVector>(IntToBitVector(bvsize));
897
178
    return d_nm->mkNode(intToBVOp, n);
898
  }
899
24
  Assert(n.getType().isBitVector());
900
24
  Assert(tn.isInteger());
901
24
  return d_nm->mkNode(kind::BITVECTOR_TO_NAT, n);
902
}
903
904
158
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
158
  kind::Kind_t oldKind = originalNode.getKind();
911
316
  NodeBuilder builder(oldKind);
912
158
  if (originalNode.getMetaKind() == kind::metakind::PARAMETERIZED)
913
  {
914
1
    builder << originalNode.getOperator();
915
  }
916
393
  for (size_t i = 0; i < originalNode.getNumChildren(); i++)
917
  {
918
470
    Node originalChild = originalNode[i];
919
470
    Node translatedChild = translated_children[i];
920
470
    Node adjustedChild = castToType(translatedChild, originalChild.getType());
921
235
    builder << adjustedChild;
922
  }
923
158
  Node reconstruction = builder.constructNode();
924
  // cast to tn in case the reconstruction is a bit-vector.
925
158
  reconstruction = castToType(reconstruction, resultType);
926
316
  return reconstruction;
927
}
928
929
6271
BVToInt::BVToInt(PreprocessingPassContext* preprocContext)
930
    : PreprocessingPass(preprocContext, "bv-to-int"),
931
6271
      d_binarizeCache(userContext()),
932
6271
      d_eliminationCache(userContext()),
933
6271
      d_rebuildCache(userContext()),
934
6271
      d_bvToIntCache(userContext()),
935
31355
      d_rangeAssertions(userContext())
936
{
937
6271
  d_nm = NodeManager::currentNM();
938
6271
  d_zero = d_nm->mkConst<Rational>(0);
939
6271
  d_one = d_nm->mkConst<Rational>(1);
940
6271
};
941
942
103
PreprocessingPassResult BVToInt::applyInternal(
943
    AssertionPipeline* assertionsToPreprocess)
944
{
945
392
  for (uint64_t i = 0; i < assertionsToPreprocess->size(); ++i)
946
  {
947
578
    Node bvNode = (*assertionsToPreprocess)[i];
948
578
    Node intNode = bvToInt(bvNode);
949
578
    Node rwNode = rewrite(intNode);
950
289
    Trace("bv-to-int-debug") << "bv node: " << bvNode << std::endl;
951
289
    Trace("bv-to-int-debug") << "int node: " << intNode << std::endl;
952
289
    Trace("bv-to-int-debug") << "rw node: " << rwNode << std::endl;
953
289
    assertionsToPreprocess->replace(i, rwNode);
954
  }
955
103
  addFinalizeRangeAssertions(assertionsToPreprocess);
956
103
  return PreprocessingPassResult::NO_CONFLICT;
957
}
958
959
103
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
206
  vector<Node> vec_range;
966
103
  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
206
  Node rangeAssertions = rewrite(d_nm->mkAnd(vec_range));
970
103
  assertionsToPreprocess->push_back(rangeAssertions);
971
206
  Trace("bv-to-int-debug") << "range constraints: "
972
103
                           << rangeAssertions.toString() << std::endl;
973
103
}
974
975
33
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
66
  Node x = children[0];
988
66
  Node y = children[1];
989
  // shifting by const is eliminated by the theory rewriter
990
33
  Assert(!y.isConst());
991
33
  Node ite = d_zero;
992
66
  Node body;
993
189
  for (uint64_t i = 0; i < bvsize; i++)
994
  {
995
156
    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
140
      body = d_nm->mkNode(kind::INTS_DIVISION_TOTAL, x, pow2(i));
1004
    }
1005
468
    ite = d_nm->mkNode(kind::ITE,
1006
312
                       d_nm->mkNode(kind::EQUAL, y, d_nm->mkConst<Rational>(i)),
1007
                       body,
1008
                       ite);
1009
  }
1010
66
  return ite;
1011
}
1012
1013
23
Node BVToInt::translateQuantifiedFormula(Node quantifiedNode)
1014
{
1015
23
  kind::Kind_t k = quantifiedNode.getKind();
1016
46
  Node boundVarList = quantifiedNode[0];
1017
23
  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
46
  vector<Node> oldBoundVars;
1022
46
  vector<Node> newBoundVars;
1023
46
  vector<Node> rangeConstraints;
1024
46
  for (Node bv : quantifiedNode[0])
1025
  {
1026
23
    oldBoundVars.push_back(bv);
1027
23
    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
46
      Node newBoundVar = d_bvToIntCache[bv];
1033
23
      newBoundVars.push_back(newBoundVar);
1034
23
      rangeConstraints.push_back(
1035
46
          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
46
  Node matrix = d_bvToIntCache[quantifiedNode[1]];
1046
  // make the substitution
1047
23
  matrix = matrix.substitute(oldBoundVars.begin(),
1048
                             oldBoundVars.end(),
1049
                             newBoundVars.begin(),
1050
                             newBoundVars.end());
1051
  // A node to represent all the range constraints.
1052
46
  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
23
  matrix = d_nm->mkNode(
1057
      k == kind::FORALL ? kind::IMPLIES : kind::AND, ranges, matrix);
1058
  // create the new quantified formula and return it.
1059
46
  Node newBoundVarsList = d_nm->mkNode(kind::BOUND_VAR_LIST, newBoundVars);
1060
23
  Node result = d_nm->mkNode(kind::FORALL, newBoundVarsList, matrix);
1061
46
  return result;
1062
}
1063
1064
22
Node BVToInt::createBVNotNode(Node n, uint64_t bvsize)
1065
{
1066
22
  return d_nm->mkNode(kind::MINUS, maxInt(bvsize), n);
1067
}
1068
1069
}  // namespace passes
1070
}  // namespace preprocessing
1071
22746
}  // namespace cvc5