Skip to content

Commit cfe36b1

Browse files
committed
SVA: replace sva_sequence_concatenation_exprt
This replaces the sva_sequence_concatenation_exprt by multi-operand variants of sva_cycle_delay_exprt, sva_cycle_delay_plus_exprt and sva_cycle_delay_star_exprt. This simplifies the implementation of the SystemVerilog concatenation rules.
1 parent f9a5c68 commit cfe36b1

File tree

12 files changed

+166
-288
lines changed

12 files changed

+166
-288
lines changed

src/hw_cbmc_irep_ids.h

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -60,7 +60,6 @@ IREP_ID_ONE(sva_cycle_delay)
6060
IREP_ID_ONE(sva_cycle_delay_star)
6161
IREP_ID_ONE(sva_cycle_delay_plus)
6262
IREP_ID_ONE(sva_disable_iff)
63-
IREP_ID_ONE(sva_sequence_concatenation)
6463
IREP_ID_ONE(sva_sequence_first_match)
6564
IREP_ID_ONE(sva_sequence_goto_repetition)
6665
IREP_ID_ONE(sva_sequence_intersect)

src/temporal-logic/ltl_sva_to_string.cpp

Lines changed: 42 additions & 48 deletions
Original file line numberDiff line numberDiff line change
@@ -327,22 +327,49 @@ ltl_sva_to_stringt::rec(const exprt &expr, modet mode)
327327
PRECONDITION(mode == PROPERTY || mode == SVA_SEQUENCE);
328328
return rec(to_sva_boolean_expr(expr).op(), BOOLEAN);
329329
}
330-
else if(expr.id() == ID_sva_sequence_concatenation)
330+
else if(expr.id() == ID_sva_cycle_delay)
331331
{
332332
PRECONDITION(mode == SVA_SEQUENCE);
333-
// SVA sequence concatenation is overlapping, whereas
334-
// the ; operator is nonoverlapping. We special-case
335-
// the following for better readability:
336-
// f ##0 g --> f : g
337-
// f ##1 g --> f ; g
338-
// f ##n g --> f ; 1[*n-1] ; b
339-
auto &concatenation = to_sva_sequence_concatenation_expr(expr);
340-
if(concatenation.rhs().id() == ID_sva_cycle_delay)
333+
auto &delay = to_sva_cycle_delay_expr(expr);
334+
335+
if(delay.lhs().is_nil())
341336
{
342-
auto &delay = to_sva_cycle_delay_expr(concatenation.rhs());
337+
auto new_expr = unary_exprt{expr.id(), delay.rhs()};
343338

344-
auto new_expr = concatenation;
345-
new_expr.rhs() = delay.op();
339+
if(delay.is_range()) // ##[from:to] rhs
340+
{
341+
auto from = numeric_cast_v<mp_integer>(delay.from());
342+
343+
if(delay.is_unbounded()) // ##[n:$] rhs
344+
{
345+
return prefix(
346+
"1[*" + integer2string(from) + "..] ; ", new_expr, mode);
347+
}
348+
else
349+
{
350+
auto to = numeric_cast_v<mp_integer>(delay.to());
351+
PRECONDITION(to >= 0);
352+
return prefix(
353+
"1[*" + integer2string(from) + ".." + integer2string(to) + "] ; ",
354+
new_expr,
355+
mode);
356+
}
357+
}
358+
else // ##n rhs
359+
{
360+
auto i = numeric_cast_v<mp_integer>(delay.from());
361+
PRECONDITION(i >= 0);
362+
return prefix("1[*" + integer2string(i) + "] ; ", new_expr, mode);
363+
}
364+
}
365+
else // lhs is not nil
366+
{
367+
// We special-case the following for better readability:
368+
// f ##0 g --> f : g
369+
// f ##1 g --> f ; g
370+
// f ##n g --> f ; 1[*n-1] ; b
371+
auto new_expr =
372+
binary_exprt{delay.lhs(), delay.id(), delay.rhs(), delay.type()};
346373

347374
if(delay.is_range())
348375
{
@@ -354,12 +381,12 @@ ltl_sva_to_stringt::rec(const exprt &expr, modet mode)
354381
throw ebmc_errort{}
355382
<< "cannot convert 0.. ranged sequence concatenation to Buechi";
356383
}
357-
else if(delay.is_unbounded())
384+
else if(delay.is_unbounded()) // f ##[n:$] g
358385
{
359386
return infix(
360387
" ; 1[*" + integer2string(from - 1) + "..] ; ", new_expr, mode);
361388
}
362-
else
389+
else // f ##[from:to] g
363390
{
364391
auto to = numeric_cast_v<mp_integer>(delay.to());
365392
PRECONDITION(to >= 0);
@@ -370,7 +397,7 @@ ltl_sva_to_stringt::rec(const exprt &expr, modet mode)
370397
mode);
371398
}
372399
}
373-
else
400+
else // f ##n g
374401
{
375402
auto n = numeric_cast_v<mp_integer>(delay.from());
376403
PRECONDITION(n >= 0);
@@ -385,39 +412,6 @@ ltl_sva_to_stringt::rec(const exprt &expr, modet mode)
385412
}
386413
}
387414
}
388-
else
389-
return infix(":", expr, mode);
390-
}
391-
else if(expr.id() == ID_sva_cycle_delay)
392-
{
393-
PRECONDITION(mode == SVA_SEQUENCE);
394-
auto &delay = to_sva_cycle_delay_expr(expr);
395-
unary_exprt new_expr{expr.id(), delay.op()};
396-
397-
if(delay.is_range())
398-
{
399-
auto from = numeric_cast_v<mp_integer>(delay.from());
400-
401-
if(delay.is_unbounded())
402-
{
403-
return prefix("1[*" + integer2string(from) + "..] ; ", new_expr, mode);
404-
}
405-
else
406-
{
407-
auto to = numeric_cast_v<mp_integer>(delay.to());
408-
PRECONDITION(to >= 0);
409-
return prefix(
410-
"1[*" + integer2string(from) + ".." + integer2string(to) + "] ; ",
411-
new_expr,
412-
mode);
413-
}
414-
}
415-
else // singleton
416-
{
417-
auto i = numeric_cast_v<mp_integer>(delay.from());
418-
PRECONDITION(i >= 0);
419-
return prefix("1[*" + integer2string(i) + "] ; ", new_expr, mode);
420-
}
421415
}
422416
else if(expr.id() == ID_sva_cycle_delay_star) // ##[*] something
423417
{

src/temporal-logic/sva_sequence_match.cpp

Lines changed: 41 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -47,7 +47,8 @@ overlapping_concat(sva_sequence_matcht a, sva_sequence_matcht b)
4747
PRECONDITION(!b.empty_match());
4848
auto a_last = a.cond_vector.back();
4949
a.cond_vector.pop_back();
50-
b.cond_vector.front() = conjunction({a_last, b.cond_vector.front()});
50+
if(!a_last.is_true())
51+
b.cond_vector.front() = conjunction({a_last, b.cond_vector.front()});
5152
return concat(std::move(a), b);
5253
}
5354

