Skip to content

Commit 1ab08a6

Browse files
polgreentautschnig
authored andcommitted
Fix and demonstrate support for __CPROVER_rational
1 parent 5f4c82d commit 1ab08a6

File tree

9 files changed

+132
-6
lines changed

9 files changed

+132
-6
lines changed

regression/cbmc/rational1/main.c

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
int main()
2+
{
3+
__CPROVER_rational x;
4+
__CPROVER_rational y;
5+
x = 6 / 10;
6+
y = 3 / 5;
7+
8+
__CPROVER_assert(y + 1 != x, "should pass");
9+
__CPROVER_assert(y != x, "should fail");
10+
}
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
CORE smt-backend broken-cprover-smt-backend no-new-smt
2+
main.c
3+
--trace --smt2
4+
^\[main.assertion.2\] line 9 should fail: FAILURE$
5+
^\*\* 1 of 2 failed
6+
^EXIT=10$
7+
^SIGNAL=0$
8+
--
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
CORE
2+
main.c
3+
--show-goto-functions
4+
^[[:space:]]*ASSIGN main::1::x := 3/5
5+
^[[:space:]]*ASSIGN main::1::y := 3/5
6+
^EXIT=0$
7+
^SIGNAL=0$
8+
--

src/ansi-c/c_typecast.cpp

Lines changed: 25 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,20 +8,22 @@ Author: Daniel Kroening, [email protected]
88

99
#include "c_typecast.h"
1010

11-
#include <algorithm>
12-
1311
#include <util/arith_tools.h>
1412
#include <util/c_types.h>
1513
#include <util/config.h>
1614
#include <util/expr_util.h>
1715
#include <util/mathematical_types.h>
1816
#include <util/namespace.h>
1917
#include <util/pointer_expr.h>
18+
#include <util/rational.h>
19+
#include <util/rational_tools.h>
2020
#include <util/simplify_expr.h>
2121
#include <util/std_expr.h>
2222

2323
#include "c_qualifiers.h"
2424

