Skip to content

Commit 587e5ef

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

File tree

10 files changed

+117
-11
lines changed

10 files changed

+117
-11
lines changed

regression/cbmc/rational1/main.c

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
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 != x, "should fail");
9+
}
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
CORE smt-backend broken-cprover-smt-backend no-new-smt
2+
main.c
3+
--trace --smt2
4+
^EXIT=10$
5+
^SIGNAL=0$
6+
--
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
CORE
2+
main.c
3+
--show-goto-functions
4+
^[[:space:]]*ASSIGN main::1::x := cast\(6 / 10, ℚ\)
5+
^EXIT=0$
6+
^SIGNAL=0$
7+
--

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: 56 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,8 @@ Author: Daniel Kroening, kroening@kroening.com
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>
@@ -416,8 +418,7 @@ constant_exprt smt2_convt::parse_literal(
416418

417419
if(!src.id().empty())
418420
{
419-
const std::string &s=src.id_string();
420-
421+
const std::string &s = src.id_string();
421422
if(s.size()>=2 && s[0]=='#' && s[1]=='b')
422423
{
423424
// Binary #b010101
@@ -430,8 +431,29 @@ constant_exprt smt2_convt::parse_literal(
430431
}
431432
else
432433
{
434+
std::size_t pos = s.find(".");
435+
if(pos != std::string::npos)
436+
{
437+
// Decimal, return as rational
438+
mp_integer first = string2integer(s.substr(0, pos));
439+
mp_integer second = string2integer(s.substr(pos, std::string::npos));
440+
if(type.id() == ID_rational)
441+
{
442+
rationalt rational_value(first);
443+
rationalt second_rational(second);
444+
rationalt tmp = rational_value + second_rational / rationalt(100);
445+
return from_rational(tmp);
446+
}
447+
else
448+
{
449+
UNREACHABLE_BECAUSE(
450+
"smt2_convt::parse_literal parsed a number with a decimal point "
451+
"in, which cannot be converted to type " +
452+
type.id_string());
453+
}
454+
}
433455
// Numeral
434-
value=string2integer(s);
456+
value = string2integer(s);
435457
}
436458
}
437459
else if(src.get_sub().size()==2 &&
@@ -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/expr.cpp

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -59,8 +59,10 @@ bool exprt::is_zero() const
5959
{
6060
rationalt rat_value;
6161
if(to_rational(*this, rat_value))
62-
CHECK_RETURN(false);
63-
return rat_value.is_zero();
62+
{
63+
// CHECK_RETURN(false);
64+
return rat_value.is_zero();
65+
}
6466
}
6567
else if(
6668
type_id == ID_unsignedbv || type_id == ID_signedbv ||

src/util/pointer_expr.cpp

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@ unsigned int dynamic_object_exprt::get_instance() const
2626
return std::stoul(id2string(to_constant_expr(op0()).get_value()));
2727
}
2828

29+
#include <iostream>
2930
/// Build an object_descriptor_exprt from a given expr
3031
static void build_object_descriptor_rec(
3132
const namespacet &ns,
@@ -39,6 +40,11 @@ static void build_object_descriptor_rec(
3940
build_object_descriptor_rec(ns, index.array(), dest);
4041

4142
auto sub_size = size_of_expr(expr.type(), ns);
43+
if(!sub_size.has_value())
44+
{
45+
std::cout << "no value for " << id2string(expr.type().id()) << std::endl;
46+
}
47+
CHECK_RETURN(sub_size.has_value());
4248

4349
if(sub_size.has_value())
4450
{

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: 16 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -29,11 +29,18 @@ 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);
3333

3434
std::string no1, no2;
3535
char mode=0;
3636

37+
bool is_negative = false;
38+
if(value[0] == '-')
39+
{
40+
is_negative = true;
41+
value = value.substr(1, value.size() - 1);
42+
}
43+
3744
for(const char ch : value)
3845
{
3946
if(isdigit(ch))
@@ -54,20 +61,23 @@ bool to_rational(const exprt &expr, rationalt &rational_value)
5461
return true;
5562
}
5663

64+
if(is_negative)
65+
rational_value = rationalt(-string2integer(no1));
66+
else
67+
rational_value = rationalt(string2integer(no1));
68+
5769
switch(mode)
5870
{
5971
case 0:
60-
rational_value=rationalt(string2integer(no1));
72+
// do nothing
6173
break;
6274

6375
case '.':
64-
rational_value=rationalt(string2integer(no1));
65-
rational_value+=
66-
rationalt(string2integer(no2))/rationalt(power10(no2.size()));
76+
rational_value +=
77+
rationalt(string2integer(no2)) / rationalt(power10(no2.size()));
6778
break;
6879

6980
case '/':
70-
rational_value=rationalt(string2integer(no1));
7181
rational_value/=rationalt(string2integer(no2));
7282
break;
7383

0 commit comments

Comments
 (0)