Skip to content

Commit 1d360a8

Browse files
author
Daniel Kroening
authored
Merge pull request #3549 from diffblue/smt2_solver_fpa
smt2-solver: FPA
2 parents e18ac13 + fef58a5 commit 1d360a8

File tree

4 files changed

+162
-3
lines changed

4 files changed

+162
-3
lines changed

src/solvers/smt2/smt2_format.cpp

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,14 @@ std::ostream &smt2_format_rec(std::ostream &out, const typet &type)
2828
out << "(Array " << smt2_format(array_type.size().type()) << ' '
2929
<< smt2_format(array_type.subtype()) << ')';
3030
}
31+
else if(type.id() == ID_floatbv)
32+
{
33+
const auto &floatbv_type = to_floatbv_type(type);
34+
// the width of the mantissa needs to be increased by one to
35+
// include the hidden bit
36+
out << "(_ FloatingPoint " << floatbv_type.get_e() << ' '
37+
<< floatbv_type.get_f() + 1 << ')';
38+
}
3139
else
3240
out << "? " << type.id();
3341

@@ -78,6 +86,10 @@ std::ostream &smt2_format_rec(std::ostream &out, const exprt &expr)
7886

7987
out << '"';
8088
}
89+
else if(expr_type.id() == ID_floatbv)
90+
{
91+
out << value;
92+
}
8193
else
8294
DATA_INVARIANT(false, "unhandled constant: " + expr_type.id_string());
8395
}

src/solvers/smt2/smt2_parser.cpp

Lines changed: 142 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ Author: Daniel Kroening, [email protected]
1111
#include "smt2_format.h"
1212

1313
#include <util/arith_tools.h>
14+
#include <util/ieee_float.h>
1415
#include <util/range.h>
1516

1617
#include <numeric>
@@ -398,6 +399,74 @@ exprt smt2_parsert::binary(irep_idt id, const exprt::operandst &op)
398399
return binary_exprt(op[0], id, op[1], op[0].type());
399400
}
400401

