Skip to content

Commit 52ad7c3

Browse files
committed
SMV: implement bit selection operator
This implements the grammar and type checking for SMV's term[high:low] bit-selection operator.
1 parent d128ef8 commit 52ad7c3

File tree

9 files changed

+110
-3
lines changed

9 files changed

+110
-3
lines changed

CHANGELOG

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
# EBMC 5.9
22

33
* SMV: word constants
4+
* SMV: bit selection operator
45

56
# EBMC 5.8
67

regression/smv/word/bit_selection1.desc

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,10 @@
1-
KNOWNBUG
1+
CORE
22
bit_selection1.smv
33
--bound 0
4+
^\[.*\] -0sd7_39\[4:1\] = 0ud4_12: PROVED .*$
5+
^\[.*\] 0ud3_5\[0:0\] = 0ud1_1: PROVED .*$
46
^EXIT=0$
57
^SIGNAL=0$
68
--
79
^warning: ignoring
810
--
9-
This fails to parse.

regression/smv/word/extractbits1.desc renamed to regression/smv/word/bit_selection2.desc

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
CORE
2-
shift1.smv
2+
bit_selection2.smv
33

44
^EXIT=0$
55
^SIGNAL=0$
File renamed without changes.

src/hw_cbmc_irep_ids.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ IREP_ID_ONE(G)
1919
IREP_ID_ONE(X)
2020
IREP_ID_ONE(smv_abs)
2121
IREP_ID_ONE(smv_bitimplies)
22+
IREP_ID_ONE(smv_bit_selection)
2223
IREP_ID_ONE(smv_bool)
2324
IREP_ID_ONE(smv_count)
2425
IREP_ID_ONE(smv_enumeration)

src/smvlang/expr2smv.cpp

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -544,6 +544,41 @@ expr2smvt::resultt expr2smvt::convert_extractbits(const extractbits_exprt &expr)
544544

