Skip to content

Commit cadd0a6

Browse files
authored
Merge pull request #8922 from tautschnig/fix-8054-smt2-incr-floating-point
Add floating point support to incremental SMT2 solver via bit-blasting
2 parents 6df204e + ae300b3 commit cadd0a6

File tree

6 files changed

+144
-24
lines changed

6 files changed

+144
-24
lines changed
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
int main()
2+
{
3+
float x = 1.0f;
4+
float y = 2.0f;
5+
__CPROVER_assert(x + y == 3.0f, "float add");
6+
__CPROVER_assert(x < y, "float lt");
7+
__CPROVER_assert(x != y, "float ne");
8+
__CPROVER_assert(!(x != x), "x == x");
9+
}
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
CORE
2+
basic.c
3+
4+
^VERIFICATION SUCCESSFUL$
5+
^EXIT=0$
6+
^SIGNAL=0$
7+
--
8+
--
9+
Basic floating-point operations via bit-blasting in incremental SMT2.
Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
// _Float16 requires GCC >= 12 or Clang >= 15.
2+
// On other compilers, fall back to a trivial float test.
3+
#if defined(__GNUC__) && !defined(__clang__) && __GNUC__ >= 12
4+
# define HAS_FLOAT16
5+
#elif defined(__clang__) && __clang_major__ >= 15
6+
# define HAS_FLOAT16
7+
#endif
8+
9+
#ifdef HAS_FLOAT16
10+
11+
int main()
12+
{
13+
_Float16 a = 3.0f16;
14+
_Float16 b = 2.0f16;
15+
16+
__CPROVER_assert(a + b == 5.0f16, "add");
17+
__CPROVER_assert(a - b == 1.0f16, "sub");
18+
__CPROVER_assert(a * b == 6.0f16, "mul");
19+
__CPROVER_assert(a / b == 1.5f16, "div");
20+
__CPROVER_assert(a > b, "gt");
21+
__CPROVER_assert(b < a, "lt");
22+
__CPROVER_assert(-a == -3.0f16, "neg");
23+
24+
int i = (int)a;
25+
__CPROVER_assert(i == 3, "to_int");
26+
_Float16 c = (_Float16)5;
27+
__CPROVER_assert(c == 5.0f16, "from_int");
28+
float d = (float)a;
29+
__CPROVER_assert(d == 3.0f, "f16_to_f32");
30+
}
31+
32+
#else
33+
34+
int main()
35+
{
36+
}
37+
38+
#endif
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
CORE
2+
float16_ops.c
3+
4+
^VERIFICATION SUCCESSFUL$
5+
^EXIT=0$
6+
^SIGNAL=0$
7+
--
8+
--
9+
Tests float arithmetic, comparisons, negation, and casts via
10+
incremental SMT2 with float_bvt bit-blasting. Uses _Float16
11+
where available (GCC >= 12, Clang >= 15) for small formulae.

src/solvers/smt2_incremental/convert_expr_to_smt.cpp

Lines changed: 38 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -96,6 +96,12 @@ static smt_sortt convert_type_to_smt_sort(const array_typet &type)
9696
convert_type_to_smt_sort(type.element_type())};
9797
}
9898

