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