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 |
1514897 |
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 |
1454371 |
nodeWrapper(const Node &n) : Node(n) {} |
113 |
|
#endif |
114 |
|
}; |
115 |
|
|
116 |
545051 |
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 |
939449 |
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 */ |