GCC Code Coverage Report
Directory: . Exec Total Coverage
File: src/theory/fp/fp_converter.cpp Lines: 491 757 64.9 %
Date: 2021-05-22 Branches: 1024 3327 30.8 %

Line Exec Source
1
/******************************************************************************
2
 * Top contributors (to current version):
3
 *   Martin Brain, Mathias Preiner, Aina Niemetz
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
 * Conversion of floating-point operations to bit-vectors using symfpu.
14
 */
15
16
#include "theory/fp/fp_converter.h"
17
18
#include <vector>
19
20
#include "base/check.h"
21
#include "expr/node_builder.h"
22
#include "theory/theory.h"  // theory.h Only needed for the leaf test
23
#include "util/floatingpoint.h"
24
#include "util/floatingpoint_literal_symfpu.h"
25
26
#ifdef CVC5_USE_SYMFPU
27
#include "symfpu/core/add.h"
28
#include "symfpu/core/classify.h"
29
#include "symfpu/core/compare.h"
30
#include "symfpu/core/convert.h"
31
#include "symfpu/core/divide.h"
32
#include "symfpu/core/fma.h"
33
#include "symfpu/core/ite.h"
34
#include "symfpu/core/multiply.h"
35
#include "symfpu/core/packing.h"
36
#include "symfpu/core/remainder.h"
37
#include "symfpu/core/sign.h"
38
#include "symfpu/core/sqrt.h"
39
#include "symfpu/utils/numberOfRoundingModes.h"
40
#include "symfpu/utils/properties.h"
41
#endif
42
43
#ifdef CVC5_USE_SYMFPU
44
namespace symfpu {
45
using namespace ::cvc5::theory::fp::symfpuSymbolic;
46
47
#define CVC5_SYM_ITE_DFN(T)                                                \
48
  template <>                                                              \
49
  struct ite<symbolicProposition, T>                                       \
50
  {                                                                        \
51
    static const T iteOp(const symbolicProposition& _cond,                 \
52
                         const T& _l,                                      \
53
                         const T& _r)                                      \
54
    {                                                                      \
55
      ::cvc5::NodeManager* nm = ::cvc5::NodeManager::currentNM();          \
56
                                                                           \
57
      ::cvc5::Node cond = _cond;                                           \
58
      ::cvc5::Node l = _l;                                                 \
59
      ::cvc5::Node r = _r;                                                 \
60
                                                                           \
61
      /* Handle some common symfpu idioms */                               \
62
      if (cond.isConst())                                                  \
63
      {                                                                    \
64
        return (cond == nm->mkConst(::cvc5::BitVector(1U, 1U))) ? l : r;   \
65
      }                                                                    \
66
      else                                                                 \
67
      {                                                                    \
68
        if (l.getKind() == ::cvc5::kind::BITVECTOR_ITE)                    \
69
        {                                                                  \
70
          if (l[1] == r)                                                   \
71
          {                                                                \
72
            return nm->mkNode(                                             \
73
                ::cvc5::kind::BITVECTOR_ITE,                               \
74
                nm->mkNode(::cvc5::kind::BITVECTOR_AND,                    \
75
                           cond,                                           \
76
                           nm->mkNode(::cvc5::kind::BITVECTOR_NOT, l[0])), \
77
                l[2],                                                      \
78
                r);                                                        \
79
          }                                                                \
80
          else if (l[2] == r)                                              \
81
          {                                                                \
82
            return nm->mkNode(                                             \
83
                ::cvc5::kind::BITVECTOR_ITE,                               \
84
                nm->mkNode(::cvc5::kind::BITVECTOR_AND, cond, l[0]),       \
85
                l[1],                                                      \
86
                r);                                                        \
87
          }                                                                \
88
        }                                                                  \
89
        else if (r.getKind() == ::cvc5::kind::BITVECTOR_ITE)               \
90
        {                                                                  \
91
          if (r[1] == l)                                                   \
92
          {                                                                \
93
            return nm->mkNode(                                             \
94
                ::cvc5::kind::BITVECTOR_ITE,                               \
95
                nm->mkNode(::cvc5::kind::BITVECTOR_AND,                    \
96
                           nm->mkNode(::cvc5::kind::BITVECTOR_NOT, cond),  \
97
                           nm->mkNode(::cvc5::kind::BITVECTOR_NOT, r[0])), \
98
                r[2],                                                      \
99
                l);                                                        \
100
          }                                                                \
101
          else if (r[2] == l)                                              \
102
          {                                                                \
103
            return nm->mkNode(                                             \
104
                ::cvc5::kind::BITVECTOR_ITE,                               \
105
                nm->mkNode(::cvc5::kind::BITVECTOR_AND,                    \
106
                           nm->mkNode(::cvc5::kind::BITVECTOR_NOT, cond),  \
107
                           r[0]),                                          \
108
                r[1],                                                      \
109
                l);                                                        \
110
          }                                                                \
111
        }                                                                  \
112
      }                                                                    \
113
      return T(nm->mkNode(::cvc5::kind::BITVECTOR_ITE, cond, l, r));       \
114
    }                                                                      \
115
  }
116
117
// Can (unsurprisingly) only ITE things which contain Nodes
118
CVC5_SYM_ITE_DFN(traits::rm);
119
4129
CVC5_SYM_ITE_DFN(traits::prop);
120
9069
CVC5_SYM_ITE_DFN(traits::sbv);
121
18693
CVC5_SYM_ITE_DFN(traits::ubv);
122
123
#undef CVC5_SYM_ITE_DFN
124
125
template <>
126
4915
traits::ubv orderEncode<traits, traits::ubv>(const traits::ubv &b)
127
{
128
4915
  return orderEncodeBitwise<traits, traits::ubv>(b);
129
}
130
131
template <>
132
34
stickyRightShiftResult<traits> stickyRightShift(const traits::ubv &input,
133
                                                const traits::ubv &shiftAmount)
134
{
135
34
  return stickyRightShiftBitwise<traits>(input, shiftAmount);
136
}
137
138
template <>
139
8419
void probabilityAnnotation<traits, traits::prop>(const traits::prop &p,
140
                                                 const probability &pr)
141
{
142
  // For now, do nothing...
143
8419
  return;
144
}
145
};
146
#endif
147
148
#ifndef CVC5_USE_SYMFPU
149
#define SYMFPU_NUMBER_OF_ROUNDING_MODES 5
150
#endif
151
152
namespace cvc5 {
153
namespace theory {
154
namespace fp {
155
namespace symfpuSymbolic {
156
157
353
symbolicRoundingMode traits::RNE(void) { return symbolicRoundingMode(0x01); };
158
333
symbolicRoundingMode traits::RNA(void) { return symbolicRoundingMode(0x02); };
159
333
symbolicRoundingMode traits::RTP(void) { return symbolicRoundingMode(0x04); };
160
398
symbolicRoundingMode traits::RTN(void) { return symbolicRoundingMode(0x08); };
161
280
symbolicRoundingMode traits::RTZ(void) { return symbolicRoundingMode(0x10); };
162
163
6503
void traits::precondition(const bool b)
164
{
165
6503
  Assert(b);
166
6503
  return;
167
}
168
3209
void traits::postcondition(const bool b)
169
{
170
3209
  Assert(b);
171
3209
  return;
172
}
173
60904
void traits::invariant(const bool b)
174
{
175
60904
  Assert(b);
176
60904
  return;
177
}
178
179
5327
void traits::precondition(const prop &p) { return; }
180
5449
void traits::postcondition(const prop &p) { return; }
181
16415
void traits::invariant(const prop &p) { return; }
182
// This allows us to use the symfpu literal / symbolic assertions in the
183
// symbolic back-end
184
typedef traits t;
185
186
530562
bool symbolicProposition::checkNodeType(const TNode node)
187
{
188
1061124
  TypeNode tn = node.getType(false);
189
1061124
  return tn.isBitVector() && tn.getBitVectorSize() == 1;
190
}
191
192
499166
symbolicProposition::symbolicProposition(const Node n) : nodeWrapper(n)
193
{
194
499166
  Assert(checkNodeType(*this));
195
499166
}  // Only used within this header so could be friend'd
196
20307
symbolicProposition::symbolicProposition(bool v)
197
    : nodeWrapper(
198
20307
          NodeManager::currentNM()->mkConst(BitVector(1U, (v ? 1U : 0U))))
199
{
200
20307
  Assert(checkNodeType(*this));
201
20307
}
202
203
11089
symbolicProposition::symbolicProposition(const symbolicProposition &old)
204
11089
    : nodeWrapper(old)
205
{
206
11089
  Assert(checkNodeType(*this));
207
11089
}
208
209
59037
symbolicProposition symbolicProposition::operator!(void)const
210
{
211
  return symbolicProposition(
212
59037
      NodeManager::currentNM()->mkNode(kind::BITVECTOR_NOT, *this));
213
}
214
215
80131
symbolicProposition symbolicProposition::operator&&(
216
    const symbolicProposition &op) const
217
{
218
  return symbolicProposition(
219
80131
      NodeManager::currentNM()->mkNode(kind::BITVECTOR_AND, *this, op));
220
}
221
222
130937
symbolicProposition symbolicProposition::operator||(
223
    const symbolicProposition &op) const
224
{
225
  return symbolicProposition(
226
130937
      NodeManager::currentNM()->mkNode(kind::BITVECTOR_OR, *this, op));
227
}
228
229
9536
symbolicProposition symbolicProposition::operator==(
230
    const symbolicProposition &op) const
231
{
232
  return symbolicProposition(
233
9536
      NodeManager::currentNM()->mkNode(kind::BITVECTOR_COMP, *this, op));
234
}
235
236
219
symbolicProposition symbolicProposition::operator^(
237
    const symbolicProposition &op) const
238
{
239
  return symbolicProposition(
240
219
      NodeManager::currentNM()->mkNode(kind::BITVECTOR_XOR, *this, op));
241
}
242
243
1804
bool symbolicRoundingMode::checkNodeType(const TNode n)
244
{
245
#ifdef CVC5_USE_SYMFPU
246
1804
  return n.getType(false).isBitVector(SYMFPU_NUMBER_OF_ROUNDING_MODES);
247
#else
248
  return false;
249
#endif
250
}
251
252
21
symbolicRoundingMode::symbolicRoundingMode(const Node n) : nodeWrapper(n)
253
{
254
21
  Assert(checkNodeType(*this));
255
21
}
256
257
#ifdef CVC5_USE_SYMFPU
258
1697
symbolicRoundingMode::symbolicRoundingMode(const unsigned v)
259
5091
    : nodeWrapper(NodeManager::currentNM()->mkConst(
260
6788
          BitVector(SYMFPU_NUMBER_OF_ROUNDING_MODES, v)))
261
{
262
1697
  Assert((v & (v - 1)) == 0 && v != 0);  // Exactly one bit set
263
1697
  Assert(checkNodeType(*this));
264
1697
}
265
#else
266
symbolicRoundingMode::symbolicRoundingMode(const unsigned v)
267
    : nodeWrapper(NodeManager::currentNM()->mkConst(
268
          BitVector(SYMFPU_NUMBER_OF_ROUNDING_MODES, v)))
269
{
270
  Unreachable();
271
}
272
#endif
273
274
86
symbolicRoundingMode::symbolicRoundingMode(const symbolicRoundingMode &old)
275
86
    : nodeWrapper(old)
276
{
277
86
  Assert(checkNodeType(*this));
278
86
}
279
280
21
symbolicProposition symbolicRoundingMode::valid(void) const
281
{
282
21
  NodeManager *nm = NodeManager::currentNM();
283
42
  Node zero(nm->mkConst(BitVector(SYMFPU_NUMBER_OF_ROUNDING_MODES, 0u)));
284
285
  // Is there a better encoding of this?
286
84
  return symbolicProposition(nm->mkNode(
287
      kind::BITVECTOR_AND,
288
84
      nm->mkNode(
289
          kind::BITVECTOR_COMP,
290
42
          nm->mkNode(kind::BITVECTOR_AND,
291
                     *this,
292
42
                     nm->mkNode(kind::BITVECTOR_SUB,
293
                                *this,
294
42
                                nm->mkConst(BitVector(
295
                                    SYMFPU_NUMBER_OF_ROUNDING_MODES, 1u)))),
296
          zero),
297
42
      nm->mkNode(kind::BITVECTOR_NOT,
298
84
                 nm->mkNode(kind::BITVECTOR_COMP, *this, zero))));
299
}
300
301
904
symbolicProposition symbolicRoundingMode::operator==(
302
    const symbolicRoundingMode &op) const
303
{
304
  return symbolicProposition(
305
904
      NodeManager::currentNM()->mkNode(kind::BITVECTOR_COMP, *this, op));
306
}
307
308
template <bool isSigned>
309
Node symbolicBitVector<isSigned>::boolNodeToBV(Node node) const
310
{
311
  Assert(node.getType().isBoolean());
312
  NodeManager *nm = NodeManager::currentNM();
313
  return nm->mkNode(kind::ITE,
314
                    node,
315
                    nm->mkConst(BitVector(1U, 1U)),
316
                    nm->mkConst(BitVector(1U, 0U)));
317
}
318
319
template <bool isSigned>
320
Node symbolicBitVector<isSigned>::BVToBoolNode(Node node) const
321
{
322
  Assert(node.getType().isBitVector());
323
  Assert(node.getType().getBitVectorSize() == 1);
324
  NodeManager *nm = NodeManager::currentNM();
325
  return nm->mkNode(kind::EQUAL, node, nm->mkConst(BitVector(1U, 1U)));
326
}
327
328
template <bool isSigned>
329
66079
Node symbolicBitVector<isSigned>::fromProposition(Node node) const
330
{
331
66079
  return node;
332
}
333
template <bool isSigned>
334
Node symbolicBitVector<isSigned>::toProposition(Node node) const
335
{
336
  return boolNodeToBV(node);
337
}
338
339
template <bool isSigned>
340
544766
symbolicBitVector<isSigned>::symbolicBitVector(const Node n) : nodeWrapper(n)
341
{
342
544766
  Assert(checkNodeType(*this));
343
544766
}
344
345
template <bool isSigned>
346
844277
bool symbolicBitVector<isSigned>::checkNodeType(const TNode n)
347
{
348
844277
  return n.getType(false).isBitVector();
349
}
350
351
template <bool isSigned>
352
283336
symbolicBitVector<isSigned>::symbolicBitVector(const bwt w, const unsigned v)
353
283336
    : nodeWrapper(NodeManager::currentNM()->mkConst(BitVector(w, v)))
354
{
355
283336
  Assert(checkNodeType(*this));
356
283336
}
357
template <bool isSigned>
358
66079
symbolicBitVector<isSigned>::symbolicBitVector(const symbolicProposition &p)
359
66079
    : nodeWrapper(fromProposition(p))
360
{
361
66079
}
362
template <bool isSigned>
363
15673
symbolicBitVector<isSigned>::symbolicBitVector(
364
    const symbolicBitVector<isSigned> &old)
365
15673
    : nodeWrapper(old)
366
{
367
15673
  Assert(checkNodeType(*this));
368
15673
}
369
template <bool isSigned>
370
502
symbolicBitVector<isSigned>::symbolicBitVector(const BitVector &old)
371
502
    : nodeWrapper(NodeManager::currentNM()->mkConst(old))
372
{
373
502
  Assert(checkNodeType(*this));
374
502
}
375
376
template <bool isSigned>
377
91199
bwt symbolicBitVector<isSigned>::getWidth(void) const
378
{
379
91199
  return this->getType(false).getBitVectorSize();
380
}
381
382
/*** Constant creation and test ***/
383
template <bool isSigned>
384
95348
symbolicBitVector<isSigned> symbolicBitVector<isSigned>::one(const bwt &w)
385
{
386
95348
  return symbolicBitVector<isSigned>(w, 1);
387
}
388
template <bool isSigned>
389
41381
symbolicBitVector<isSigned> symbolicBitVector<isSigned>::zero(const bwt &w)
390
{
391
41381
  return symbolicBitVector<isSigned>(w, 0);
392
}
393
template <bool isSigned>
394
4955
symbolicBitVector<isSigned> symbolicBitVector<isSigned>::allOnes(const bwt &w)
395
{
396
4955
  return symbolicBitVector<isSigned>(~zero(w));
397
}
398
399
template <bool isSigned>
400
1398
symbolicProposition symbolicBitVector<isSigned>::isAllOnes() const
401
{
402
1398
  return (*this == symbolicBitVector<isSigned>::allOnes(this->getWidth()));
403
}
404
template <bool isSigned>
405
11111
symbolicProposition symbolicBitVector<isSigned>::isAllZeros() const
406
{
407
11111
  return (*this == symbolicBitVector<isSigned>::zero(this->getWidth()));
408
}
409
410
template <>
411
69
symbolicBitVector<true> symbolicBitVector<true>::maxValue(const bwt &w)
412
{
413
138
  symbolicBitVector<true> leadingZero(symbolicBitVector<true>::zero(1));
414
138
  symbolicBitVector<true> base(symbolicBitVector<true>::allOnes(w - 1));
415
416
138
  return symbolicBitVector<true>(::cvc5::NodeManager::currentNM()->mkNode(
417
138
      ::cvc5::kind::BITVECTOR_CONCAT, leadingZero, base));
418
}
419
420
template <>
421
symbolicBitVector<false> symbolicBitVector<false>::maxValue(const bwt &w)
422
{
423
  return symbolicBitVector<false>::allOnes(w);
424
}
425
426
template <>
427
6
symbolicBitVector<true> symbolicBitVector<true>::minValue(const bwt &w)
428
{
429
12
  symbolicBitVector<true> leadingOne(symbolicBitVector<true>::one(1));
430
12
  symbolicBitVector<true> base(symbolicBitVector<true>::zero(w - 1));
431
432
12
  return symbolicBitVector<true>(::cvc5::NodeManager::currentNM()->mkNode(
433
12
      ::cvc5::kind::BITVECTOR_CONCAT, leadingOne, base));
434
}
435
436
template <>
437
symbolicBitVector<false> symbolicBitVector<false>::minValue(const bwt &w)
438
{
439
  return symbolicBitVector<false>::zero(w);
440
}
441
442
/*** Operators ***/
443
template <bool isSigned>
444
71040
symbolicBitVector<isSigned> symbolicBitVector<isSigned>::operator<<(
445
    const symbolicBitVector<isSigned> &op) const
446
{
447
  return symbolicBitVector<isSigned>(
448
71040
      NodeManager::currentNM()->mkNode(kind::BITVECTOR_SHL, *this, op));
449
}
450
451
template <bool isSigned>
452
3246
symbolicBitVector<isSigned> symbolicBitVector<isSigned>::operator>>(
453
    const symbolicBitVector<isSigned> &op) const
454
{
455
  return symbolicBitVector<isSigned>(NodeManager::currentNM()->mkNode(
456
3246
      (isSigned) ? kind::BITVECTOR_ASHR : kind::BITVECTOR_LSHR, *this, op));
457
}
458
459
template <bool isSigned>
460
57793
symbolicBitVector<isSigned> symbolicBitVector<isSigned>::operator|(
461
    const symbolicBitVector<isSigned> &op) const
462
{
463
  return symbolicBitVector<isSigned>(
464
57793
      NodeManager::currentNM()->mkNode(kind::BITVECTOR_OR, *this, op));
465
}
466
467
template <bool isSigned>
468
10437
symbolicBitVector<isSigned> symbolicBitVector<isSigned>::operator&(
469
    const symbolicBitVector<isSigned> &op) const
470
{
471
  return symbolicBitVector<isSigned>(
472
10437
      NodeManager::currentNM()->mkNode(kind::BITVECTOR_AND, *this, op));
473
}
474
475
template <bool isSigned>
476
4014
symbolicBitVector<isSigned> symbolicBitVector<isSigned>::operator+(
477
    const symbolicBitVector<isSigned> &op) const
478
{
479
  return symbolicBitVector<isSigned>(
480
4014
      NodeManager::currentNM()->mkNode(kind::BITVECTOR_ADD, *this, op));
481
}
482
483
template <bool isSigned>
484
91944
symbolicBitVector<isSigned> symbolicBitVector<isSigned>::operator-(
485
    const symbolicBitVector<isSigned> &op) const
486
{
487
  return symbolicBitVector<isSigned>(
488
91944
      NodeManager::currentNM()->mkNode(kind::BITVECTOR_SUB, *this, op));
489
}
490
491
template <bool isSigned>
492
9
symbolicBitVector<isSigned> symbolicBitVector<isSigned>::operator*(
493
    const symbolicBitVector<isSigned> &op) const
494
{
495
  return symbolicBitVector<isSigned>(
496
9
      NodeManager::currentNM()->mkNode(kind::BITVECTOR_MULT, *this, op));
497
}
498
499
template <bool isSigned>
500
6
symbolicBitVector<isSigned> symbolicBitVector<isSigned>::operator/(
501
    const symbolicBitVector<isSigned> &op) const
502
{
503
  return symbolicBitVector<isSigned>(NodeManager::currentNM()->mkNode(
504
6
      (isSigned) ? kind::BITVECTOR_SDIV : kind::BITVECTOR_UDIV, *this, op));
505
}
506
507
template <bool isSigned>
508
6
symbolicBitVector<isSigned> symbolicBitVector<isSigned>::operator%(
509
    const symbolicBitVector<isSigned> &op) const
510
{
511
  return symbolicBitVector<isSigned>(NodeManager::currentNM()->mkNode(
512
6
      (isSigned) ? kind::BITVECTOR_SREM : kind::BITVECTOR_UREM, *this, op));
513
}
514
515
template <bool isSigned>
516
40967
symbolicBitVector<isSigned> symbolicBitVector<isSigned>::operator-(void) const
517
{
518
  return symbolicBitVector<isSigned>(
519
40967
      NodeManager::currentNM()->mkNode(kind::BITVECTOR_NEG, *this));
520
}
521
522
template <bool isSigned>
523
5156
symbolicBitVector<isSigned> symbolicBitVector<isSigned>::operator~(void)const
524
{
525
  return symbolicBitVector<isSigned>(
526
5156
      NodeManager::currentNM()->mkNode(kind::BITVECTOR_NOT, *this));
527
}
528
529
template <bool isSigned>
530
20
symbolicBitVector<isSigned> symbolicBitVector<isSigned>::increment() const
531
{
532
  return symbolicBitVector<isSigned>(NodeManager::currentNM()->mkNode(
533
20
      kind::BITVECTOR_ADD, *this, one(this->getWidth())));
534
}
535
536
template <bool isSigned>
537
5033
symbolicBitVector<isSigned> symbolicBitVector<isSigned>::decrement() const
538
{
539
  return symbolicBitVector<isSigned>(NodeManager::currentNM()->mkNode(
540
5033
      kind::BITVECTOR_SUB, *this, one(this->getWidth())));
541
}
542
543
template <bool isSigned>
544
248
symbolicBitVector<isSigned> symbolicBitVector<isSigned>::signExtendRightShift(
545
    const symbolicBitVector<isSigned> &op) const
546
{
547
  return symbolicBitVector<isSigned>(
548
248
      NodeManager::currentNM()->mkNode(kind::BITVECTOR_ASHR, *this, op));
549
}
550
551
/*** Modular operations ***/
552
// No overflow checking so these are the same as other operations
553
template <bool isSigned>
554
5309
symbolicBitVector<isSigned> symbolicBitVector<isSigned>::modularLeftShift(
555
    const symbolicBitVector<isSigned> &op) const
556
{
557
5309
  return *this << op;
558
}
559
560
template <bool isSigned>
561
34
symbolicBitVector<isSigned> symbolicBitVector<isSigned>::modularRightShift(
562
    const symbolicBitVector<isSigned> &op) const
563
{
564
34
  return *this >> op;
565
}
566
567
template <bool isSigned>
568
symbolicBitVector<isSigned> symbolicBitVector<isSigned>::modularIncrement()
569
    const
570
{
571
  return this->increment();
572
}
573
574
template <bool isSigned>
575
4915
symbolicBitVector<isSigned> symbolicBitVector<isSigned>::modularDecrement()
576
    const
577
{
578
4915
  return this->decrement();
579
}
580
581
template <bool isSigned>
582
690
symbolicBitVector<isSigned> symbolicBitVector<isSigned>::modularAdd(
583
    const symbolicBitVector<isSigned> &op) const
584
{
585
690
  return *this + op;
586
}
587
588
template <bool isSigned>
589
681
symbolicBitVector<isSigned> symbolicBitVector<isSigned>::modularNegate() const
590
{
591
681
  return -(*this);
592
}
593
594
/*** Comparisons ***/
595
596
template <bool isSigned>
597
149001
symbolicProposition symbolicBitVector<isSigned>::operator==(
598
    const symbolicBitVector<isSigned> &op) const
599
{
600
  return symbolicProposition(
601
149001
      NodeManager::currentNM()->mkNode(kind::BITVECTOR_COMP, *this, op));
602
}
603
604
template <bool isSigned>
605
57645
symbolicProposition symbolicBitVector<isSigned>::operator<=(
606
    const symbolicBitVector<isSigned> &op) const
607
{
608
  // Consider adding kind::BITVECTOR_SLEBV and BITVECTOR_ULEBV
609
57645
  return (*this < op) || (*this == op);
610
}
611
612
template <bool isSigned>
613
5761
symbolicProposition symbolicBitVector<isSigned>::operator>=(
614
    const symbolicBitVector<isSigned> &op) const
615
{
616
5761
  return (*this > op) || (*this == op);
617
}
618
619
template <bool isSigned>
620
58202
symbolicProposition symbolicBitVector<isSigned>::operator<(
621
    const symbolicBitVector<isSigned> &op) const
622
{
623
  return symbolicProposition(NodeManager::currentNM()->mkNode(
624
58202
      (isSigned) ? kind::BITVECTOR_SLTBV : kind::BITVECTOR_ULTBV, *this, op));
625
}
626
627
template <bool isSigned>
628
6569
symbolicProposition symbolicBitVector<isSigned>::operator>(
629
    const symbolicBitVector<isSigned> &op) const
630
{
631
  return symbolicProposition(NodeManager::currentNM()->mkNode(
632
6569
      (isSigned) ? kind::BITVECTOR_SLTBV : kind::BITVECTOR_ULTBV, op, *this));
633
}
634
635
/*** Type conversion ***/
636
// cvc5 nodes make no distinction between signed and unsigned, thus ...
637
template <bool isSigned>
638
80
symbolicBitVector<true> symbolicBitVector<isSigned>::toSigned(void) const
639
{
640
80
  return symbolicBitVector<true>(*this);
641
}
642
template <bool isSigned>
643
11255
symbolicBitVector<false> symbolicBitVector<isSigned>::toUnsigned(void) const
644
{
645
11255
  return symbolicBitVector<false>(*this);
646
}
647
648
/*** Bit hacks ***/
649
template <>
650
868
symbolicBitVector<true> symbolicBitVector<true>::extend(bwt extension) const
651
{
652
1736
  NodeBuilder construct(kind::BITVECTOR_SIGN_EXTEND);
653
2604
  construct << NodeManager::currentNM()->mkConst<BitVectorSignExtend>(
654
3472
                   BitVectorSignExtend(extension))
655
868
            << *this;
656
657
1736
  return symbolicBitVector<true>(construct);
658
}
659
660
template <>
661
13487
symbolicBitVector<false> symbolicBitVector<false>::extend(bwt extension) const
662
{
663
26974
  NodeBuilder construct(kind::BITVECTOR_ZERO_EXTEND);
664
40461
  construct << NodeManager::currentNM()->mkConst<BitVectorZeroExtend>(
665
53948
                   BitVectorZeroExtend(extension))
666
13487
            << *this;
667
668
26974
  return symbolicBitVector<false>(construct);
669
}
670
671
template <bool isSigned>
672
83
symbolicBitVector<isSigned> symbolicBitVector<isSigned>::contract(
673
    bwt reduction) const
674
{
675
83
  Assert(this->getWidth() > reduction);
676
677
166
  NodeBuilder construct(kind::BITVECTOR_EXTRACT);
678
332
  construct << NodeManager::currentNM()->mkConst<BitVectorExtract>(
679
83
                   BitVectorExtract((this->getWidth() - 1) - reduction, 0))
680
166
            << *this;
681
682
166
  return symbolicBitVector<isSigned>(construct);
683
}
684
685
template <bool isSigned>
686
5015
symbolicBitVector<isSigned> symbolicBitVector<isSigned>::resize(
687
    bwt newSize) const
688
{
689
5015
  bwt width = this->getWidth();
690
691
5015
  if (newSize > width)
692
  {
693
5015
    return this->extend(newSize - width);
694
  }
695
  else if (newSize < width)
696
  {
697
    return this->contract(width - newSize);
698
  }
699
  else
700
  {
701
    return *this;
702
  }
703
}
704
705
template <bool isSigned>
706
8367
symbolicBitVector<isSigned> symbolicBitVector<isSigned>::matchWidth(
707
    const symbolicBitVector<isSigned> &op) const
708
{
709
8367
  Assert(this->getWidth() <= op.getWidth());
710
8367
  return this->extend(op.getWidth() - this->getWidth());
711
}
712
713
template <bool isSigned>
714
64534
symbolicBitVector<isSigned> symbolicBitVector<isSigned>::append(
715
    const symbolicBitVector<isSigned> &op) const
716
{
717
  return symbolicBitVector<isSigned>(
718
64534
      NodeManager::currentNM()->mkNode(kind::BITVECTOR_CONCAT, *this, op));
719
}
720
721
// Inclusive of end points, thus if the same, extracts just one bit
722
template <bool isSigned>
723
136441
symbolicBitVector<isSigned> symbolicBitVector<isSigned>::extract(
724
    bwt upper, bwt lower) const
725
{
726
136441
  Assert(upper >= lower);
727
728
272882
  NodeBuilder construct(kind::BITVECTOR_EXTRACT);
729
409323
  construct << NodeManager::currentNM()->mkConst<BitVectorExtract>(
730
                   BitVectorExtract(upper, lower))
731
272882
            << *this;
732
733
272882
  return symbolicBitVector<isSigned>(construct);
734
}
735
736
3856
floatingPointTypeInfo::floatingPointTypeInfo(const TypeNode type)
737
3856
    : FloatingPointSize(type.getConst<FloatingPointSize>())
738
{
739
3856
  Assert(type.isFloatingPoint());
740
3856
}
741
57
floatingPointTypeInfo::floatingPointTypeInfo(unsigned exp, unsigned sig)
742
57
    : FloatingPointSize(exp, sig)
743
{
744
57
}
745
floatingPointTypeInfo::floatingPointTypeInfo(const floatingPointTypeInfo &old)
746
    : FloatingPointSize(old)
747
{
748
}
749
750
3143
TypeNode floatingPointTypeInfo::getTypeNode(void) const
751
{
752
3143
  return NodeManager::currentNM()->mkFloatingPointType(*this);
753
}
754
}
755
756
9460
FpConverter::FpConverter(context::UserContext* user)
757
    : d_additionalAssertions(user)
758
#ifdef CVC5_USE_SYMFPU
759
      ,
760
      d_fpMap(user),
761
      d_rmMap(user),
762
      d_boolMap(user),
763
      d_ubvMap(user),
764
9460
      d_sbvMap(user)
765
#endif
766
{
767
9460
}
768
769
9460
FpConverter::~FpConverter() {}
770
771
#ifdef CVC5_USE_SYMFPU
772
3143
Node FpConverter::ufToNode(const fpt &format, const uf &u) const
773
{
774
3143
  NodeManager *nm = NodeManager::currentNM();
775
776
3143
  FloatingPointSize fps(format.getTypeNode().getConst<FloatingPointSize>());
777
778
  // This is not entirely obvious but it builds a float from components
779
  // Particularly, if the components can be constant folded, it should
780
  // build a Node containing a constant FloatingPoint number
781
782
6286
  ubv packed(symfpu::pack<traits>(format, u));
783
  Node value =
784
3143
      nm->mkNode(nm->mkConst(FloatingPointToFPIEEEBitVector(fps)), packed);
785
6286
  return value;
786
}
787
788
152
Node FpConverter::rmToNode(const rm &r) const
789
{
790
152
  NodeManager *nm = NodeManager::currentNM();
791
792
304
  Node transVar = r;
793
794
304
  Node RNE = traits::RNE();
795
304
  Node RNA = traits::RNA();
796
304
  Node RTP = traits::RTP();
797
304
  Node RTN = traits::RTN();
798
304
  Node RTZ = traits::RTZ();
799
800
  Node value = nm->mkNode(
801
      kind::ITE,
802
304
      nm->mkNode(kind::EQUAL, transVar, RNE),
803
304
      nm->mkConst(ROUND_NEAREST_TIES_TO_EVEN),
804
912
      nm->mkNode(kind::ITE,
805
304
                 nm->mkNode(kind::EQUAL, transVar, RNA),
806
304
                 nm->mkConst(ROUND_NEAREST_TIES_TO_AWAY),
807
912
                 nm->mkNode(kind::ITE,
808
304
                            nm->mkNode(kind::EQUAL, transVar, RTP),
809
304
                            nm->mkConst(ROUND_TOWARD_POSITIVE),
810
912
                            nm->mkNode(kind::ITE,
811
304
                                       nm->mkNode(kind::EQUAL, transVar, RTN),
812
304
                                       nm->mkConst(ROUND_TOWARD_NEGATIVE),
813
1064
                                       nm->mkConst(ROUND_TOWARD_ZERO)))));
814
304
  return value;
815
}
816
817
Node FpConverter::propToNode(const prop &p) const
818
{
819
  NodeManager *nm = NodeManager::currentNM();
820
  Node value =
821
      nm->mkNode(kind::EQUAL, p, nm->mkConst(::cvc5::BitVector(1U, 1U)));
822
  return value;
823
}
824
Node FpConverter::ubvToNode(const ubv &u) const { return u; }
825
Node FpConverter::sbvToNode(const sbv &s) const { return s; }
826
// Creates the components constraint
827
120
FpConverter::uf FpConverter::buildComponents(TNode current)
828
{
829
120
  Assert(Theory::isLeafOf(current, THEORY_FP)
830
         || current.getKind() == kind::FLOATINGPOINT_TO_FP_REAL);
831
832
120
  NodeManager *nm = NodeManager::currentNM();
833
240
  uf tmp(nm->mkNode(kind::FLOATINGPOINT_COMPONENT_NAN, current),
834
240
         nm->mkNode(kind::FLOATINGPOINT_COMPONENT_INF, current),
835
240
         nm->mkNode(kind::FLOATINGPOINT_COMPONENT_ZERO, current),
836
240
         nm->mkNode(kind::FLOATINGPOINT_COMPONENT_SIGN, current),
837
240
         nm->mkNode(kind::FLOATINGPOINT_COMPONENT_EXPONENT, current),
838
1320
         nm->mkNode(kind::FLOATINGPOINT_COMPONENT_SIGNIFICAND, current));
839
840
120
  d_additionalAssertions.push_back(tmp.valid(fpt(current.getType())));
841
842
120
  return tmp;
843
}
844
#endif
845
846
// Non-convertible things should only be added to the stack at the very start,
847
// thus...
848
#define CVC5_FPCONV_PASSTHROUGH Assert(workStack.empty())
849
850
1922
Node FpConverter::convert(TNode node)
851
{
852
#ifdef CVC5_USE_SYMFPU
853
3844
  std::vector<TNode> workStack;
854
3844
  TNode result = node;
855
856
1922
  workStack.push_back(node);
857
858
1922
  NodeManager *nm = NodeManager::currentNM();
859
860
5466
  while (!workStack.empty())
861
  {
862
3694
    TNode current = workStack.back();
863
1922
    workStack.pop_back();
864
1922
    result = current;
865
866
3694
    TypeNode t(current.getType());
867
868
1922
    if (t.isRoundingMode())
869
    {
870
43
      rmMap::const_iterator i(d_rmMap.find(current));
871
872
43
      if (i == d_rmMap.end())
873
      {
874
43
        if (Theory::isLeafOf(current, THEORY_FP))
875
        {
876
43
          if (current.getKind() == kind::CONST_ROUNDINGMODE)
877
          {
878
            /******** Constants ********/
879
22
            switch (current.getConst<RoundingMode>())
880
            {
881
14
              case ROUND_NEAREST_TIES_TO_EVEN:
882
14
                d_rmMap.insert(current, traits::RNE());
883
14
                break;
884
4
              case ROUND_NEAREST_TIES_TO_AWAY:
885
4
                d_rmMap.insert(current, traits::RNA());
886
4
                break;
887
4
              case ROUND_TOWARD_POSITIVE:
888
4
                d_rmMap.insert(current, traits::RTP());
889
4
                break;
890
              case ROUND_TOWARD_NEGATIVE:
891
                d_rmMap.insert(current, traits::RTN());
892
                break;
893
              case ROUND_TOWARD_ZERO:
894
                d_rmMap.insert(current, traits::RTZ());
895
                break;
896
              default: Unreachable() << "Unknown rounding mode"; break;
897
            }
898
          }
899
          else
900
          {
901
            /******** Variables ********/
902
42
            rm tmp(nm->mkNode(kind::ROUNDINGMODE_BITBLAST, current));
903
21
            d_rmMap.insert(current, tmp);
904
21
            d_additionalAssertions.push_back(tmp.valid());
905
          }
906
        }
907
        else
908
        {
909
          Unreachable() << "Unknown kind of type RoundingMode";
910
        }
911
      }
912
      // Returns a rounding-mode type so don't alter the return value
913
    }
914
1879
    else if (t.isFloatingPoint())
915
    {
916
487
      fpMap::const_iterator i(d_fpMap.find(current));
917
918
487
      if (i == d_fpMap.end())
919
      {
920
487
        if (Theory::isLeafOf(current, THEORY_FP))
921
        {
922
371
          if (current.getKind() == kind::CONST_FLOATINGPOINT)
923
          {
924
            /******** Constants ********/
925
502
            d_fpMap.insert(
926
                current,
927
753
                symfpu::unpackedFloat<traits>(current.getConst<FloatingPoint>()
928
                                                  .getLiteral()
929
251
                                                  ->getSymUF()));
930
          }
931
          else
932
          {
933
            /******** Variables ********/
934
120
            d_fpMap.insert(current, buildComponents(current));
935
          }
936
        }
937
        else
938
        {
939
116
          switch (current.getKind())
940
          {
941
            case kind::CONST_FLOATINGPOINT:
942
            case kind::VARIABLE:
943
            case kind::BOUND_VARIABLE:
944
            case kind::SKOLEM:
945
              Unreachable() << "Kind should have been handled as a leaf.";
946
              break;
947
948
            /******** Operations ********/
949
23
            case kind::FLOATINGPOINT_ABS:
950
            case kind::FLOATINGPOINT_NEG:
951
            {
952
23
              fpMap::const_iterator arg1(d_fpMap.find(current[0]));
953
954
23
              if (arg1 == d_fpMap.end())
955
              {
956
                workStack.push_back(current);
957
                workStack.push_back(current[0]);
958
                continue;  // i.e. recurse!
959
              }
960
961
23
              switch (current.getKind())
962
              {
963
9
                case kind::FLOATINGPOINT_ABS:
964
18
                  d_fpMap.insert(current,
965
27
                                 symfpu::absolute<traits>(
966
27
                                     fpt(current.getType()), (*arg1).second));
967
9
                  break;
968
14
                case kind::FLOATINGPOINT_NEG:
969
28
                  d_fpMap.insert(current,
970
28
                                 symfpu::negate<traits>(fpt(current.getType()),
971
14
                                                        (*arg1).second));
972
14
                  break;
973
                default:
974
                  Unreachable() << "Unknown unary floating-point function";
975
                  break;
976
23
              }
977
            }
978
23
            break;
979
980
20
            case kind::FLOATINGPOINT_SQRT:
981
            case kind::FLOATINGPOINT_RTI:
982
            {
983
20
              rmMap::const_iterator mode(d_rmMap.find(current[0]));
984
20
              fpMap::const_iterator arg1(d_fpMap.find(current[1]));
985
              bool recurseNeeded =
986
20
                  (mode == d_rmMap.end()) || (arg1 == d_fpMap.end());
987
988
20
              if (recurseNeeded)
989
              {
990
                workStack.push_back(current);
991
                if (mode == d_rmMap.end())
992
                {
993
                  workStack.push_back(current[0]);
994
                }
995
                if (arg1 == d_fpMap.end())
996
                {
997
                  workStack.push_back(current[1]);
998
                }
999
                continue;  // i.e. recurse!
1000
              }
1001
1002
20
              switch (current.getKind())
1003
              {
1004
                case kind::FLOATINGPOINT_SQRT:
1005
                  d_fpMap.insert(current,
1006
                                 symfpu::sqrt<traits>(fpt(current.getType()),
1007
                                                      (*mode).second,
1008
                                                      (*arg1).second));
1009
                  break;
1010
20
                case kind::FLOATINGPOINT_RTI:
1011
40
                  d_fpMap.insert(
1012
                      current,
1013
60
                      symfpu::roundToIntegral<traits>(fpt(current.getType()),
1014
20
                                                      (*mode).second,
1015
20
                                                      (*arg1).second));
1016
20
                  break;
1017
                default:
1018
                  Unreachable()
1019
                      << "Unknown unary rounded floating-point function";
1020
                  break;
1021
20
              }
1022
            }
1023
20
            break;
1024
1025
10
            case kind::FLOATINGPOINT_REM:
1026
            {
1027
10
              fpMap::const_iterator arg1(d_fpMap.find(current[0]));
1028
10
              fpMap::const_iterator arg2(d_fpMap.find(current[1]));
1029
              bool recurseNeeded =
1030
10
                  (arg1 == d_fpMap.end()) || (arg2 == d_fpMap.end());
1031
1032
10
              if (recurseNeeded)
1033
              {
1034
                workStack.push_back(current);
1035
                if (arg1 == d_fpMap.end())
1036
                {
1037
                  workStack.push_back(current[0]);
1038
                }
1039
                if (arg2 == d_fpMap.end())
1040
                {
1041
                  workStack.push_back(current[1]);
1042
                }
1043
                continue;  // i.e. recurse!
1044
              }
1045
1046
20
              d_fpMap.insert(
1047
                  current,
1048
40
                  symfpu::remainder<traits>(
1049
40
                      fpt(current.getType()), (*arg1).second, (*arg2).second));
1050
            }
1051
10
            break;
1052
1053
            case kind::FLOATINGPOINT_MIN_TOTAL:
1054
            case kind::FLOATINGPOINT_MAX_TOTAL:
1055
            {
1056
              fpMap::const_iterator arg1(d_fpMap.find(current[0]));
1057
              fpMap::const_iterator arg2(d_fpMap.find(current[1]));
1058
              // current[2] is a bit-vector so we do not need to recurse down it
1059
1060
              bool recurseNeeded =
1061
                  (arg1 == d_fpMap.end()) || (arg2 == d_fpMap.end());
1062
1063
              if (recurseNeeded)
1064
              {
1065
                workStack.push_back(current);
1066
                if (arg1 == d_fpMap.end())
1067
                {
1068
                  workStack.push_back(current[0]);
1069
                }
1070
                if (arg2 == d_fpMap.end())
1071
                {
1072
                  workStack.push_back(current[1]);
1073
                }
1074
                continue;  // i.e. recurse!
1075
              }
1076
1077
              switch (current.getKind())
1078
              {
1079
                case kind::FLOATINGPOINT_MAX_TOTAL:
1080
                  d_fpMap.insert(current,
1081
                                 symfpu::max<traits>(fpt(current.getType()),
1082
                                                     (*arg1).second,
1083
                                                     (*arg2).second,
1084
                                                     prop(current[2])));
1085
                  break;
1086
1087
                case kind::FLOATINGPOINT_MIN_TOTAL:
1088
                  d_fpMap.insert(current,
1089
                                 symfpu::min<traits>(fpt(current.getType()),
1090
                                                     (*arg1).second,
1091
                                                     (*arg2).second,
1092
                                                     prop(current[2])));
1093
                  break;
1094
1095
                default:
1096
                  Unreachable()
1097
                      << "Unknown binary floating-point partial function";
1098
                  break;
1099
              }
1100
            }
1101
            break;
1102
1103
39
            case kind::FLOATINGPOINT_PLUS:
1104
            case kind::FLOATINGPOINT_SUB:
1105
            case kind::FLOATINGPOINT_MULT:
1106
            case kind::FLOATINGPOINT_DIV:
1107
            {
1108
39
              rmMap::const_iterator mode(d_rmMap.find(current[0]));
1109
39
              fpMap::const_iterator arg1(d_fpMap.find(current[1]));
1110
39
              fpMap::const_iterator arg2(d_fpMap.find(current[2]));
1111
78
              bool recurseNeeded = (mode == d_rmMap.end())
1112
78
                                   || (arg1 == d_fpMap.end())
1113
78
                                   || (arg2 == d_fpMap.end());
1114
1115
39
              if (recurseNeeded)
1116
              {
1117
                workStack.push_back(current);
1118
                if (mode == d_rmMap.end())
1119
                {
1120
                  workStack.push_back(current[0]);
1121
                }
1122
                if (arg1 == d_fpMap.end())
1123
                {
1124
                  workStack.push_back(current[1]);
1125
                }
1126
                if (arg2 == d_fpMap.end())
1127
                {
1128
                  workStack.push_back(current[2]);
1129
                }
1130
                continue;  // i.e. recurse!
1131
              }
1132
1133
39
              switch (current.getKind())
1134
              {
1135
24
                case kind::FLOATINGPOINT_PLUS:
1136
48
                  d_fpMap.insert(current,
1137
96
                                 symfpu::add<traits>(fpt(current.getType()),
1138
24
                                                     (*mode).second,
1139
24
                                                     (*arg1).second,
1140
24
                                                     (*arg2).second,
1141
48
                                                     prop(true)));
1142
24
                  break;
1143
1144
                case kind::FLOATINGPOINT_SUB:
1145
                  // Should have been removed by the rewriter
1146
                  Unreachable()
1147
                      << "Floating-point subtraction should be removed by the "
1148
                         "rewriter.";
1149
                  break;
1150
1151
9
                case kind::FLOATINGPOINT_MULT:
1152
18
                  d_fpMap.insert(
1153
                      current,
1154
36
                      symfpu::multiply<traits>(fpt(current.getType()),
1155
9
                                               (*mode).second,
1156
9
                                               (*arg1).second,
1157
9
                                               (*arg2).second));
1158
9
                  break;
1159
6
                case kind::FLOATINGPOINT_DIV:
1160
12
                  d_fpMap.insert(current,
1161
24
                                 symfpu::divide<traits>(fpt(current.getType()),
1162
6
                                                        (*mode).second,
1163
6
                                                        (*arg1).second,
1164
6
                                                        (*arg2).second));
1165
6
                  break;
1166
                case kind::FLOATINGPOINT_REM:
1167
                  /*
1168
                  d_fpMap.insert(current,
1169
                  symfpu::remainder<traits>(fpt(current.getType()),
1170
                                                             (*mode).second,
1171
                                                             (*arg1).second,
1172
                                                             (*arg2).second));
1173
                  */
1174
                  Unimplemented()
1175
                      << "Remainder with rounding mode not yet supported by "
1176
                         "SMT-LIB";
1177
                  break;
1178
1179
                default:
1180
                  Unreachable()
1181
                      << "Unknown binary rounded floating-point function";
1182
                  break;
1183
39
              }
1184
            }
1185
39
            break;
1186
1187
            case kind::FLOATINGPOINT_FMA:
1188
            {
1189
              rmMap::const_iterator mode(d_rmMap.find(current[0]));
1190
              fpMap::const_iterator arg1(d_fpMap.find(current[1]));
1191
              fpMap::const_iterator arg2(d_fpMap.find(current[2]));
1192
              fpMap::const_iterator arg3(d_fpMap.find(current[3]));
1193
              bool recurseNeeded =
1194
                  (mode == d_rmMap.end()) || (arg1 == d_fpMap.end())
1195
                  || (arg2 == d_fpMap.end() || (arg3 == d_fpMap.end()));
1196
1197
              if (recurseNeeded)
1198
              {
1199
                workStack.push_back(current);
1200
                if (mode == d_rmMap.end())
1201
                {
1202
                  workStack.push_back(current[0]);
1203
                }
1204
                if (arg1 == d_fpMap.end())
1205
                {
1206
                  workStack.push_back(current[1]);
1207
                }
1208
                if (arg2 == d_fpMap.end())
1209
                {
1210
                  workStack.push_back(current[2]);
1211
                }
1212
                if (arg3 == d_fpMap.end())
1213
                {
1214
                  workStack.push_back(current[3]);
1215
                }
1216
                continue;  // i.e. recurse!
1217
              }
1218
1219
              d_fpMap.insert(current,
1220
                             symfpu::fma<traits>(fpt(current.getType()),
1221
                                                 (*mode).second,
1222
                                                 (*arg1).second,
1223
                                                 (*arg2).second,
1224
                                                 (*arg3).second));
1225
            }
1226
            break;
1227
1228
            /******** Conversions ********/
1229
2
            case kind::FLOATINGPOINT_TO_FP_FLOATINGPOINT:
1230
            {
1231
2
              rmMap::const_iterator mode(d_rmMap.find(current[0]));
1232
2
              fpMap::const_iterator arg1(d_fpMap.find(current[1]));
1233
              bool recurseNeeded =
1234
2
                  (mode == d_rmMap.end()) || (arg1 == d_fpMap.end());
1235
1236
2
              if (recurseNeeded)
1237
              {
1238
                workStack.push_back(current);
1239
                if (mode == d_rmMap.end())
1240
                {
1241
                  workStack.push_back(current[0]);
1242
                }
1243
                if (arg1 == d_fpMap.end())
1244
                {
1245
                  workStack.push_back(current[1]);
1246
                }
1247
                continue;  // i.e. recurse!
1248
              }
1249
1250
4
              d_fpMap.insert(
1251
                  current,
1252
8
                  symfpu::convertFloatToFloat<traits>(fpt(current[1].getType()),
1253
4
                                                      fpt(current.getType()),
1254
2
                                                      (*mode).second,
1255
4
                                                      (*arg1).second));
1256
            }
1257
2
            break;
1258
1259
2
            case kind::FLOATINGPOINT_FP:
1260
            {
1261
              Node IEEEBV(nm->mkNode(
1262
4
                  kind::BITVECTOR_CONCAT, current[0], current[1], current[2]));
1263
4
              d_fpMap.insert(
1264
                  current,
1265
6
                  symfpu::unpack<traits>(fpt(current.getType()), IEEEBV));
1266
            }
1267
2
            break;
1268
1269
12
            case kind::FLOATINGPOINT_TO_FP_IEEE_BITVECTOR:
1270
24
              d_fpMap.insert(current,
1271
24
                             symfpu::unpack<traits>(fpt(current.getType()),
1272
24
                                                    ubv(current[0])));
1273
12
              break;
1274
1275
8
            case kind::FLOATINGPOINT_TO_FP_SIGNED_BITVECTOR:
1276
            case kind::FLOATINGPOINT_TO_FP_UNSIGNED_BITVECTOR:
1277
            {
1278
8
              rmMap::const_iterator mode(d_rmMap.find(current[0]));
1279
8
              bool recurseNeeded = (mode == d_rmMap.end());
1280
1281
8
              if (recurseNeeded)
1282
              {
1283
                workStack.push_back(current);
1284
                if (mode == d_rmMap.end())
1285
                {
1286
                  workStack.push_back(current[0]);
1287
                }
1288
                continue;  // i.e. recurse!
1289
              }
1290
1291
8
              switch (current.getKind())
1292
              {
1293
                case kind::FLOATINGPOINT_TO_FP_SIGNED_BITVECTOR:
1294
                  d_fpMap.insert(
1295
                      current,
1296
                      symfpu::convertSBVToFloat<traits>(fpt(current.getType()),
1297
                                                        (*mode).second,
1298
                                                        sbv(current[1])));
1299
                  break;
1300
1301
8
                case kind::FLOATINGPOINT_TO_FP_UNSIGNED_BITVECTOR:
1302
16
                  d_fpMap.insert(
1303
                      current,
1304
32
                      symfpu::convertUBVToFloat<traits>(fpt(current.getType()),
1305
8
                                                        (*mode).second,
1306
16
                                                        ubv(current[1])));
1307
8
                  break;
1308
1309
                default:
1310
                  Unreachable() << "Unknown converstion from bit-vector to "
1311
                                   "floating-point";
1312
                  break;
1313
8
              }
1314
            }
1315
8
            break;
1316
1317
            case kind::FLOATINGPOINT_TO_FP_REAL:
1318
            {
1319
              d_fpMap.insert(current, buildComponents(current));
1320
              // Rely on the real theory and theory combination
1321
              // to handle the value
1322
            }
1323
            break;
1324
1325
            case kind::FLOATINGPOINT_TO_FP_GENERIC:
1326
              Unreachable() << "Generic to_fp not removed";
1327
              break;
1328
1329
            default:
1330
              Unreachable() << "Unknown kind of type FloatingPoint";
1331
              break;
1332
          }
1333
        }
1334
      }
1335
      // Returns a floating-point type so don't alter the return value
1336
    }
1337
1392
    else if (t.isBoolean())
1338
    {
1339
625
      boolMap::const_iterator i(d_boolMap.find(current));
1340
1341
625
      if (i == d_boolMap.end())
1342
      {
1343
625
        switch (current.getKind())
1344
        {
1345
          /******** Comparisons ********/
1346
485
          case kind::EQUAL:
1347
          {
1348
820
            TypeNode childType(current[0].getType());
1349
1350
485
            if (childType.isFloatingPoint())
1351
            {
1352
335
              fpMap::const_iterator arg1(d_fpMap.find(current[0]));
1353
335
              fpMap::const_iterator arg2(d_fpMap.find(current[1]));
1354
              bool recurseNeeded =
1355
335
                  (arg1 == d_fpMap.end()) || (arg2 == d_fpMap.end());
1356
1357
335
              if (recurseNeeded)
1358
              {
1359
                workStack.push_back(current);
1360
                if (arg1 == d_fpMap.end())
1361
                {
1362
                  workStack.push_back(current[0]);
1363
                }
1364
                if (arg2 == d_fpMap.end())
1365
                {
1366
                  workStack.push_back(current[1]);
1367
                }
1368
                continue;  // i.e. recurse!
1369
              }
1370
1371
670
              d_boolMap.insert(
1372
                  current,
1373
1340
                  symfpu::smtlibEqual<traits>(
1374
1340
                      fpt(childType), (*arg1).second, (*arg2).second));
1375
            }
1376
150
            else if (childType.isRoundingMode())
1377
            {
1378
              rmMap::const_iterator arg1(d_rmMap.find(current[0]));
1379
              rmMap::const_iterator arg2(d_rmMap.find(current[1]));
1380
              bool recurseNeeded =
1381
                  (arg1 == d_rmMap.end()) || (arg2 == d_rmMap.end());
1382
1383
              if (recurseNeeded)
1384
              {
1385
                workStack.push_back(current);
1386
                if (arg1 == d_rmMap.end())
1387
                {
1388
                  workStack.push_back(current[0]);
1389
                }
1390
                if (arg2 == d_rmMap.end())
1391
                {
1392
                  workStack.push_back(current[1]);
1393
                }
1394
                continue;  // i.e. recurse!
1395
              }
1396
1397
              d_boolMap.insert(current, (*arg1).second == (*arg2).second);
1398
            }
1399
            else
1400
            {
1401
150
              CVC5_FPCONV_PASSTHROUGH;
1402
150
              return result;
1403
335
            }
1404
          }
1405
335
          break;
1406
1407
56
          case kind::FLOATINGPOINT_LEQ:
1408
          case kind::FLOATINGPOINT_LT:
1409
          {
1410
112
            TypeNode childType(current[0].getType());
1411
1412
56
            fpMap::const_iterator arg1(d_fpMap.find(current[0]));
1413
56
            fpMap::const_iterator arg2(d_fpMap.find(current[1]));
1414
            bool recurseNeeded =
1415
56
                (arg1 == d_fpMap.end()) || (arg2 == d_fpMap.end());
1416
1417
56
            if (recurseNeeded)
1418
            {
1419
              workStack.push_back(current);
1420
              if (arg1 == d_fpMap.end())
1421
              {
1422
                workStack.push_back(current[0]);
1423
              }
1424
              if (arg2 == d_fpMap.end())
1425
              {
1426
                workStack.push_back(current[1]);
1427
              }
1428
              continue;  // i.e. recurse!
1429
            }
1430
1431
56
            switch (current.getKind())
1432
            {
1433
52
              case kind::FLOATINGPOINT_LEQ:
1434
104
                d_boolMap.insert(
1435
                    current,
1436
208
                    symfpu::lessThanOrEqual<traits>(
1437
208
                        fpt(childType), (*arg1).second, (*arg2).second));
1438
52
                break;
1439
1440
4
              case kind::FLOATINGPOINT_LT:
1441
8
                d_boolMap.insert(
1442
                    current,
1443
16
                    symfpu::lessThan<traits>(
1444
16
                        fpt(childType), (*arg1).second, (*arg2).second));
1445
4
                break;
1446
1447
              default:
1448
                Unreachable() << "Unknown binary floating-point relation";
1449
                break;
1450
56
            }
1451
          }
1452
56
          break;
1453
1454
84
          case kind::FLOATINGPOINT_ISN:
1455
          case kind::FLOATINGPOINT_ISSN:
1456
          case kind::FLOATINGPOINT_ISZ:
1457
          case kind::FLOATINGPOINT_ISINF:
1458
          case kind::FLOATINGPOINT_ISNAN:
1459
          case kind::FLOATINGPOINT_ISNEG:
1460
          case kind::FLOATINGPOINT_ISPOS:
1461
          {
1462
168
            TypeNode childType(current[0].getType());
1463
84
            fpMap::const_iterator arg1(d_fpMap.find(current[0]));
1464
1465
84
            if (arg1 == d_fpMap.end())
1466
            {
1467
              workStack.push_back(current);
1468
              workStack.push_back(current[0]);
1469
              continue;  // i.e. recurse!
1470
            }
1471
1472
84
            switch (current.getKind())
1473
            {
1474
              case kind::FLOATINGPOINT_ISN:
1475
                d_boolMap.insert(
1476
                    current,
1477
                    symfpu::isNormal<traits>(fpt(childType), (*arg1).second));
1478
                break;
1479
1480
3
              case kind::FLOATINGPOINT_ISSN:
1481
6
                d_boolMap.insert(current,
1482
6
                                 symfpu::isSubnormal<traits>(fpt(childType),
1483
3
                                                             (*arg1).second));
1484
3
                break;
1485
1486
7
              case kind::FLOATINGPOINT_ISZ:
1487
14
                d_boolMap.insert(
1488
                    current,
1489
14
                    symfpu::isZero<traits>(fpt(childType), (*arg1).second));
1490
7
                break;
1491
1492
26
              case kind::FLOATINGPOINT_ISINF:
1493
52
                d_boolMap.insert(
1494
                    current,
1495
52
                    symfpu::isInfinite<traits>(fpt(childType), (*arg1).second));
1496
26
                break;
1497
1498
22
              case kind::FLOATINGPOINT_ISNAN:
1499
44
                d_boolMap.insert(
1500
                    current,
1501
44
                    symfpu::isNaN<traits>(fpt(childType), (*arg1).second));
1502
22
                break;
1503
1504
5
              case kind::FLOATINGPOINT_ISPOS:
1505
10
                d_boolMap.insert(
1506
                    current,
1507
10
                    symfpu::isPositive<traits>(fpt(childType), (*arg1).second));
1508
5
                break;
1509
1510
21
              case kind::FLOATINGPOINT_ISNEG:
1511
42
                d_boolMap.insert(
1512
                    current,
1513
42
                    symfpu::isNegative<traits>(fpt(childType), (*arg1).second));
1514
21
                break;
1515
1516
              default:
1517
                Unreachable() << "Unknown unary floating-point relation";
1518
                break;
1519
84
            }
1520
          }
1521
84
          break;
1522
1523
          case kind::FLOATINGPOINT_EQ:
1524
          case kind::FLOATINGPOINT_GEQ:
1525
          case kind::FLOATINGPOINT_GT:
1526
            Unreachable() << "Kind should have been removed by rewriter.";
1527
            break;
1528
1529
          // Components will be registered as they are owned by
1530
          // the floating-point theory.  No action is required.
1531
          case kind::FLOATINGPOINT_COMPONENT_NAN:
1532
          case kind::FLOATINGPOINT_COMPONENT_INF:
1533
          case kind::FLOATINGPOINT_COMPONENT_ZERO:
1534
          case kind::FLOATINGPOINT_COMPONENT_SIGN:
1535
          /* Fall through... */
1536
1537
          default:
1538
            CVC5_FPCONV_PASSTHROUGH;
1539
            return result;
1540
            break;
1541
        }
1542
1543
475
        i = d_boolMap.find(current);
1544
      }
1545
1546
475
      result = (*i).second;
1547
    }
1548
767
    else if (t.isBitVector())
1549
    {
1550
767
      switch (current.getKind())
1551
      {
1552
        /******** Conversions ********/
1553
        case kind::FLOATINGPOINT_TO_UBV_TOTAL:
1554
        {
1555
          TypeNode childType(current[1].getType());
1556
          ubvMap::const_iterator i(d_ubvMap.find(current));
1557
1558
          if (i == d_ubvMap.end())
1559
          {
1560
            rmMap::const_iterator mode(d_rmMap.find(current[0]));
1561
            fpMap::const_iterator arg1(d_fpMap.find(current[1]));
1562
            bool recurseNeeded =
1563
                (mode == d_rmMap.end()) || (arg1 == d_fpMap.end());
1564
1565
            if (recurseNeeded)
1566
            {
1567
              workStack.push_back(current);
1568
              if (mode == d_rmMap.end())
1569
              {
1570
                workStack.push_back(current[0]);
1571
              }
1572
              if (arg1 == d_fpMap.end())
1573
              {
1574
                workStack.push_back(current[1]);
1575
              }
1576
              continue;  // i.e. recurse!
1577
            }
1578
1579
            FloatingPointToUBVTotal info =
1580
                current.getOperator().getConst<FloatingPointToUBVTotal>();
1581
1582
            d_ubvMap.insert(current,
1583
                            symfpu::convertFloatToUBV<traits>(fpt(childType),
1584
                                                              (*mode).second,
1585
                                                              (*arg1).second,
1586
                                                              info.d_bv_size,
1587
                                                              ubv(current[2])));
1588
            i = d_ubvMap.find(current);
1589
          }
1590
1591
          result = (*i).second;
1592
        }
1593
        break;
1594
1595
        case kind::FLOATINGPOINT_TO_SBV_TOTAL:
1596
        {
1597
          TypeNode childType(current[1].getType());
1598
          sbvMap::const_iterator i(d_sbvMap.find(current));
1599
1600
          if (i == d_sbvMap.end())
1601
          {
1602
            rmMap::const_iterator mode(d_rmMap.find(current[0]));
1603
            fpMap::const_iterator arg1(d_fpMap.find(current[1]));
1604
            bool recurseNeeded =
1605
                (mode == d_rmMap.end()) || (arg1 == d_fpMap.end());
1606
1607
            if (recurseNeeded)
1608
            {
1609
              workStack.push_back(current);
1610
              if (mode == d_rmMap.end())
1611
              {
1612
                workStack.push_back(current[0]);
1613
              }
1614
              if (arg1 == d_fpMap.end())
1615
              {
1616
                workStack.push_back(current[1]);
1617
              }
1618
              continue;  // i.e. recurse!
1619
            }
1620
1621
            FloatingPointToSBVTotal info =
1622
                current.getOperator().getConst<FloatingPointToSBVTotal>();
1623
1624
            d_sbvMap.insert(current,
1625
                            symfpu::convertFloatToSBV<traits>(fpt(childType),
1626
                                                              (*mode).second,
1627
                                                              (*arg1).second,
1628
                                                              info.d_bv_size,
1629
                                                              sbv(current[2])));
1630
1631
            i = d_sbvMap.find(current);
1632
          }
1633
1634
          result = (*i).second;
1635
        }
1636
        break;
1637
1638
        case kind::FLOATINGPOINT_TO_UBV:
1639
          Unreachable()
1640
              << "Partially defined fp.to_ubv should have been removed by "
1641
                 "expandDefinition";
1642
          break;
1643
1644
        case kind::FLOATINGPOINT_TO_SBV:
1645
          Unreachable()
1646
              << "Partially defined fp.to_sbv should have been removed by "
1647
                 "expandDefinition";
1648
          break;
1649
1650
        // Again, no action is needed
1651
767
        case kind::FLOATINGPOINT_COMPONENT_EXPONENT:
1652
        case kind::FLOATINGPOINT_COMPONENT_SIGNIFICAND:
1653
        case kind::ROUNDINGMODE_BITBLAST:
1654
        /* Fall through ... */
1655
1656
767
        default: CVC5_FPCONV_PASSTHROUGH; break;
1657
      }
1658
    }
1659
    else if (t.isReal())
1660
    {
1661
      switch (current.getKind())
1662
      {
1663
        /******** Conversions ********/
1664
        case kind::FLOATINGPOINT_TO_REAL_TOTAL:
1665
        {
1666
          // We need to recurse so that any variables that are only
1667
          // used under this will have components created
1668
          // (via auxiliary constraints)
1669
1670
          TypeNode childType(current[0].getType());
1671
          fpMap::const_iterator arg1(d_fpMap.find(current[0]));
1672
1673
          if (arg1 == d_fpMap.end())
1674
          {
1675
            workStack.push_back(current);
1676
            workStack.push_back(current[0]);
1677
            continue;  // i.e. recurse!
1678
          }
1679
1680
          // However we don't need to do anything explicitly with
1681
          // this as it will be treated as an uninterpreted function
1682
          // by the real theory and we don't need to bit-blast the
1683
          // float expression unless we need to say something about
1684
          // its value.
1685
        }
1686
1687
        break;
1688
1689
        case kind::FLOATINGPOINT_TO_REAL:
1690
          Unreachable()
1691
              << "Partially defined fp.to_real should have been removed by "
1692
                 "expandDefinition";
1693
          break;
1694
1695
        default: CVC5_FPCONV_PASSTHROUGH; break;
1696
      }
1697
    }
1698
    else
1699
    {
1700
      CVC5_FPCONV_PASSTHROUGH;
1701
    }
1702
  }
1703
1704
1772
  return result;
1705
#else
1706
  Unimplemented() << "Conversion is dependent on SymFPU";
1707
#endif
1708
}
1709
1710
#undef CVC5_FPCONV_PASSTHROUGH
1711
1712
3295
Node FpConverter::getValue(Valuation &val, TNode var)
1713
{
1714
3295
  Assert(Theory::isLeafOf(var, THEORY_FP));
1715
1716
#ifdef CVC5_USE_SYMFPU
1717
6590
  TypeNode t(var.getType());
1718
1719
3295
  Assert(t.isRoundingMode() || t.isFloatingPoint())
1720
      << "Asking for the value of a type that is not managed by the "
1721
         "floating-point theory";
1722
1723
3295
  if (t.isRoundingMode())
1724
  {
1725
152
    rmMap::const_iterator i(d_rmMap.find(var));
1726
1727
152
    Assert(i != d_rmMap.end())
1728
        << "Asking for the value of an unregistered expression";
1729
152
    return rmToNode((*i).second);
1730
  }
1731
3143
  fpMap::const_iterator i(d_fpMap.find(var));
1732
1733
3143
  Assert(i != d_fpMap.end())
1734
      << "Asking for the value of an unregistered expression";
1735
3143
  return ufToNode(fpt(t), (*i).second);
1736
#else
1737
  Unimplemented() << "Conversion is dependent on SymFPU";
1738
#endif
1739
}
1740
1741
}  // namespace fp
1742
}  // namespace theory
1743
28194
}  // namespace cvc5