99+
static smt_sortt convert_type_to_smt_sort(const floatbv_typet &type)
100+
{
101+
// Convert floating-point to bitvector for bit-blasting
102+
return smt_bit_vector_sortt{type.get_width()};
103+
}
104+
99105
smt_sortt convert_type_to_smt_sort(const typet &type)
100106
{
101107
if(const auto bool_type = type_try_dynamic_cast<bool_typet>(type))
@@ -104,6 +110,10 @@ smt_sortt convert_type_to_smt_sort(const typet &type)
104110
}
105111
if(const auto bitvector_type = type_try_dynamic_cast<bitvector_typet>(type))
106112
{
113+
if(const auto floatbv_type = type_try_dynamic_cast<floatbv_typet>(type))
114+
{
115+
return convert_type_to_smt_sort(*floatbv_type);
116+
}
107117
return convert_type_to_smt_sort(*bitvector_type);
108118
}
109119
if(const auto array_type = type_try_dynamic_cast<array_typet>(type))
@@ -182,13 +192,8 @@ static smt_termt make_bitvector_resize_cast(
182192
"type: " +
183193
to_type.pretty());
184194
}
185-
if(type_try_dynamic_cast<floatbv_typet>(to_type))
186-
{
187-
UNIMPLEMENTED_FEATURE(
188-
"Generation of SMT formula for type cast to floating-point bitvector "
189-
"type: " +
190-
to_type.pretty());
191-
}
195+
// After float lowering, floatbv types are treated as bitvectors.
196+
// Same-width casts (e.g., from float_bvt::pack) are handled below.
192197
const std::size_t from_width = from_type.get_width();
193198
const std::size_t to_width = to_type.get_width();
194199
if(to_width == from_width)
@@ -272,8 +277,11 @@ static smt_termt convert_expr_to_smt(
272277
const floatbv_typecast_exprt &float_cast,
273278
const sub_expression_mapt &converted)
274279
{
275-
UNIMPLEMENTED_FEATURE(
276-
"Generation of SMT formula for floating point type cast expression: " +
280+
// Floating-point operations should be lowered to bitvector operations
281+
// before reaching this point. If we get here, it means the lowering failed.
282+
UNREACHABLE_BECAUSE(
283+
"Floating point type cast expression should have been lowered to "
284+
"bitvector operations: " +
277285
float_cast.pretty());
278286
}
279287

@@ -535,17 +543,19 @@ static smt_termt convert_expr_to_smt(
535543
const ieee_float_equal_exprt &float_equal,
536544
const sub_expression_mapt &converted)
537545
{
538-
UNIMPLEMENTED_FEATURE(
539-
"Generation of SMT formula for floating point equality expression: " +
546+
UNREACHABLE_BECAUSE(
547+
"Floating point equality expression should have been lowered to "
548+
"bitvector operations: " +
540549
float_equal.pretty());
541550
}
542551

543552
static smt_termt convert_expr_to_smt(
544553
const ieee_float_notequal_exprt &float_not_equal,
545554
const sub_expression_mapt &converted)
546555
{
547-
UNIMPLEMENTED_FEATURE(
548-
"Generation of SMT formula for floating point not equal expression: " +
556+
UNREACHABLE_BECAUSE(
557+
"Floating point not equal expression should have been lowered to "
558+
"bitvector operations: " +
549559
float_not_equal.pretty());
550560
}
551561

@@ -785,8 +795,9 @@ static smt_termt convert_expr_to_smt(
785795
{
786796
// This case includes the floating point plus, minus, division and
787797
// multiplication operations.
788-
UNIMPLEMENTED_FEATURE(
789-
"Generation of SMT formula for floating point operation expression: " +
798+
UNREACHABLE_BECAUSE(
799+
"Floating point operation expression should have been lowered to "
800+
"bitvector operations: " +
790801
float_operation.pretty());
791802
}
792803

@@ -1158,35 +1169,39 @@ static smt_termt convert_expr_to_smt(
11581169
const isnan_exprt &is_nan_expr,
11591170
const sub_expression_mapt &converted)
11601171
{
1161-
UNIMPLEMENTED_FEATURE(
1162-
"Generation of SMT formula for is not a number expression: " +
1172+
UNREACHABLE_BECAUSE(
1173+
"Is not a number expression should have been lowered to "
1174+
"bitvector operations: " +
11631175
is_nan_expr.pretty());
11641176
}
11651177

11661178
static smt_termt convert_expr_to_smt(
11671179
const isfinite_exprt &is_finite_expr,
11681180
const sub_expression_mapt &converted)
11691181
{
1170-
UNIMPLEMENTED_FEATURE(
1171-
"Generation of SMT formula for is finite expression: " +
1182+
UNREACHABLE_BECAUSE(
1183+
"Is finite expression should have been lowered to "
1184+
"bitvector operations: " +
11721185
is_finite_expr.pretty());
11731186
}
11741187

11751188
static smt_termt convert_expr_to_smt(
11761189
const isinf_exprt &is_infinite_expr,
11771190
const sub_expression_mapt &converted)
11781191
{
1179-
UNIMPLEMENTED_FEATURE(
1180-
"Generation of SMT formula for is infinite expression: " +
1192+
UNREACHABLE_BECAUSE(
1193+
"Is infinite expression should have been lowered to "
1194+
"bitvector operations: " +
11811195
is_infinite_expr.pretty());
11821196
}
11831197

11841198
static smt_termt convert_expr_to_smt(
11851199
const isnormal_exprt &is_normal_expr,
11861200
const sub_expression_mapt &converted)
11871201
{
1188-
UNIMPLEMENTED_FEATURE(
1189-
"Generation of SMT formula for is infinite expression: " +
1202+
UNREACHABLE_BECAUSE(
1203+
"Is normal expression should have been lowered to "
1204+
"bitvector operations: " +
11901205
is_normal_expr.pretty());
11911206
}
11921207

src/solvers/smt2_incremental/smt2_incremental_decision_procedure.cpp

Lines changed: 39 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111
#include <util/std_expr.h>
1212
#include <util/string_constant.h>
1313

14+
#include <solvers/floatbv/float_bv.h>
1415
#include <solvers/smt2_incremental/ast/smt_commands.h>
1516
#include <solvers/smt2_incremental/ast/smt_responses.h>
1617
#include <solvers/smt2_incremental/ast/smt_terms.h>
@@ -308,6 +309,42 @@ static exprt lower_zero_extend(exprt expr, const namespacet &ns)
308309
return expr;
309310
}
310311

312+
/// \brief Check whether an expression or any of its immediate operands
313+
/// has floating-point bitvector type.
314+
static bool has_floatbv_type(const exprt &expr)
315+
{
316+
if(expr.type().id() == ID_floatbv)
317+
return true;
318+
for(const auto &op : expr.operands())
319+
{
320+
if(op.type().id() == ID_floatbv)
321+
return true;
322+
}
323+
return false;
324+
}
325+
326+
/// \brief Lower floating-point operations to bitvector expressions.
327+
/// Traverses \p expr bottom-up and replaces float-specific sub-expressions
328+
/// (e.g., ieee_float_equal, floatbv_plus) with their bitvector equivalents
329+
/// using \ref float_bvt::convert.
330+
static exprt lower_floatbv(exprt expr)
331+
{
332+
// Recurse into operands first (bottom-up)
333+
for(auto &op : expr.operands())
334+
op = lower_floatbv(op);
335+
336+
// Only attempt float_bv conversion on expressions involving floats
337+
if(has_floatbv_type(expr))
338+
{
339+
const float_bvt float_bv;
340+
const exprt converted = float_bv.convert(expr);
341+
if(!converted.is_nil())
342+
return converted;
343+
}
344+
345+
return expr;
346+
}
347+
311348
void smt2_incremental_decision_proceduret::ensure_handle_for_expr_defined(
312349
const exprt &in_expr)
313350
{
@@ -688,7 +725,8 @@ exprt smt2_incremental_decision_proceduret::lower(exprt expression) const
688725
{
689726
const exprt lowered = struct_encoding.encode(lower_zero_extend(
690727
lower_enum(
691-
lower_byte_operators(lower_rw_ok_pointer_in_range(expression, ns), ns),
728+
lower_byte_operators(
729+
lower_floatbv(lower_rw_ok_pointer_in_range(expression, ns)), ns),
692730
ns),
693731
ns));
694732
log.conditional_output(log.debug(), [&](messaget::mstreamt &debug) {

0 commit comments

Comments
 (0)