545545
/*******************************************************************\
546546
547+
Function: expr2smvt::convert_smv_bit_select
548+
549+
Inputs:
550+
551+
Outputs:
552+
553+
Purpose:
554+
555+
\*******************************************************************/
556+
557+
expr2smvt::resultt
558+
expr2smvt::convert_smv_bit_selection(const ternary_exprt &expr)
559+
{
560+
const precedencet precedence = precedencet::INDEX;
561+
auto op_rec = convert_rec(expr.op0());
562+
563+
std::string dest;
564+
565+
if(precedence >= op_rec.p)
566+
dest += '(';
567+
dest += op_rec.s;
568+
if(precedence >= op_rec.p)
569+
dest += ')';
570+
571+
dest += '[';
572+
dest += convert_rec(expr.op1()).s;
573+
dest += ':';
574+
dest += convert_rec(expr.op2()).s;
575+
dest += ']';
576+
577+
return {precedence, std::move(dest)};
578+
}
579+
580+
/*******************************************************************\
581+
547582
Function: expr2smvt::convert_if
548583
549584
Inputs:
@@ -907,6 +942,9 @@ expr2smvt::resultt expr2smvt::convert_rec(const exprt &src)
907942
else if(src.id() == ID_extractbits)
908943
return convert_extractbits(to_extractbits_expr(src));
909944

945+
else if(src.id() == ID_smv_bit_selection)
946+
return convert_smv_bit_selection(to_ternary_expr(src));
947+
910948
else if(src.id() == ID_smv_extend)
911949
return convert_function_application("extend", src);
912950

src/smvlang/expr2smv_class.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -114,6 +114,8 @@ class expr2smvt
114114

115115
resultt convert_extractbits(const extractbits_exprt &);
116116

117+
resultt convert_smv_bit_selection(const ternary_exprt &);
118+
117119
resultt convert_index(const index_exprt &, precedencet);
118120

119121
resultt convert_if(const if_exprt &, precedencet);

src/smvlang/parser.y

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -899,6 +899,7 @@ basic_expr : constant
899899
| basic_expr GTGT_Token basic_expr { binary($$, $1, ID_shr, $3); }
900900
| basic_expr LTLT_Token basic_expr { binary($$, $1, ID_shl, $3); }
901901
| basic_expr '[' basic_expr ']' { binary($$, $1, ID_index, $3); }
902+
| basic_expr '[' basic_expr ':' basic_expr ']' { init($$, ID_smv_bit_selection); mto($$, $1); mto($$, $3); mto($$, $5); }
902903
| basic_expr COLONCOLON_Token basic_expr { binary($$, $1, ID_concatenation, $3); }
903904
| "word1" '(' basic_expr ')' { unary($$, ID_smv_word1, $3); }
904905
| "bool" '(' basic_expr ')' { unary($$, ID_smv_bool, $3); }

src/smvlang/smv_typecheck.cpp

Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1206,6 +1206,62 @@ void smv_typecheckt::typecheck_expr_rec(exprt &expr, modet mode)
12061206
<< "abs expects integer";
12071207
}
12081208
}
1209+
else if(expr.id() == ID_smv_bit_selection) // word[high:low]
1210+
{
1211+
auto &op = to_ternary_expr(expr).op0();
1212+
1213+
typecheck_expr_rec(op, mode);
1214+
1215+
if(op.type().id() != ID_unsignedbv && op.type().id() != ID_signedbv)
1216+
{
1217+
throw errort().with_location(op.source_location())
1218+
<< "bit selection expects word";
1219+
}
1220+
1221+
auto &high = to_ternary_expr(expr).op1();
1222+
1223+
typecheck_expr_rec(high, OTHER);
1224+
1225+
// high must be an integer constant
1226+
if(high.type().id() != ID_range && high.type().id() != ID_natural)
1227+
{
1228+
throw errort().with_location(expr.find_source_location())
1229+
<< "bit-select high must be integer, but got "
1230+
<< to_string(high.type());
1231+
}
1232+
1233+
if(high.id() != ID_constant)
1234+
throw errort().with_location(expr.find_source_location())
1235+
<< "bit-select high must be constant";
1236+
1237+
auto high_int = numeric_cast_v<mp_integer>(to_constant_expr(high));
1238+
1239+
auto &low = to_ternary_expr(expr).op2();
1240+
1241+
typecheck_expr_rec(low, OTHER);
1242+
1243+
// low must be an integer constant
1244+
if(low.type().id() != ID_range && low.type().id() != ID_natural)
1245+
{
1246+
throw errort().with_location(expr.find_source_location())
1247+
<< "bit-select low must be integer, but got " << to_string(low.type());
1248+
}
1249+
1250+
if(low.id() != ID_constant)
1251+
throw errort().with_location(expr.find_source_location())
1252+
<< "bit-select low must be constant";
1253+
1254+
auto low_int = numeric_cast_v<mp_integer>(to_constant_expr(low));
1255+
1256+
if(low_int > high_int)
1257+
throw errort().with_location(expr.find_source_location())
1258+
<< "bit-select high must not be smaller than low";
1259+
1260+
auto width = numeric_cast_v<std::size_t>(high_int - low_int + 1);
1261+
1262+
// always unsigned, even if op is signed
1263+
expr.type() = unsignedbv_typet{width};
1264+
}
12091265
else if(expr.id() == ID_smv_bool)
12101266
{
12111267
auto &op = to_unary_expr(expr).op();
@@ -1626,6 +1682,13 @@ void smv_typecheckt::lower_node(exprt &expr) const
16261682
auto &implies = to_smv_bitimplies_expr(expr);
16271683
expr = bitor_exprt{bitnot_exprt{implies.op0()}, implies.op1()};
16281684
}
1685+
else if(expr.id() == ID_smv_bit_selection)
1686+
{
1687+
// we'll lower to extractbits
1688+
auto &bit_selection = to_ternary_expr(expr);
1689+
expr = extractbits_exprt{
1690+
bit_selection.op0(), bit_selection.op2(), bit_selection.type()};
1691+
}
16291692

16301693
// lower the type
16311694
lower(expr.type());

0 commit comments

Comments
 (0)