402+
exprt smt2_parsert::function_application_ieee_float_op(
403+
const irep_idt &id,
404+
const exprt::operandst &op)
405+
{
406+
if(op.size() != 3)
407+
{
408+
std::ostringstream message;
409+
message << id << " takes three operands";
410+
throw error(message);
411+
}
412+
413+
if(op[1].type().id() != ID_floatbv || op[2].type().id() != ID_floatbv)
414+
{
415+
std::ostringstream message;
416+
message << id << " takes FloatingPoint operands";
417+
throw error(message);
418+
}
419+
420+
if(op[1].type() != op[2].type())
421+
{
422+
std::ostringstream message;
423+
message << id << " takes FloatingPoint operands with matching sort, "
424+
<< "but got " << smt2_format(op[1].type()) << " vs "
425+
<< smt2_format(op[2].type());
426+
throw error(message);
427+
}
428+
429+
// clang-format off
430+
const irep_idt expr_id =
431+
id == "fp.add" ? ID_floatbv_plus :
432+
id == "fp.sub" ? ID_floatbv_minus :
433+
id == "fp.mul" ? ID_floatbv_mult :
434+
id == "fp.div" ? ID_floatbv_div :
435+
throw error("unsupported floating-point operation");
436+
// clang-format on
437+
438+
return std::move(ieee_float_op_exprt(op[1], expr_id, op[2], op[0]));
439+
}
440+
441+
exprt smt2_parsert::function_application_fp(const exprt::operandst &op)
442+
{
443+
// floating-point from bit-vectors
444+
if(op.size() != 3)
445+
throw error("fp takes three operands");
446+
447+
if(op[0].type().id() != ID_unsignedbv)
448+
throw error("fp takes BitVec as first operand");
449+
450+
if(op[1].type().id() != ID_unsignedbv)
451+
throw error("fp takes BitVec as second operand");
452+
453+
if(op[2].type().id() != ID_unsignedbv)
454+
throw error("fp takes BitVec as third operand");
455+
456+
if(to_unsignedbv_type(op[0].type()).get_width() != 1)
457+
throw error("fp takes BitVec of size 1 as first operand");
458+
459+
const auto width_e = to_unsignedbv_type(op[1].type()).get_width();
460+
const auto width_f = to_unsignedbv_type(op[2].type()).get_width();
461+
462+
// stitch the bits together
463+
concatenation_exprt c(bv_typet(width_e + width_f + 1));
464+
c.operands() = {op[0], op[1], op[2]};
465+
466+
return std::move(
467+
typecast_exprt(c, ieee_float_spect(width_f, width_e).to_type()));
468+
}
469+
401470
exprt smt2_parsert::function_application()
402471
{
403472
switch(next_token())
@@ -674,6 +743,35 @@ exprt smt2_parsert::function_application()
674743

675744
return with_exprt(op[0], op[1], op[2]);
676745
}
746+
else if(id == "fp.isNaN")
747+
{
748+
if(op.size() != 1)
749+
throw error("fp.isNaN takes one operand");
750+
751+
if(op[0].type().id() != ID_floatbv)
752+
throw error("fp.isNaN takes FloatingPoint operand");
753+
754+
return unary_predicate_exprt(ID_isnan, op[0]);
755+
}
756+
else if(id == "fp.isInf")
757+
{
758+
if(op.size() != 1)
759+
throw error("fp.isInf takes one operand");
760+
761+
if(op[0].type().id() != ID_floatbv)
762+
throw error("fp.isInf takes FloatingPoint operand");
763+
764+
return unary_predicate_exprt(ID_isinf, op[0]);
765+
}
766+
else if(id == "fp")
767+
{
768+
return function_application_fp(op);
769+
}
770+
else if(
771+
id == "fp.add" || id == "fp.mul" || id == "fp.sub" || id == "fp.div")
772+
{
773+
return function_application_ieee_float_op(id, op);
774+
}
677775
else
678776
{
679777
// rummage through id_map
@@ -864,6 +962,32 @@ exprt smt2_parsert::expression()
864962
return true_exprt();
865963
else if(identifier==ID_false)
866964
return false_exprt();
965+
else if(identifier == "roundNearestTiesToEven")
966+
{
967+
// we encode as 32-bit unsignedbv
968+
return from_integer(ieee_floatt::ROUND_TO_EVEN, unsignedbv_typet(32));
969+
}
970+
else if(identifier == "roundNearestTiesToAway")
971+
{
972+
throw error("unsupported rounding mode");
973+
}
974+
else if(identifier == "roundTowardPositive")
975+
{
976+
// we encode as 32-bit unsignedbv
977+
return from_integer(
978+
ieee_floatt::ROUND_TO_PLUS_INF, unsignedbv_typet(32));
979+
}
980+
else if(identifier == "roundTowardNegative")
981+
{
982+
// we encode as 32-bit unsignedbv
983+
return from_integer(
984+
ieee_floatt::ROUND_TO_MINUS_INF, unsignedbv_typet(32));
985+
}
986+
else if(identifier == "roundTowardZero")
987+
{
988+
// we encode as 32-bit unsignedbv
989+
return from_integer(ieee_floatt::ROUND_TO_ZERO, unsignedbv_typet(32));
990+
}
867991
else
868992
{
869993
// rummage through id_map
@@ -959,6 +1083,24 @@ typet smt2_parsert::sort()
9591083

9601084
return unsignedbv_typet(width);
9611085
}
1086+
else if(buffer == "FloatingPoint")
1087+
{
1088+
if(next_token() != NUMERAL)
1089+
throw error("expected numeral as bit-width");
1090+
1091+
const auto width_e = std::stoll(buffer);
1092+
1093+
if(next_token() != NUMERAL)
1094+
throw error("expected numeral as bit-width");
1095+
1096+
const auto width_f = std::stoll(buffer);
1097+
1098+
// consume the ')'
1099+
if(next_token() != CLOSE)
1100+
throw error("expected ')' at end of sort");
1101+
1102+
return ieee_float_spect(width_f - 1, width_e).to_type();
1103+
}
9621104
else
9631105
{
9641106
std::ostringstream msg;

src/solvers/smt2/smt2_parser.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -99,6 +99,10 @@ class smt2_parsert:public smt2_tokenizert
9999
void ignore_command();
100100
exprt expression();
101101
exprt function_application();
102+
exprt function_application_ieee_float_op(
103+
const irep_idt &,
104+
const exprt::operandst &);
105+
exprt function_application_fp(const exprt::operandst &);
102106
typet sort();
103107
exprt::operandst operands();
104108
typet function_signature_declaration();

src/util/std_expr.h

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4268,8 +4268,9 @@ inline void validate_expr(const ieee_float_notequal_exprt &value)
42684268
validate_operands(value, 2, "IEEE inequality must have two operands");
42694269
}
42704270

4271-
42724271
/// \brief IEEE floating-point operations
4272+
/// These have two data operands (op0 and op1) and one rounding mode (op2).
4273+
/// The type of the result is that of the data operands.
42734274
class ieee_float_op_exprt:public exprt
42744275
{
42754276
public:
@@ -4283,8 +4284,8 @@ class ieee_float_op_exprt:public exprt
42834284
const exprt &_lhs,
42844285
const irep_idt &_id,
42854286
const exprt &_rhs,
4286-
const exprt &_rm):
4287-
exprt(_id)
4287+
const exprt &_rm)
4288+
: exprt(_id, _lhs.type())
42884289
{
42894290
add_to_operands(_lhs, _rhs, _rm);
42904291
}

0 commit comments

Comments
 (0)