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