1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
| //===- SMTAPI.h -------------------------------------------------*- C++ -*-===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
//
// This file defines a SMT generic Solver API, which will be the base class
// for every SMT solver specific class.
//
//===----------------------------------------------------------------------===//
#ifndef LLVM_SUPPORT_SMTAPI_H
#define LLVM_SUPPORT_SMTAPI_H
#include "llvm/ADT/APFloat.h"
#include "llvm/ADT/APSInt.h"
#include "llvm/ADT/FoldingSet.h"
#include "llvm/Support/raw_ostream.h"
#include <memory>
namespace llvm {
/// Generic base class for SMT sorts
class SMTSort {
public:
SMTSort() = default;
virtual ~SMTSort() = default;
/// Returns true if the sort is a bitvector, calls isBitvectorSortImpl().
virtual bool isBitvectorSort() const { return isBitvectorSortImpl(); }
/// Returns true if the sort is a floating-point, calls isFloatSortImpl().
virtual bool isFloatSort() const { return isFloatSortImpl(); }
/// Returns true if the sort is a boolean, calls isBooleanSortImpl().
virtual bool isBooleanSort() const { return isBooleanSortImpl(); }
/// Returns the bitvector size, fails if the sort is not a bitvector
/// Calls getBitvectorSortSizeImpl().
virtual unsigned getBitvectorSortSize() const {
assert(isBitvectorSort() && "Not a bitvector sort!");
unsigned Size = getBitvectorSortSizeImpl();
assert(Size && "Size is zero!");
return Size;
};
/// Returns the floating-point size, fails if the sort is not a floating-point
/// Calls getFloatSortSizeImpl().
virtual unsigned getFloatSortSize() const {
assert(isFloatSort() && "Not a floating-point sort!");
unsigned Size = getFloatSortSizeImpl();
assert(Size && "Size is zero!");
return Size;
};
virtual void Profile(llvm::FoldingSetNodeID &ID) const = 0;
bool operator<(const SMTSort &Other) const {
llvm::FoldingSetNodeID ID1, ID2;
Profile(ID1);
Other.Profile(ID2);
return ID1 < ID2;
}
friend bool operator==(SMTSort const &LHS, SMTSort const &RHS) {
return LHS.equal_to(RHS);
}
virtual void print(raw_ostream &OS) const = 0;
LLVM_DUMP_METHOD void dump() const;
protected:
/// Query the SMT solver and returns true if two sorts are equal (same kind
/// and bit width). This does not check if the two sorts are the same objects.
virtual bool equal_to(SMTSort const &other) const = 0;
/// Query the SMT solver and checks if a sort is bitvector.
virtual bool isBitvectorSortImpl() const = 0;
/// Query the SMT solver and checks if a sort is floating-point.
virtual bool isFloatSortImpl() const = 0;
/// Query the SMT solver and checks if a sort is boolean.
virtual bool isBooleanSortImpl() const = 0;
/// Query the SMT solver and returns the sort bit width.
virtual unsigned getBitvectorSortSizeImpl() const = 0;
/// Query the SMT solver and returns the sort bit width.
virtual unsigned getFloatSortSizeImpl() const = 0;
};
/// Shared pointer for SMTSorts, used by SMTSolver API.
using SMTSortRef = const SMTSort *;
/// Generic base class for SMT exprs
class SMTExpr {
public:
SMTExpr() = default;
virtual ~SMTExpr() = default;
bool operator<(const SMTExpr &Other) const {
llvm::FoldingSetNodeID ID1, ID2;
Profile(ID1);
Other.Profile(ID2);
return ID1 < ID2;
}
virtual void Profile(llvm::FoldingSetNodeID &ID) const = 0;
friend bool operator==(SMTExpr const &LHS, SMTExpr const &RHS) {
return LHS.equal_to(RHS);
}
virtual void print(raw_ostream &OS) const = 0;
LLVM_DUMP_METHOD void dump() const;
protected:
/// Query the SMT solver and returns true if two sorts are equal (same kind
/// and bit width). This does not check if the two sorts are the same objects.
virtual bool equal_to(SMTExpr const &other) const = 0;
};
/// Shared pointer for SMTExprs, used by SMTSolver API.
using SMTExprRef = const SMTExpr *;
/// Generic base class for SMT Solvers
///
/// This class is responsible for wrapping all sorts and expression generation,
/// through the mk* methods. It also provides methods to create SMT expressions
/// straight from clang's AST, through the from* methods.
class SMTSolver {
public:
SMTSolver() = default;
virtual ~SMTSolver() = default;
LLVM_DUMP_METHOD void dump() const;
// Returns an appropriate floating-point sort for the given bitwidth.
SMTSortRef getFloatSort(unsigned BitWidth) {
switch (BitWidth) {
case 16:
return getFloat16Sort();
case 32:
return getFloat32Sort();
case 64:
return getFloat64Sort();
case 128:
return getFloat128Sort();
default:;
}
llvm_unreachable("Unsupported floating-point bitwidth!");
}
// Returns a boolean sort.
virtual SMTSortRef getBoolSort() = 0;
// Returns an appropriate bitvector sort for the given bitwidth.
virtual SMTSortRef getBitvectorSort(const unsigned BitWidth) = 0;
// Returns a floating-point sort of width 16
virtual SMTSortRef getFloat16Sort() = 0;
// Returns a floating-point sort of width 32
virtual SMTSortRef getFloat32Sort() = 0;
// Returns a floating-point sort of width 64
virtual SMTSortRef getFloat64Sort() = 0;
// Returns a floating-point sort of width 128
virtual SMTSortRef getFloat128Sort() = 0;
// Returns an appropriate sort for the given AST.
virtual SMTSortRef getSort(const SMTExprRef &AST) = 0;
/// Given a constraint, adds it to the solver
virtual void addConstraint(const SMTExprRef &Exp) const = 0;
/// Creates a bitvector addition operation
virtual SMTExprRef mkBVAdd(const SMTExprRef &LHS, const SMTExprRef &RHS) = 0;
/// Creates a bitvector subtraction operation
virtual SMTExprRef mkBVSub(const SMTExprRef &LHS, const SMTExprRef &RHS) = 0;
/// Creates a bitvector multiplication operation
virtual SMTExprRef mkBVMul(const SMTExprRef &LHS, const SMTExprRef &RHS) = 0;
/// Creates a bitvector signed modulus operation
virtual SMTExprRef mkBVSRem(const SMTExprRef &LHS, const SMTExprRef &RHS) = 0;
/// Creates a bitvector unsigned modulus operation
virtual SMTExprRef mkBVURem(const SMTExprRef &LHS, const SMTExprRef &RHS) = 0;
/// Creates a bitvector signed division operation
virtual SMTExprRef mkBVSDiv(const SMTExprRef &LHS, const SMTExprRef &RHS) = 0;
/// Creates a bitvector unsigned division operation
virtual SMTExprRef mkBVUDiv(const SMTExprRef &LHS, const SMTExprRef &RHS) = 0;
/// Creates a bitvector logical shift left operation
virtual SMTExprRef mkBVShl(const SMTExprRef &LHS, const SMTExprRef &RHS) = 0;
/// Creates a bitvector arithmetic shift right operation
virtual SMTExprRef mkBVAshr(const SMTExprRef &LHS, const SMTExprRef &RHS) = 0;
/// Creates a bitvector logical shift right operation
virtual SMTExprRef mkBVLshr(const SMTExprRef &LHS, const SMTExprRef &RHS) = 0;
/// Creates a bitvector negation operation
virtual SMTExprRef mkBVNeg(const SMTExprRef &Exp) = 0;
/// Creates a bitvector not operation
virtual SMTExprRef mkBVNot(const SMTExprRef &Exp) = 0;
/// Creates a bitvector xor operation
virtual SMTExprRef mkBVXor(const SMTExprRef &LHS, const SMTExprRef &RHS) = 0;
/// Creates a bitvector or operation
virtual SMTExprRef mkBVOr(const SMTExprRef &LHS, const SMTExprRef &RHS) = 0;
/// Creates a bitvector and operation
virtual SMTExprRef mkBVAnd(const SMTExprRef &LHS, const SMTExprRef &RHS) = 0;
/// Creates a bitvector unsigned less-than operation
virtual SMTExprRef mkBVUlt(const SMTExprRef &LHS, const SMTExprRef &RHS) = 0;
/// Creates a bitvector signed less-than operation
virtual SMTExprRef mkBVSlt(const SMTExprRef &LHS, const SMTExprRef &RHS) = 0;
/// Creates a bitvector unsigned greater-than operation
virtual SMTExprRef mkBVUgt(const SMTExprRef &LHS, const SMTExprRef &RHS) = 0;
/// Creates a bitvector signed greater-than operation
virtual SMTExprRef mkBVSgt(const SMTExprRef &LHS, const SMTExprRef &RHS) = 0;
/// Creates a bitvector unsigned less-equal-than operation
virtual SMTExprRef mkBVUle(const SMTExprRef &LHS, const SMTExprRef &RHS) = 0;
/// Creates a bitvector signed less-equal-than operation
virtual SMTExprRef mkBVSle(const SMTExprRef &LHS, const SMTExprRef &RHS) = 0;
/// Creates a bitvector unsigned greater-equal-than operation
virtual SMTExprRef mkBVUge(const SMTExprRef &LHS, const SMTExprRef &RHS) = 0;
/// Creates a bitvector signed greater-equal-than operation
virtual SMTExprRef mkBVSge(const SMTExprRef &LHS, const SMTExprRef &RHS) = 0;
/// Creates a boolean not operation
virtual SMTExprRef mkNot(const SMTExprRef &Exp) = 0;
/// Creates a boolean equality operation
virtual SMTExprRef mkEqual(const SMTExprRef &LHS, const SMTExprRef &RHS) = 0;
/// Creates a boolean and operation
virtual SMTExprRef mkAnd(const SMTExprRef &LHS, const SMTExprRef &RHS) = 0;
/// Creates a boolean or operation
virtual SMTExprRef mkOr(const SMTExprRef &LHS, const SMTExprRef &RHS) = 0;
/// Creates a boolean ite operation
virtual SMTExprRef mkIte(const SMTExprRef &Cond, const SMTExprRef &T,
const SMTExprRef &F) = 0;
/// Creates a bitvector sign extension operation
virtual SMTExprRef mkBVSignExt(unsigned i, const SMTExprRef &Exp) = 0;
/// Creates a bitvector zero extension operation
virtual SMTExprRef mkBVZeroExt(unsigned i, const SMTExprRef &Exp) = 0;
/// Creates a bitvector extract operation
virtual SMTExprRef mkBVExtract(unsigned High, unsigned Low,
const SMTExprRef &Exp) = 0;
/// Creates a bitvector concat operation
virtual SMTExprRef mkBVConcat(const SMTExprRef &LHS,
const SMTExprRef &RHS) = 0;
/// Creates a predicate that checks for overflow in a bitvector addition
/// operation
virtual SMTExprRef mkBVAddNoOverflow(const SMTExprRef &LHS,
const SMTExprRef &RHS,
bool isSigned) = 0;
/// Creates a predicate that checks for underflow in a signed bitvector
/// addition operation
virtual SMTExprRef mkBVAddNoUnderflow(const SMTExprRef &LHS,
const SMTExprRef &RHS) = 0;
/// Creates a predicate that checks for overflow in a signed bitvector
/// subtraction operation
virtual SMTExprRef mkBVSubNoOverflow(const SMTExprRef &LHS,
const SMTExprRef &RHS) = 0;
/// Creates a predicate that checks for underflow in a bitvector subtraction
/// operation
virtual SMTExprRef mkBVSubNoUnderflow(const SMTExprRef &LHS,
const SMTExprRef &RHS,
bool isSigned) = 0;
/// Creates a predicate that checks for overflow in a signed bitvector
/// division/modulus operation
virtual SMTExprRef mkBVSDivNoOverflow(const SMTExprRef &LHS,
const SMTExprRef &RHS) = 0;
/// Creates a predicate that checks for overflow in a bitvector negation
/// operation
virtual SMTExprRef mkBVNegNoOverflow(const SMTExprRef &Exp) = 0;
/// Creates a predicate that checks for overflow in a bitvector multiplication
/// operation
virtual SMTExprRef mkBVMulNoOverflow(const SMTExprRef &LHS,
const SMTExprRef &RHS,
bool isSigned) = 0;
/// Creates a predicate that checks for underflow in a signed bitvector
/// multiplication operation
virtual SMTExprRef mkBVMulNoUnderflow(const SMTExprRef &LHS,
const SMTExprRef &RHS) = 0;
/// Creates a floating-point negation operation
virtual SMTExprRef mkFPNeg(const SMTExprRef &Exp) = 0;
/// Creates a floating-point isInfinite operation
virtual SMTExprRef mkFPIsInfinite(const SMTExprRef &Exp) = 0;
/// Creates a floating-point isNaN operation
virtual SMTExprRef mkFPIsNaN(const SMTExprRef &Exp) = 0;
/// Creates a floating-point isNormal operation
virtual SMTExprRef mkFPIsNormal(const SMTExprRef &Exp) = 0;
/// Creates a floating-point isZero operation
virtual SMTExprRef mkFPIsZero(const SMTExprRef &Exp) = 0;
/// Creates a floating-point multiplication operation
virtual SMTExprRef mkFPMul(const SMTExprRef &LHS, const SMTExprRef &RHS) = 0;
/// Creates a floating-point division operation
virtual SMTExprRef mkFPDiv(const SMTExprRef &LHS, const SMTExprRef &RHS) = 0;
/// Creates a floating-point remainder operation
virtual SMTExprRef mkFPRem(const SMTExprRef &LHS, const SMTExprRef &RHS) = 0;
/// Creates a floating-point addition operation
virtual SMTExprRef mkFPAdd(const SMTExprRef &LHS, const SMTExprRef &RHS) = 0;
/// Creates a floating-point subtraction operation
virtual SMTExprRef mkFPSub(const SMTExprRef &LHS, const SMTExprRef &RHS) = 0;
/// Creates a floating-point less-than operation
virtual SMTExprRef mkFPLt(const SMTExprRef &LHS, const SMTExprRef &RHS) = 0;
/// Creates a floating-point greater-than operation
virtual SMTExprRef mkFPGt(const SMTExprRef &LHS, const SMTExprRef &RHS) = 0;
/// Creates a floating-point less-than-or-equal operation
virtual SMTExprRef mkFPLe(const SMTExprRef &LHS, const SMTExprRef &RHS) = 0;
/// Creates a floating-point greater-than-or-equal operation
virtual SMTExprRef mkFPGe(const SMTExprRef &LHS, const SMTExprRef &RHS) = 0;
/// Creates a floating-point equality operation
virtual SMTExprRef mkFPEqual(const SMTExprRef &LHS,
const SMTExprRef &RHS) = 0;
/// Creates a floating-point conversion from floatint-point to floating-point
/// operation
virtual SMTExprRef mkFPtoFP(const SMTExprRef &From, const SMTSortRef &To) = 0;
/// Creates a floating-point conversion from signed bitvector to
/// floatint-point operation
virtual SMTExprRef mkSBVtoFP(const SMTExprRef &From,
const SMTSortRef &To) = 0;
/// Creates a floating-point conversion from unsigned bitvector to
/// floatint-point operation
virtual SMTExprRef mkUBVtoFP(const SMTExprRef &From,
const SMTSortRef &To) = 0;
/// Creates a floating-point conversion from floatint-point to signed
/// bitvector operation
virtual SMTExprRef mkFPtoSBV(const SMTExprRef &From, unsigned ToWidth) = 0;
/// Creates a floating-point conversion from floatint-point to unsigned
/// bitvector operation
virtual SMTExprRef mkFPtoUBV(const SMTExprRef &From, unsigned ToWidth) = 0;
/// Creates a new symbol, given a name and a sort
virtual SMTExprRef mkSymbol(const char *Name, SMTSortRef Sort) = 0;
// Returns an appropriate floating-point rounding mode.
virtual SMTExprRef getFloatRoundingMode() = 0;
// If the a model is available, returns the value of a given bitvector symbol
virtual llvm::APSInt getBitvector(const SMTExprRef &Exp, unsigned BitWidth,
bool isUnsigned) = 0;
// If the a model is available, returns the value of a given boolean symbol
virtual bool getBoolean(const SMTExprRef &Exp) = 0;
/// Constructs an SMTExprRef from a boolean.
virtual SMTExprRef mkBoolean(const bool b) = 0;
/// Constructs an SMTExprRef from a finite APFloat.
virtual SMTExprRef mkFloat(const llvm::APFloat Float) = 0;
/// Constructs an SMTExprRef from an APSInt and its bit width
virtual SMTExprRef mkBitvector(const llvm::APSInt Int, unsigned BitWidth) = 0;
/// Given an expression, extract the value of this operand in the model.
virtual bool getInterpretation(const SMTExprRef &Exp, llvm::APSInt &Int) = 0;
/// Given an expression extract the value of this operand in the model.
virtual bool getInterpretation(const SMTExprRef &Exp,
llvm::APFloat &Float) = 0;
/// Check if the constraints are satisfiable
virtual Optional<bool> check() const = 0;
/// Push the current solver state
virtual void push() = 0;
/// Pop the previous solver state
virtual void pop(unsigned NumStates = 1) = 0;
/// Reset the solver and remove all constraints.
virtual void reset() = 0;
/// Checks if the solver supports floating-points.
virtual bool isFPSupported() = 0;
virtual void print(raw_ostream &OS) const = 0;
};
/// Shared pointer for SMTSolvers.
using SMTSolverRef = std::shared_ptr<SMTSolver>;
/// Convenience method to create and Z3Solver object
SMTSolverRef CreateZ3Solver();
} // namespace llvm
#endif
|