GCC Code Coverage Report
Directory: . Exec Total Coverage
File: src/theory/fp/fp_converter.h Lines: 5 5 100.0 %
Date: 2021-05-22 Branches: 0 0 0.0 %

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
 * Converts floating-point nodes to bit-vector expressions.
14
 *
15
 * Uses the symfpu library to convert from floating-point operations to
16
 * bit-vectors and propositions allowing the theory to be solved by
17
 * 'bit-blasting'.
18
 *
19
 * !!! This header is not to be included in any other headers !!!
20
 */
21
22
#include "cvc5_private.h"
23
24
#ifndef CVC5__THEORY__FP__FP_CONVERTER_H
25
#define CVC5__THEORY__FP__FP_CONVERTER_H
26
27
#include "context/cdhashmap.h"
28
#include "context/cdlist.h"
29
#include "expr/node.h"
30
#include "expr/type_node.h"
31
#include "theory/valuation.h"
32
#include "util/bitvector.h"
33
#include "util/floatingpoint_size.h"
34
#include "util/hash.h"
35
36
#ifdef CVC5_USE_SYMFPU
37
#include "symfpu/core/unpackedFloat.h"
38
#endif
39
40
#ifdef CVC5_SYM_SYMBOLIC_EVAL
41
// This allows debugging of the cvc5 symbolic back-end.
42
// By enabling this and disabling constant folding in the rewriter,
43
// SMT files that have operations on constants will be evaluated
44
// during the encoding step, which means that the expressions
45
// generated by the symbolic back-end can be debugged with gdb.
46
#include "theory/rewriter.h"
47
#endif
48
49
namespace cvc5 {
50
namespace theory {
51
namespace fp {
52
53
/**
54
 * This is a symfpu symbolic "back-end".  It allows the library to be used to
55
 * construct bit-vector expressions that compute floating-point operations.
56
 * This is effectively the glue between symfpu's notion of "signed bit-vector"
57
 * and cvc5's node.
58
 */
59
namespace symfpuSymbolic {
60
61
// Forward declarations of the wrapped types so that traits can be defined early
62
// and used in the implementations
63
class symbolicRoundingMode;
64
class floatingPointTypeInfo;
65
class symbolicProposition;
66
template <bool T>
67
class symbolicBitVector;
68
69
// This is the template parameter for symfpu's templates.
70
class traits
71
{
72
 public:
73
  // The six key types that symfpu uses.
74
  typedef unsigned bwt;
75
  typedef symbolicRoundingMode rm;
76
  typedef floatingPointTypeInfo fpt;
77
  typedef symbolicProposition prop;
78
  typedef symbolicBitVector<true> sbv;
79
  typedef symbolicBitVector<false> ubv;
80
81
  // Give concrete instances (wrapped nodes) for each rounding mode.
82
  static symbolicRoundingMode RNE(void);
83
  static symbolicRoundingMode RNA(void);
84
  static symbolicRoundingMode RTP(void);
85
  static symbolicRoundingMode RTN(void);
86
  static symbolicRoundingMode RTZ(void);
87
88
  // Properties used by symfpu
89
  static void precondition(const bool b);
90
  static void postcondition(const bool b);
91
  static void invariant(const bool b);
92
  static void precondition(const prop &p);
93
  static void postcondition(const prop &p);
94
  static void invariant(const prop &p);
95
};
96
97
// Use the same type names as symfpu.
98
typedef traits::bwt bwt;
99
100
/**
101
 * Wrap the cvc5::Node types so that we can debug issues with this back-end
102
 */
103
1473010
class nodeWrapper : public Node
104
{
105
 protected:
106
/* CVC5_SYM_SYMBOLIC_EVAL is for debugging cvc5 symbolic back-end issues.
107
 * Enable this and disabling constant folding will mean that operations
108
 * that are input with constant args are 'folded' using the symbolic encoding
109
 * allowing them to be traced via GDB.
110
 */
111
#ifdef CVC5_SYM_SYMBOLIC_EVAL
112
  nodeWrapper(const Node &n) : Node(theory::Rewriter::rewrite(n)) {}
113
#else
114
1415874
  nodeWrapper(const Node &n) : Node(n) {}
115
#endif
116
};
117
118
532985
class symbolicProposition : public nodeWrapper
119
{
120
 protected:
121
  bool checkNodeType(const TNode node);
122
123
#ifdef CVC5_USE_SYMFPU
124
  friend ::symfpu::ite<symbolicProposition, symbolicProposition>;  // For ITE
125
#endif
126
127
 public:
128
  symbolicProposition(const Node n);
129
  symbolicProposition(bool v);
130
  symbolicProposition(const symbolicProposition &old);
131
132
  symbolicProposition operator!(void)const;
133
  symbolicProposition operator&&(const symbolicProposition &op) const;
134
  symbolicProposition operator||(const symbolicProposition &op) const;
135
  symbolicProposition operator==(const symbolicProposition &op) const;
136
  symbolicProposition operator^(const symbolicProposition &op) const;
137
};
138
139
1847
class symbolicRoundingMode : public nodeWrapper
140
{
141
 protected:
142
  bool checkNodeType(const TNode n);
143
144
#ifdef CVC5_USE_SYMFPU
145
  friend ::symfpu::ite<symbolicProposition, symbolicRoundingMode>;  // For ITE
146
#endif
147
148
 public:
149
  symbolicRoundingMode(const Node n);
150
  symbolicRoundingMode(const unsigned v);
151
  symbolicRoundingMode(const symbolicRoundingMode &old);
152
153
  symbolicProposition valid(void) const;
154
  symbolicProposition operator==(const symbolicRoundingMode &op) const;
155
};
156
157
// Type function for mapping between types
158
template <bool T>
159
struct signedToLiteralType;
160
161
template <>
162
struct signedToLiteralType<true>
163
{
164
  typedef int literalType;
165
};
166
template <>
167
struct signedToLiteralType<false>
168
{
169
  typedef unsigned int literalType;
170
};
171
172
template <bool isSigned>
173
911330
class symbolicBitVector : public nodeWrapper
174
{
175
 protected:
176
  typedef typename signedToLiteralType<isSigned>::literalType literalType;
177
178
  Node boolNodeToBV(Node node) const;
179
  Node BVToBoolNode(Node node) const;
180
181
  Node fromProposition(Node node) const;
182
  Node toProposition(Node node) const;
183
  bool checkNodeType(const TNode n);
184
  friend symbolicBitVector<!isSigned>;  // To allow conversion between the types
185
186
#ifdef CVC5_USE_SYMFPU
187
  friend ::symfpu::ite<symbolicProposition,
188
                       symbolicBitVector<isSigned> >;  // For ITE
189
#endif
190
191
 public:
192
  symbolicBitVector(const Node n);
193
  symbolicBitVector(const bwt w, const unsigned v);
194
  symbolicBitVector(const symbolicProposition &p);
195
  symbolicBitVector(const symbolicBitVector<isSigned> &old);
196
  symbolicBitVector(const BitVector &old);
197
198
  bwt getWidth(void) const;
199
200
  /*** Constant creation and test ***/
201
  static symbolicBitVector<isSigned> one(const bwt &w);
202
  static symbolicBitVector<isSigned> zero(const bwt &w);
203
  static symbolicBitVector<isSigned> allOnes(const bwt &w);
204
205
  symbolicProposition isAllOnes() const;
206
  symbolicProposition isAllZeros() const;
207
208
  static symbolicBitVector<isSigned> maxValue(const bwt &w);
209
  static symbolicBitVector<isSigned> minValue(const bwt &w);
210
211
  /*** Operators ***/
212
  symbolicBitVector<isSigned> operator<<(
213
      const symbolicBitVector<isSigned> &op) const;
214
  symbolicBitVector<isSigned> operator>>(
215
      const symbolicBitVector<isSigned> &op) const;
216
  symbolicBitVector<isSigned> operator|(
217
      const symbolicBitVector<isSigned> &op) const;
218
  symbolicBitVector<isSigned> operator&(
219
      const symbolicBitVector<isSigned> &op) const;
220
  symbolicBitVector<isSigned> operator+(
221
      const symbolicBitVector<isSigned> &op) const;
222
  symbolicBitVector<isSigned> operator-(
223
      const symbolicBitVector<isSigned> &op) const;
224
  symbolicBitVector<isSigned> operator*(
225
      const symbolicBitVector<isSigned> &op) const;
226
  symbolicBitVector<isSigned> operator/(
227
      const symbolicBitVector<isSigned> &op) const;
228
  symbolicBitVector<isSigned> operator%(
229
      const symbolicBitVector<isSigned> &op) const;
230
  symbolicBitVector<isSigned> operator-(void) const;
231
  symbolicBitVector<isSigned> operator~(void)const;
232
  symbolicBitVector<isSigned> increment() const;
233
  symbolicBitVector<isSigned> decrement() const;
234
  symbolicBitVector<isSigned> signExtendRightShift(
235
      const symbolicBitVector<isSigned> &op) const;
236
237
  /*** Modular operations ***/
238
  // This back-end doesn't do any overflow checking so these are the same as
239
  // other operations
240
  symbolicBitVector<isSigned> modularLeftShift(
241
      const symbolicBitVector<isSigned> &op) const;
242
  symbolicBitVector<isSigned> modularRightShift(
243
      const symbolicBitVector<isSigned> &op) const;
244
  symbolicBitVector<isSigned> modularIncrement() const;
245
  symbolicBitVector<isSigned> modularDecrement() const;
246
  symbolicBitVector<isSigned> modularAdd(
247
      const symbolicBitVector<isSigned> &op) const;
248
  symbolicBitVector<isSigned> modularNegate() const;
249
250
  /*** Comparisons ***/
251
  symbolicProposition operator==(const symbolicBitVector<isSigned> &op) const;
252
  symbolicProposition operator<=(const symbolicBitVector<isSigned> &op) const;
253
  symbolicProposition operator>=(const symbolicBitVector<isSigned> &op) const;
254
  symbolicProposition operator<(const symbolicBitVector<isSigned> &op) const;
255
  symbolicProposition operator>(const symbolicBitVector<isSigned> &op) const;
256
257
  /*** Type conversion ***/
258
  // cvc5 nodes make no distinction between signed and unsigned, thus these are
259
  // trivial
260
  symbolicBitVector<true> toSigned(void) const;
261
  symbolicBitVector<false> toUnsigned(void) const;
262
263
  /*** Bit hacks ***/
264
  symbolicBitVector<isSigned> extend(bwt extension) const;
265
  symbolicBitVector<isSigned> contract(bwt reduction) const;
266
  symbolicBitVector<isSigned> resize(bwt newSize) const;
267
  symbolicBitVector<isSigned> matchWidth(
268
      const symbolicBitVector<isSigned> &op) const;
269
  symbolicBitVector<isSigned> append(
270
      const symbolicBitVector<isSigned> &op) const;
271
272
  // Inclusive of end points, thus if the same, extracts just one bit
273
  symbolicBitVector<isSigned> extract(bwt upper, bwt lower) const;
274
};
275
276
// Use the same type information as the literal back-end but add an interface to
277
// TypeNodes for convenience.
278
class floatingPointTypeInfo : public FloatingPointSize
279
{
280
 public:
281
  floatingPointTypeInfo(const TypeNode t);
282
  floatingPointTypeInfo(unsigned exp, unsigned sig);
283
  floatingPointTypeInfo(const floatingPointTypeInfo &old);
284
285
  TypeNode getTypeNode(void) const;
286
};
287
}
288
289
/**
290
 * This class uses SymFPU to convert an expression containing floating-point
291
 * kinds and operations into a logically equivalent form with bit-vector
292
 * operations replacing the floating-point ones.  It also has a getValue method
293
 * to produce an expression which will reconstruct the value of the
294
 * floating-point terms from a valuation.
295
 *
296
 * Internally it caches all of the unpacked floats so that unnecessary packing
297
 * and unpacking operations are avoided and to make best use of structural
298
 * sharing.
299
 */
300
class FpConverter
301
{
302
 public:
303
  /** Constructor. */
304
  FpConverter(context::UserContext*);
305
  /** Destructor. */
306
  ~FpConverter();
307
308
  /** Adds a node to the conversion, returns the converted node */
309
  Node convert(TNode);
310
311
  /** Gives the node representing the value of a given variable */
312
  Node getValue(Valuation&, TNode);
313
314
  context::CDList<Node> d_additionalAssertions;
315
316
 protected:
317
#ifdef CVC5_USE_SYMFPU
318
  typedef symfpuSymbolic::traits traits;
319
  typedef ::symfpu::unpackedFloat<symfpuSymbolic::traits> uf;
320
  typedef symfpuSymbolic::traits::rm rm;
321
  typedef symfpuSymbolic::traits::fpt fpt;
322
  typedef symfpuSymbolic::traits::prop prop;
323
  typedef symfpuSymbolic::traits::ubv ubv;
324
  typedef symfpuSymbolic::traits::sbv sbv;
325
326
  typedef context::CDHashMap<Node, uf> fpMap;
327
  typedef context::CDHashMap<Node, rm> rmMap;
328
  typedef context::CDHashMap<Node, prop> boolMap;
329
  typedef context::CDHashMap<Node, ubv> ubvMap;
330
  typedef context::CDHashMap<Node, sbv> sbvMap;
331
332
  fpMap d_fpMap;
333
  rmMap d_rmMap;
334
  boolMap d_boolMap;
335
  ubvMap d_ubvMap;
336
  sbvMap d_sbvMap;
337
338
  /* These functions take a symfpu object and convert it to a node.
339
   * These should ensure that constant folding it will give a
340
   * constant of the right type.
341
   */
342
343
  Node ufToNode(const fpt &, const uf &) const;
344
  Node rmToNode(const rm &) const;
345
  Node propToNode(const prop &) const;
346
  Node ubvToNode(const ubv &) const;
347
  Node sbvToNode(const sbv &) const;
348
349
  /* Creates the relevant components for a variable */
350
  uf buildComponents(TNode current);
351
#endif
352
};
353
354
}  // namespace fp
355
}  // namespace theory
356
}  // namespace cvc5
357
358
#endif /* CVC5__THEORY__FP__THEORY_FP_H */