25+
#include <algorithm>
26+
2527
bool c_implicit_typecast(
2628
exprt &expr,
2729
const typet &dest_type,
@@ -776,6 +778,27 @@ void c_typecastt::do_typecast(exprt &expr, const typet &dest_type)
776778
{
777779
expr=is_not_zero(expr, ns);
778780
}
781+
else if(dest_type.id() == ID_rational)
782+
{
783+
if(auto div_expr = expr_try_dynamic_cast<div_exprt>(expr))
784+
{
785+
auto op1 = numeric_cast<mp_integer>(div_expr->lhs());
786+
auto op2 = numeric_cast<mp_integer>(div_expr->rhs());
787+
if(op1.has_value() && op2.has_value())
788+
{
789+
rationalt numerator{*op1};
790+
expr = from_rational(rationalt{*op1} / rationalt{*op2});
791+
return;
792+
}
793+
}
794+
else if(auto int_const = numeric_cast<mp_integer>(expr))
795+
{
796+
expr = from_integer(*int_const, dest_type);
797+
return;
798+
}
799+
800+
expr = typecast_exprt(expr, dest_type);
801+
}
779802
else
780803
{
781804
expr = typecast_exprt(expr, dest_type);

src/solvers/flattening/boolbv_width.cpp

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -206,6 +206,10 @@ const boolbv_widtht::entryt &boolbv_widtht::get_entry(const typet &type) const
206206
{
207207
cache_entry = defined_entryt{0};
208208
}
209+
else if(type_id == ID_rational)
210+
{
211+
cache_entry = defined_entryt{1};
212+
}
209213
else
210214
{
211215
UNIMPLEMENTED_FEATURE(

src/solvers/smt2/smt2_conv.cpp

Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,8 @@ Author: Daniel Kroening, [email protected]
2929
#include <util/pointer_predicates.h>
3030
#include <util/prefix.h>
3131
#include <util/range.h>
32+
#include <util/rational.h>
33+
#include <util/rational_tools.h>
3234
#include <util/simplify_expr.h>
3335
#include <util/std_expr.h>
3436
#include <util/string2int.h>
@@ -430,6 +432,26 @@ constant_exprt smt2_convt::parse_literal(
430432
}
431433
else
432434
{
435+
std::size_t pos = s.find(".");
436+
if(pos != std::string::npos)
437+
{
438+
// Decimal, return as rational
439+
if(type.id() == ID_rational)
440+
{
441+
rationalt rational_value;
442+
bool failed = to_rational(
443+
constant_exprt{src.id(), rational_typet{}}, rational_value);
444+
CHECK_RETURN(!failed);
445+
return from_rational(rational_value);
446+
}
447+
else
448+
{
449+
UNREACHABLE_BECAUSE(
450+
"smt2_convt::parse_literal parsed a number with a decimal point "
451+
"as type " +
452+
type.id_string());
453+
}
454+
}
433455
// Numeral
434456
value=string2integer(s);
435457
}
@@ -527,6 +549,11 @@ constant_exprt smt2_convt::parse_literal(
527549
{
528550
return from_integer(value + to_range_type(type).get_from(), type);
529551
}
552+
else if(type.id() == ID_rational)
553+
{
554+
// TODO parse this literal back correctly.
555+
return from_integer(value, type);
556+
}
530557
else
531558
UNREACHABLE_BECAUSE(
532559
"smt2_convt::parse_literal should not be of unsupported type " +
@@ -3167,6 +3194,19 @@ void smt2_convt::convert_typecast(const typecast_exprt &expr)
31673194
convert_typecast(tmp);
31683195
}
31693196
}
3197+
else if(dest_type.id() == ID_rational)
3198+
{
3199+
if(src_type.id() == ID_signedbv)
3200+
{
3201+
// TODO: negative numbers
3202+
out << "(/ ";
3203+
convert_expr(src);
3204+
out << " 1)";
3205+
}
3206+
else
3207+
UNEXPECTEDCASE(
3208+
"Unknown typecast " + src_type.id_string() + " -> rational");
3209+
}
31703210
else
31713211
UNEXPECTEDCASE(
31723212
"TODO typecast8 "+src_type.id_string()+" -> "+dest_type.id_string());
@@ -3588,7 +3628,10 @@ void smt2_convt::convert_constant(const constant_exprt &expr)
35883628
const bool negative = has_prefix(value, "-");
35893629

35903630
if(negative)
3631+
{
35913632
out << "(- ";
3633+
value = value.substr(1);
3634+
}
35923635

35933636
size_t pos=value.find("/");
35943637

@@ -4190,6 +4233,16 @@ void smt2_convt::convert_div(const div_exprt &expr)
41904233
// the rounding mode. See smt2_convt::convert_floatbv_div.
41914234
UNREACHABLE;
41924235
}
4236+
else if(
4237+
expr.type().id() == ID_rational || expr.type().id() == ID_integer ||
4238+
expr.type().id() == ID_real)
4239+
{
4240+
out << "(/ ";
4241+
convert_expr(expr.op0());
4242+
out << " ";
4243+
convert_expr(expr.op1());
4244+
out << ")";
4245+
}
41934246
else
41944247
UNEXPECTEDCASE("unsupported type for /: "+expr.type().id_string());
41954248
}

src/util/arith_tools.cpp

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -177,6 +177,10 @@ constant_exprt from_integer(
177177
ieee_float.from_integer(int_value);
178178
return ieee_float.to_expr();
179179
}
180+
else if(type_id == ID_rational)
181+
{
182+
return constant_exprt(integer2string(int_value), type);
183+
}
180184
else
181185
PRECONDITION(false);
182186
}

src/util/pointer_offset_size.cpp

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -488,6 +488,11 @@ std::optional<exprt> size_of_expr(const typet &type, const namespacet &ns)
488488
{
489489
return from_integer(32 / config.ansi_c.char_width, size_type());
490490
}
491+
else if(type.id() == ID_rational)
492+
{
493+
// these shouldn't really have sizes but this will do
494+
return from_integer(1, size_type());
495+
}
491496
else
492497
return {};
493498
}

src/util/rational_tools.cpp

Lines changed: 15 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -29,11 +29,19 @@ bool to_rational(const exprt &expr, rationalt &rational_value)
2929
if(!expr.is_constant())
3030
return true;
3131

32-
const std::string &value=expr.get_string(ID_value);
32+
std::string value = expr.get_string(ID_value);
33+
PRECONDITION(!value.empty());
3334

3435
std::string no1, no2;
3536
char mode=0;
3637

38+
bool is_negative = false;
39+
if(value[0] == '-')
40+
{
41+
is_negative = true;
42+
value = value.substr(1);
43+
}
44+
3745
for(const char ch : value)
3846
{
3947
if(isdigit(ch))
@@ -54,20 +62,23 @@ bool to_rational(const exprt &expr, rationalt &rational_value)
5462
return true;
5563
}
5664

65+
if(is_negative)
66+
rational_value = rationalt{-string2integer(no1)};
67+
else
68+
rational_value = rationalt{string2integer(no1)};
69+
5770
switch(mode)
5871
{
5972
case 0:
60-
rational_value=rationalt(string2integer(no1));
73+
// do nothing
6174
break;
6275

6376
case '.':
64-
rational_value=rationalt(string2integer(no1));
6577
rational_value+=
6678
rationalt(string2integer(no2))/rationalt(power10(no2.size()));
6779
break;
6880

6981
case '/':
70-
rational_value=rationalt(string2integer(no1));
7182
rational_value/=rationalt(string2integer(no2));
7283
break;
7384

0 commit comments

Comments
 (0)