GCC Code Coverage Report
Directory: . Exec Total Coverage
File: src/theory/bv/theory_bv.cpp Lines: 182 185 98.4 %
Date: 2021-09-29 Branches: 303 617 49.1 %

Line Exec Source
1
/******************************************************************************
2
 * Top contributors (to current version):
3
 *   Mathias Preiner, Andrew Reynolds, Haniel Barbosa
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
 * Theory of bit-vectors.
14
 */
15
16
#include "theory/bv/theory_bv.h"
17
18
#include "options/bv_options.h"
19
#include "options/smt_options.h"
20
#include "proof/proof_checker.h"
21
#include "smt/smt_statistics_registry.h"
22
#include "theory/bv/bv_solver_bitblast.h"
23
#include "theory/bv/bv_solver_bitblast_internal.h"
24
#include "theory/bv/bv_solver_layered.h"
25
#include "theory/bv/theory_bv_utils.h"
26
#include "theory/ee_setup_info.h"
27
#include "theory/trust_substitutions.h"
28
29
namespace cvc5 {
30
namespace theory {
31
namespace bv {
32
33
6271
TheoryBV::TheoryBV(Env& env,
34
                   OutputChannel& out,
35
                   Valuation valuation,
36
6271
                   std::string name)
37
    : Theory(THEORY_BV, env, out, valuation, name),
38
      d_internal(nullptr),
39
      d_rewriter(),
40
      d_state(env, valuation),
41
      d_im(env, *this, d_state, nullptr, "theory::bv::"),
42
      d_notify(d_im),
43
      d_invalidateModelCache(context(), true),
44
6271
      d_stats(statisticsRegistry(), "theory::bv::")
45
{
46
6271
  switch (options().bv.bvSolver)
47
  {
48
6111
    case options::BVSolver::BITBLAST:
49
6111
      d_internal.reset(new BVSolverBitblast(env, &d_state, d_im, d_pnm));
50
6111
      break;
51
52
3
    case options::BVSolver::LAYERED:
53
9
      d_internal.reset(new BVSolverLayered(
54
6
          env, *this, context(), userContext(), d_pnm, name));
55
3
      break;
56
57
157
    default:
58
157
      AlwaysAssert(options().bv.bvSolver == options::BVSolver::BITBLAST_INTERNAL);
59
314
      d_internal.reset(
60
157
          new BVSolverBitblastInternal(d_env, &d_state, d_im, d_pnm));
61
  }
62
6271
  d_theoryState = &d_state;
63
6271
  d_inferManager = &d_im;
64
6271
}
65
66
12536
TheoryBV::~TheoryBV() {}
67
68
6271
TheoryRewriter* TheoryBV::getTheoryRewriter() { return &d_rewriter; }
69
70
143
ProofRuleChecker* TheoryBV::getProofChecker()
71
{
72
143
  if (options().bv.bvSolver == options::BVSolver::BITBLAST_INTERNAL)
73
  {
74
143
    return static_cast<BVSolverBitblastInternal*>(d_internal.get())
75
143
        ->getProofChecker();
76
  }
77
  return nullptr;
78
}
79
80
6271
bool TheoryBV::needsEqualityEngine(EeSetupInfo& esi)
81
{
82
6271
  bool need_ee = d_internal->needsEqualityEngine(esi);
83
84
  /* Set up default notify class for equality engine. */
85
6271
  if (need_ee && esi.d_notify == nullptr)
86
  {
87
6268
    esi.d_notify = &d_notify;
88
6268
    esi.d_name = "theory::bv::ee";
89
  }
90
91
6271
  return need_ee;
92
}
93
94
6271
void TheoryBV::finishInit()
95
{
96
  // these kinds are semi-evaluated in getModelValue (applications of this
97
  // kind are treated as variables)
98
6271
  getValuation().setSemiEvaluatedKind(kind::BITVECTOR_ACKERMANNIZE_UDIV);
99
6271
  getValuation().setSemiEvaluatedKind(kind::BITVECTOR_ACKERMANNIZE_UREM);
100
6271
  d_internal->finishInit();
101
102
6271
  eq::EqualityEngine* ee = getEqualityEngine();
103
6271
  if (ee)
104
  {
105
    // The kinds we are treating as function application in congruence
106
6269
    ee->addFunctionKind(kind::BITVECTOR_CONCAT, true);
107
    //    ee->addFunctionKind(kind::BITVECTOR_AND);
108
    //    ee->addFunctionKind(kind::BITVECTOR_OR);
109
    //    ee->addFunctionKind(kind::BITVECTOR_XOR);
110
    //    ee->addFunctionKind(kind::BITVECTOR_NOT);
111
    //    ee->addFunctionKind(kind::BITVECTOR_NAND);
112
    //    ee->addFunctionKind(kind::BITVECTOR_NOR);
113
    //    ee->addFunctionKind(kind::BITVECTOR_XNOR);
114
    //    ee->addFunctionKind(kind::BITVECTOR_COMP);
115
6269
    ee->addFunctionKind(kind::BITVECTOR_MULT, true);
116
6269
    ee->addFunctionKind(kind::BITVECTOR_ADD, true);
117
6269
    ee->addFunctionKind(kind::BITVECTOR_EXTRACT, true);
118
    //    ee->addFunctionKind(kind::BITVECTOR_SUB);
119
    //    ee->addFunctionKind(kind::BITVECTOR_NEG);
120
    //    ee->addFunctionKind(kind::BITVECTOR_UDIV);
121
    //    ee->addFunctionKind(kind::BITVECTOR_UREM);
122
    //    ee->addFunctionKind(kind::BITVECTOR_SDIV);
123
    //    ee->addFunctionKind(kind::BITVECTOR_SREM);
124
    //    ee->addFunctionKind(kind::BITVECTOR_SMOD);
125
    //    ee->addFunctionKind(kind::BITVECTOR_SHL);
126
    //    ee->addFunctionKind(kind::BITVECTOR_LSHR);
127
    //    ee->addFunctionKind(kind::BITVECTOR_ASHR);
128
    //    ee->addFunctionKind(kind::BITVECTOR_ULT);
129
    //    ee->addFunctionKind(kind::BITVECTOR_ULE);
130
    //    ee->addFunctionKind(kind::BITVECTOR_UGT);
131
    //    ee->addFunctionKind(kind::BITVECTOR_UGE);
132
    //    ee->addFunctionKind(kind::BITVECTOR_SLT);
133
    //    ee->addFunctionKind(kind::BITVECTOR_SLE);
134
    //    ee->addFunctionKind(kind::BITVECTOR_SGT);
135
    //    ee->addFunctionKind(kind::BITVECTOR_SGE);
136
6269
    ee->addFunctionKind(kind::BITVECTOR_TO_NAT);
137
6269
    ee->addFunctionKind(kind::INT_TO_BITVECTOR);
138
  }
139
6271
}
140
141
136649
void TheoryBV::preRegisterTerm(TNode node)
142
{
143
136649
  d_internal->preRegisterTerm(node);
144
145
136649
  eq::EqualityEngine* ee = getEqualityEngine();
146
136649
  if (ee)
147
  {
148
136649
    if (node.getKind() == kind::EQUAL)
149
    {
150
29622
      ee->addTriggerPredicate(node);
151
    }
152
    else
153
    {
154
107027
      ee->addTerm(node);
155
    }
156
  }
157
136649
}
158
159
723568
bool TheoryBV::preCheck(Effort e) { return d_internal->preCheck(e); }
160
161
723568
void TheoryBV::postCheck(Effort e)
162
{
163
723568
  d_invalidateModelCache = true;
164
723568
  d_internal->postCheck(e);
165
723568
}
166
167
1191559
bool TheoryBV::preNotifyFact(
168
    TNode atom, bool pol, TNode fact, bool isPrereg, bool isInternal)
169
{
170
1191559
  return d_internal->preNotifyFact(atom, pol, fact, isPrereg, isInternal);
171
}
172
173
1191559
void TheoryBV::notifyFact(TNode atom, bool pol, TNode fact, bool isInternal)
174
{
175
1191559
  d_internal->notifyFact(atom, pol, fact, isInternal);
176
1191559
}
177
178
6788
bool TheoryBV::needsCheckLastEffort()
179
{
180
6788
  return d_internal->needsCheckLastEffort();
181
}
182
183
5925
void TheoryBV::computeRelevantTerms(std::set<Node>& termSet)
184
{
185
5925
  return d_internal->computeRelevantTerms(termSet);
186
}
187
188
5925
bool TheoryBV::collectModelValues(TheoryModel* m, const std::set<Node>& termSet)
189
{
190
5925
  return d_internal->collectModelValues(m, termSet);
191
}
192
193
1096886
void TheoryBV::propagate(Effort e) { return d_internal->propagate(e); }
194
195
3805
Theory::PPAssertStatus TheoryBV::ppAssert(
196
    TrustNode tin, TrustSubstitutionMap& outSubstitutions)
197
{
198
7610
  TNode in = tin.getNode();
199
3805
  Kind k = in.getKind();
200
3805
  if (k == kind::EQUAL)
201
  {
202
    // Substitute variables
203
1032
    if (in[0].isVar() && isLegalElimination(in[0], in[1]))
204
    {
205
221
      ++d_stats.d_solveSubstitutions;
206
221
      outSubstitutions.addSubstitutionSolved(in[0], in[1], tin);
207
895
      return Theory::PP_ASSERT_STATUS_SOLVED;
208
    }
209
811
    if (in[1].isVar() && isLegalElimination(in[1], in[0]))
210
    {
211
438
      ++d_stats.d_solveSubstitutions;
212
438
      outSubstitutions.addSubstitutionSolved(in[1], in[0], tin);
213
438
      return Theory::PP_ASSERT_STATUS_SOLVED;
214
    }
215
    /**
216
     * Eliminate extract over bit-vector variables.
217
     *
218
     * Given x[h:l] = c, where c is a constant and x is a variable.
219
     *
220
     * We rewrite to:
221
     *
222
     * x = sk1::c       if l == 0, where bw(sk1) = bw(x)-1-h
223
     * x = c::sk2       if h == bw(x)-1, where bw(sk2) = l
224
     * x = sk1::c::sk2  otherwise, where bw(sk1) = bw(x)-1-h and bw(sk2) = l
225
     */
226
731
    Node node = rewrite(in);
227
1158
    if ((node[0].getKind() == kind::BITVECTOR_EXTRACT && node[1].isConst())
228
1878
        || (node[1].getKind() == kind::BITVECTOR_EXTRACT
229
412
            && node[0].isConst()))
230
    {
231
53
      Node extract = node[0].isConst() ? node[1] : node[0];
232
34
      if (extract[0].isVar())
233
      {
234
15
        Node c = node[0].isConst() ? node[0] : node[1];
235
236
15
        uint32_t high = utils::getExtractHigh(extract);
237
15
        uint32_t low = utils::getExtractLow(extract);
238
15
        uint32_t var_bw = utils::getSize(extract[0]);
239
15
        std::vector<Node> children;
240
241
        // create sk1 with size bw(x)-1-h
242
15
        if (low == 0 || high != var_bw - 1)
243
        {
244
12
          Assert(high != var_bw - 1);
245
12
          uint32_t skolem_size = var_bw - high - 1;
246
24
          Node skolem = utils::mkVar(skolem_size);
247
12
          children.push_back(skolem);
248
        }
249
250
15
        children.push_back(c);
251
252
        // create sk2 with size l
253
15
        if (high == var_bw - 1 || low != 0)
254
        {
255
4
          Assert(low != 0);
256
4
          uint32_t skolem_size = low;
257
8
          Node skolem = utils::mkVar(skolem_size);
258
4
          children.push_back(skolem);
259
        }
260
261
15
        Node concat = utils::mkConcat(children);
262
15
        Assert(utils::getSize(concat) == utils::getSize(extract[0]));
263
15
        if (isLegalElimination(extract[0], concat))
264
        {
265
15
          outSubstitutions.addSubstitutionSolved(extract[0], concat, tin);
266
15
          return Theory::PP_ASSERT_STATUS_SOLVED;
267
        }
268
      }
269
    }
270
  }
271
3131
  return Theory::PP_ASSERT_STATUS_UNSOLVED;
272
}
273
274
201221
TrustNode TheoryBV::ppRewrite(TNode t, std::vector<SkolemLemma>& lems)
275
{
276
  // first, see if we need to expand definitions
277
402442
  TrustNode texp = d_rewriter.expandDefinition(t);
278
201221
  if (!texp.isNull())
279
  {
280
73
    return texp;
281
  }
282
201148
  return d_internal->ppRewrite(t);
283
}
284
285
9354
void TheoryBV::presolve() { d_internal->presolve(); }
286
287
27688
EqualityStatus TheoryBV::getEqualityStatus(TNode a, TNode b)
288
{
289
27688
  EqualityStatus status = d_internal->getEqualityStatus(a, b);
290
291
27688
  if (status == EqualityStatus::EQUALITY_UNKNOWN)
292
  {
293
55376
    Node value_a = getValue(a);
294
55376
    Node value_b = getValue(b);
295
296
27688
    if (value_a.isNull() || value_b.isNull())
297
    {
298
      return status;
299
    }
300
301
27688
    if (value_a == value_b)
302
    {
303
3118
      Debug("theory-bv") << EQUALITY_TRUE_IN_MODEL << std::endl;
304
3118
      return EQUALITY_TRUE_IN_MODEL;
305
    }
306
24570
    Debug("theory-bv") << EQUALITY_FALSE_IN_MODEL << std::endl;
307
24570
    return EQUALITY_FALSE_IN_MODEL;
308
  }
309
  return status;
310
}
311
312
4275
TrustNode TheoryBV::explain(TNode node) { return d_internal->explain(node); }
313
314
79084
void TheoryBV::notifySharedTerm(TNode t)
315
{
316
79084
  d_internal->notifySharedTerm(t);
317
79084
}
318
319
63519
void TheoryBV::ppStaticLearn(TNode in, NodeBuilder& learned)
320
{
321
63519
  d_internal->ppStaticLearn(in, learned);
322
63519
}
323
324
4
bool TheoryBV::applyAbstraction(const std::vector<Node>& assertions,
325
                                std::vector<Node>& new_assertions)
326
{
327
4
  return d_internal->applyAbstraction(assertions, new_assertions);
328
}
329
330
55376
Node TheoryBV::getValue(TNode node)
331
{
332
55376
  if (d_invalidateModelCache.get())
333
  {
334
202
    d_modelCache.clear();
335
  }
336
55376
  d_invalidateModelCache.set(false);
337
338
110752
  std::vector<TNode> visit;
339
340
110752
  TNode cur;
341
55376
  visit.push_back(node);
342
489
  do
343
  {
344
55865
    cur = visit.back();
345
55865
    visit.pop_back();
346
347
55865
    auto it = d_modelCache.find(cur);
348
55865
    if (it != d_modelCache.end() && !it->second.isNull())
349
    {
350
110175
      continue;
351
    }
352
353
1417
    if (cur.isConst())
354
    {
355
248
      d_modelCache[cur] = cur;
356
248
      continue;
357
    }
358
359
1307
    Node value = d_internal->getValue(cur, false);
360
1283
    if (value.isConst())
361
    {
362
362
      d_modelCache[cur] = value;
363
362
      continue;
364
    }
365
366
732
    if (Theory::isLeafOf(cur, theory::THEORY_BV))
367
    {
368
173
      value = d_internal->getValue(cur, true);
369
173
      d_modelCache[cur] = value;
370
173
      continue;
371
    }
372
373
386
    if (it == d_modelCache.end())
374
    {
375
193
      visit.push_back(cur);
376
193
      d_modelCache.emplace(cur, Node());
377
193
      visit.insert(visit.end(), cur.begin(), cur.end());
378
    }
379
193
    else if (it->second.isNull())
380
    {
381
386
      NodeBuilder nb(cur.getKind());
382
193
      if (cur.getMetaKind() == kind::metakind::PARAMETERIZED)
383
      {
384
29
        nb << cur.getOperator();
385
      }
386
387
193
      std::unordered_map<Node, Node>::iterator iit;
388
489
      for (const TNode& child : cur)
389
      {
390
296
        iit = d_modelCache.find(child);
391
296
        Assert(iit != d_modelCache.end());
392
296
        Assert(iit->second.isConst());
393
296
        nb << iit->second;
394
      }
395
193
      it->second = rewrite(nb.constructNode());
396
    }
397
55865
  } while (!visit.empty());
398
399
55376
  auto it = d_modelCache.find(node);
400
55376
  Assert(it != d_modelCache.end());
401
110752
  return it->second;
402
}
403
404
6271
TheoryBV::Statistics::Statistics(StatisticsRegistry& reg,
405
6271
                                 const std::string& name)
406
6271
    : d_solveSubstitutions(reg.registerInt(name + "NumSolveSubstitutions"))
407
{
408
6271
}
409
410
}  // namespace bv
411
}  // namespace theory
412
22746
}  // namespace cvc5