@@ -58,26 +59,6 @@ std::vector<sva_sequence_matcht> LTL_sequence_matches(const exprt &sequence)
5859
// atomic proposition
5960
return {sva_sequence_matcht{to_sva_boolean_expr(sequence).op()}};
6061
}
61-
else if(sequence.id() == ID_sva_sequence_concatenation)
62-
{
63-
auto &concatenation = to_sva_sequence_concatenation_expr(sequence);
64-
auto matches_lhs = LTL_sequence_matches(concatenation.lhs());
65-
auto matches_rhs = LTL_sequence_matches(concatenation.rhs());
66-
67-
std::vector<sva_sequence_matcht> result;
68-
69-
// cross product
70-
for(auto &match_lhs : matches_lhs)
71-
for(auto &match_rhs : matches_rhs)
72-
{
73-
// Sequence concatenation is overlapping
74-
auto new_match = overlapping_concat(match_lhs, match_rhs);
75-
CHECK_RETURN(
76-
new_match.length() == match_lhs.length() + match_rhs.length() - 1);
77-
result.push_back(std::move(new_match));
78-
}
79-
return result;
80-
}
8162
else if(sequence.id() == ID_sva_sequence_repetition_star) // [*n], [*n:m]
8263
{
8364
auto &repetition = to_sva_sequence_repetition_star_expr(sequence);
@@ -119,41 +100,61 @@ std::vector<sva_sequence_matcht> LTL_sequence_matches(const exprt &sequence)
119100
else if(sequence.id() == ID_sva_cycle_delay)
120101
{
121102
auto &delay = to_sva_cycle_delay_expr(sequence);
122-
auto matches = LTL_sequence_matches(delay.op());
123-
auto from_int = numeric_cast_v<mp_integer>(delay.from());
124103

125-
if(!delay.is_range())
104+
// These have an optional LHS and a RHS.
105+
std::vector<sva_sequence_matcht> lhs_matches;
106+
107+
if(delay.lhs().is_nil())
126108
{
127-
// delay as instructed
128-
auto delay_sequence = sva_sequence_matcht::true_match(from_int);
109+
// If the LHS is not given, it's equivalent to 'true'.
110+
lhs_matches = {sva_sequence_matcht::true_match(1)};
111+
}
112+
else
113+
{
114+
lhs_matches = LTL_sequence_matches(delay.lhs());
115+
}
129116

130-
for(auto &match : matches)
131-
match = concat(delay_sequence, match);
117+
// The delay in between lhs and rhs
118+
std::vector<sva_sequence_matcht> delay_matches;
119+
120+
auto from_int = numeric_cast_v<mp_integer>(delay.from());
132121

133-
return matches;
122+
if(!delay.is_range()) // f ##n g
123+
{
124+
delay_matches = {sva_sequence_matcht::true_match(from_int)};
134125
}
135-
else if(delay.is_unbounded())
126+
else if(delay.is_unbounded()) // f ##[from:$] g
136127
{
137128
throw sva_sequence_match_unsupportedt{sequence}; // can't encode
138129
}
139-
else
130+
else // f ##[from:to] g
140131
{
141132
auto to_int = numeric_cast_v<mp_integer>(delay.to());
142-
std::vector<sva_sequence_matcht> new_matches;
143133

144134
for(mp_integer i = from_int; i <= to_int; ++i)
145-
{
146-
// delay as instructed
147-
auto delay_sequence = sva_sequence_matcht::true_match(i);
135+
delay_matches.push_back(sva_sequence_matcht::true_match(i));
136+
}
137+
138+
// now do RHS
139+
auto rhs_matches = LTL_sequence_matches(delay.rhs());
140+
141+
// cross product lhs x delay x rhs
142+
std::vector<sva_sequence_matcht> result;
148143

149-
for(const auto &match : matches)
144+
for(auto &lhs_match : lhs_matches)
145+
for(auto &delay_match : delay_matches)
146+
for(auto &rhs_match : rhs_matches)
150147
{
151-
new_matches.push_back(concat(delay_sequence, match));
148+
// Sequence concatenation is overlapping
149+
auto new_match =
150+
overlapping_concat(lhs_match, concat(delay_match, rhs_match));
151+
CHECK_RETURN(
152+
new_match.length() ==
153+
lhs_match.length() + delay_match.length() + rhs_match.length() - 1);
154+
result.push_back(std::move(new_match));
152155
}
153-
}
154156

155-
return new_matches;
156-
}
157+
return result;
157158
}
158159
else if(sequence.id() == ID_sva_and)
159160
{

src/temporal-logic/temporal_logic.cpp

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -107,7 +107,6 @@ bool is_SVA_sequence_operator(const exprt &expr)
107107
// Note that ID_sva_not does not yield a sequence expression.
108108
return id == ID_sva_and || id == ID_sva_or || id == ID_sva_cycle_delay ||
109109
id == ID_sva_cycle_delay_plus || id == ID_sva_cycle_delay_star ||
110-
id == ID_sva_sequence_concatenation ||
111110
id == ID_sva_sequence_intersect || id == ID_sva_sequence_first_match ||
112111
id == ID_sva_sequence_throughout || id == ID_sva_sequence_within ||
113112
id == ID_sva_sequence_goto_repetition ||

0 commit comments

Comments
 (0)