Skip to content

Commit 680dd8b

Browse files
authored
Merge pull request #1031 from diffblue/sva-sequence-implication-fix
SVA: bugfix for sequence implication operators
2 parents 65c5e52 + 41d0faf commit 680dd8b

File tree

7 files changed

+66
-30
lines changed

7 files changed

+66
-30
lines changed

CHANGELOG

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
* SystemVerilog: assignment patterns with keys for structs
55
* SystemVerilog: unbased unsigned literals '0, '1, 'x, 'z
66
* SystemVerilog: first_match
7+
* SystemVerilog: bugfix for |-> and |=>
78
* Verilog: 'dx, 'dz
89
* SMV: LTL V operator, xnor operator
910
* SMV: word types and operators

regression/verilog/SVA/sequence_first_match2.desc

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,11 @@
11
CORE
22
sequence_first_match2.sv
33
--bound 5
4-
^\[.*\] \(\(##1 1\) or \(##2 1\)\) \|-> main.x == 1: PROVED up to bound 5$
4+
^\[.*\] \(\(##1 1\) or \(##2 1\)\) \|-> main.x == 1: REFUTED$
55
^\[.*\] first_match\(\(##1 1\) or \(##2 1\)\) \|-> main\.x == 1: PROVED up to bound 5$
6-
^\[.*\] \(1 or \(##1 1\)\) \|-> main\.x == 0: PROVED up to bound 5$
6+
^\[.*\] \(1 or \(##1 1\)\) \|-> main\.x == 0: REFUTED$
77
^\[.*\] first_match\(1 or \(##1 1\)\) \|-> main\.x == 0: PROVED up to bound 5$
8-
^EXIT=0$
8+
^EXIT=10$
99
^SIGNAL=0$
1010
--
1111
^warning: ignoring

regression/verilog/SVA/sequence_implication1.desc

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,11 @@
11
CORE
22
sequence_implication1.sv
33
--bound 20
4-
^EXIT=0$
4+
^\[.*\] always \(\(main\.counter == 1 ##1 main\.counter == 2\) \|-> \(##1 main.counter == 0\)\): PROVED up to bound 20$
5+
^\[.*\] always \(\(main\.counter == 1 ##1 main\.counter == 2\) \|=> main\.counter == 0\): PROVED up to bound 20$
6+
^\[.*\] always \(0 \|-> 0\): PROVED up to bound 20$
7+
^\[.*\] \(1 or \(##1 1\)\) \|-> main\.counter == 0: REFUTED$
8+
^EXIT=10$
59
^SIGNAL=0$
610
--
711
^warning: ignoring

regression/verilog/SVA/sequence_implication1.sv

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,4 +15,10 @@ module main(input clk);
1515
// same with non-overlapping implication
1616
assert property (@(posedge clk) counter == 1 ##1 counter == 2 |=> counter == 0);
1717

18+
// if the LHS doesn't match the implication is vacuously true
19+
assert property (0 |-> 0);
20+
21+
// the implication must hold for _all_ matches of the LHS, not just one
22+
initial assert property (1 or ##1 1 |-> counter==0);
23+
1824
endmodule : main

src/temporal-logic/temporal_logic.cpp

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -95,12 +95,11 @@ bool is_LTL_past(const exprt &expr)
9595
bool is_SVA_sequence_operator(const exprt &expr)
9696
{
9797
auto id = expr.id();
98-
// Note that ID_sva_overlapped_followed_by and ID_sva_nonoverlapped_followed_by
98+
// Note that ID_sva_overlapped_followed_by, ID_sva_nonoverlapped_followed_by,
99+
// ID_sva_non_overlapped_implication and ID_sva_overlapped_implication
99100
// are property expressions, not sequence expressions.
100101
// Note that ID_sva_not does not yield a sequence expression.
101-
return id == ID_sva_and || id == ID_sva_or ||
102-
id == ID_sva_overlapped_implication ||
103-
id == ID_sva_non_overlapped_implication || id == ID_sva_cycle_delay ||
102+
return id == ID_sva_and || id == ID_sva_or || id == ID_sva_cycle_delay ||
104103
id == ID_sva_sequence_concatenation ||
105104
id == ID_sva_sequence_intersect || id == ID_sva_sequence_first_match ||
106105
id == ID_sva_sequence_throughout || id == ID_sva_sequence_within ||
@@ -124,6 +123,8 @@ bool is_SVA_operator(const exprt &expr)
124123
id == ID_sva_until_with || id == ID_sva_s_until_with ||
125124
id == ID_sva_eventually || id == ID_sva_s_eventually ||
126125
id == ID_sva_ranged_s_eventually || id == ID_sva_cycle_delay ||
126+
id == ID_sva_overlapped_implication ||
127+
id == ID_sva_non_overlapped_implication ||
127128
id == ID_sva_overlapped_followed_by ||
128129
id == ID_sva_nonoverlapped_followed_by;
129130
}

src/trans-word-level/property.cpp

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -576,6 +576,48 @@ static obligationst property_obligations_rec(
576576
auto equal_expr = equal_exprt{sva_iff_expr.lhs(), sva_iff_expr.rhs()};
577577
return property_obligations_rec(equal_expr, current, no_timeframes);
578578
}
579+
else if(
580+
property_expr.id() == ID_sva_overlapped_implication ||
581+
property_expr.id() == ID_sva_non_overlapped_implication)
582+
{
583+
auto &implication = to_binary_expr(property_expr);
584+
585+
// The LHS is a sequence, the RHS is a property.
586+
// The implication must hold for _all_ matches on the LHS,
587+
// i.e., each pair of LHS match and RHS obligation yields an obligation.
588+
const auto lhs_match_points =
589+
instantiate_sequence(implication.lhs(), current, no_timeframes);
590+
591+
obligationst result;
592+
593+
for(auto &lhs_match_point : lhs_match_points)
594+
{
595+
// The RHS of the non-overlapped implication starts one timeframe later
596+
auto t_rhs = property_expr.id() == ID_sva_non_overlapped_implication
597+
? lhs_match_point.first + 1
598+
: lhs_match_point.first;
599+
600+
// Do we exceed the bound? Make it 'true'
601+
if(t_rhs >= no_timeframes)
602+
{
603+
DATA_INVARIANT(no_timeframes != 0, "must have timeframe");
604+
return obligationst{no_timeframes - 1, true_exprt()};
605+
}
606+
607+
// Get obligations for RHS
608+
auto rhs_obligations_rec =
609+
property_obligations_rec(implication.rhs(), t_rhs, no_timeframes);
610+
611+
for(auto &rhs_obligation : rhs_obligations_rec.map)
612+
{
613+
auto rhs_conjunction = conjunction(rhs_obligation.second);
614+
auto cond = implies_exprt{lhs_match_point.second, rhs_conjunction};
615+
result.add(rhs_obligation.first, cond);
616+
}
617+
}
618+
619+
return result;
620+
}
579621
else if(
580622
property_expr.id() == ID_sva_nonoverlapped_followed_by ||
581623
property_expr.id() == ID_sva_overlapped_followed_by)

src/trans-word-level/sequence.cpp

Lines changed: 4 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -75,23 +75,18 @@ std::vector<std::pair<mp_integer, exprt>> instantiate_sequence(
7575
return match_points;
7676
}
7777
}
78-
else if(
79-
expr.id() == ID_sva_sequence_concatenation ||
80-
expr.id() == ID_sva_overlapped_implication ||
81-
expr.id() == ID_sva_non_overlapped_implication)
78+
else if(expr.id() == ID_sva_sequence_concatenation)
8279
{
8380
auto &implication = to_binary_expr(expr);
8481
std::vector<std::pair<mp_integer, exprt>> result;
8582

8683
// This is the product of the match points on the LHS and RHS
8784
const auto lhs_match_points =
8885
instantiate_sequence(implication.lhs(), t, no_timeframes);
86+
8987
for(auto &lhs_match_point : lhs_match_points)
9088
{
91-
// The RHS of the non-overlapped implication starts one timeframe later
92-
auto t_rhs = expr.id() == ID_sva_non_overlapped_implication
93-
? lhs_match_point.first + 1
94-
: lhs_match_point.first;
89+
auto t_rhs = lhs_match_point.first;
9590

9691
// Do we exceed the bound? Make it 'true'
9792
if(t_rhs >= no_timeframes)
@@ -105,20 +100,7 @@ std::vector<std::pair<mp_integer, exprt>> instantiate_sequence(
105100

106101
for(auto &rhs_match_point : rhs_match_points)
107102
{
108-
exprt cond;
109-
if(expr.id() == ID_sva_sequence_concatenation)
110-
{
111-
cond = and_exprt{lhs_match_point.second, rhs_match_point.second};
112-
}
113-
else if(
114-
expr.id() == ID_sva_overlapped_implication ||
115-
expr.id() == ID_sva_non_overlapped_implication)
116-
{
117-
cond = implies_exprt{lhs_match_point.second, rhs_match_point.second};
118-
}
119-
else
120-
PRECONDITION(false);
121-
103+
auto cond = and_exprt{lhs_match_point.second, rhs_match_point.second};
122104
result.push_back({rhs_match_point.first, cond});
123105
}
124106
}

0 commit comments

Comments
 (0)