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