Skip to content

Commit 03dc402

Browse files
authored
Merge pull request #762 from diffblue/trivial_sva
SVA: move rewrites for state-formula SVA into separate file
2 parents c598ef7 + 0a8fc6a commit 03dc402

File tree

5 files changed

+144
-108
lines changed

5 files changed

+144
-108
lines changed

src/temporal-logic/Makefile

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
SRC = nnf.cpp \
22
normalize_property.cpp \
33
temporal_logic.cpp \
4+
trivial_sva.cpp \
45
#empty line
56

67
include ../config.inc

src/temporal-logic/normalize_property.cpp

Lines changed: 17 additions & 95 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ Author: Daniel Kroening, [email protected]
1616

1717
#include "temporal_expr.h"
1818
#include "temporal_logic.h"
19+
#include "trivial_sva.h"
1920

2021
exprt normalize_pre_not(not_exprt expr)
2122
{
@@ -73,16 +74,6 @@ exprt normalize_pre_implies(implies_exprt expr)
7374
return or_exprt{not_exprt{expr.lhs()}, expr.rhs()};
7475
}
7576

76-
exprt normalize_pre_sva_overlapped_implication(
77-
sva_overlapped_implication_exprt expr)
78-
{
79-
// Same as regular implication if lhs is not a sequence.
80-
if(!is_SVA_sequence(expr.lhs()))
81-
return or_exprt{not_exprt{expr.lhs()}, expr.rhs()};
82-
else
83-
return std::move(expr);
84-
}
85-
8677
exprt normalize_pre_sva_non_overlapped_implication(
8778
sva_non_overlapped_implication_exprt expr)
8879
{
@@ -97,30 +88,6 @@ exprt normalize_pre_sva_non_overlapped_implication(
9788
return std::move(expr);
9889
}
9990

100-
exprt normalize_pre_sva_not(sva_not_exprt expr)
101-
{
102-
// Same as regular 'not'. These do not apply to sequences.
103-
return normalize_pre_not(not_exprt{expr.op()});
104-
}
105-
106-
exprt normalize_pre_sva_and(sva_and_exprt expr)
107-
{
108-
// Same as a ∧ b if lhs and rhs are not sequences.
109-
if(!is_SVA_sequence(expr.lhs()) && !is_SVA_sequence(expr.rhs()))
110-
return and_exprt{expr.lhs(), expr.rhs()};
111-
else
112-
return std::move(expr);
113-
}
114-
115-
exprt normalize_pre_sva_or(sva_or_exprt expr)
116-
{
117-
// Same as a ∧ b if lhs or rhs are not sequences.
118-
if(!is_SVA_sequence(expr.lhs()) && !is_SVA_sequence(expr.rhs()))
119-
return or_exprt{expr.lhs(), expr.rhs()};
120-
else
121-
return std::move(expr);
122-
}
123-
12491
exprt normalize_pre_sva_cycle_delay(sva_cycle_delay_exprt expr)
12592
{
12693
if(expr.is_unbounded())
@@ -143,37 +110,16 @@ exprt normalize_pre_sva_cycle_delay(sva_cycle_delay_exprt expr)
143110
return std::move(expr);
144111
}
145112

146-
exprt normalize_property(exprt expr)
113+
exprt normalize_property_rec(exprt expr)
147114
{
148115
// pre-traversal
149116
if(expr.id() == ID_not)
150117
expr = normalize_pre_not(to_not_expr(expr));
151118
else if(expr.id() == ID_implies)
152119
expr = normalize_pre_implies(to_implies_expr(expr));
153-
else if(expr.id() == ID_sva_cover)
154-
expr = G_exprt{not_exprt{to_sva_cover_expr(expr).op()}};
155-
else if(expr.id() == ID_sva_overlapped_implication)
156-
expr = normalize_pre_sva_overlapped_implication(
157-
to_sva_overlapped_implication_expr(expr));
158120
else if(expr.id() == ID_sva_non_overlapped_implication)
159121
expr = normalize_pre_sva_non_overlapped_implication(
160122
to_sva_non_overlapped_implication_expr(expr));
161-
else if(expr.id() == ID_sva_iff)
162-
{
163-
expr =
164-
equal_exprt{to_sva_iff_expr(expr).lhs(), to_sva_iff_expr(expr).rhs()};
165-
}
166-
else if(expr.id() == ID_sva_implies)
167-
{
168-
expr = implies_exprt{
169-
to_sva_implies_expr(expr).lhs(), to_sva_implies_expr(expr).rhs()};
170-
}
171-
else if(expr.id() == ID_sva_and)
172-
expr = normalize_pre_sva_and(to_sva_and_expr(expr));
173-
else if(expr.id() == ID_sva_not)
174-
expr = normalize_pre_sva_not(to_sva_not_expr(expr));
175-
else if(expr.id() == ID_sva_or)
176-
expr = normalize_pre_sva_or(to_sva_or_expr(expr));
177123
else if(expr.id() == ID_sva_nexttime)
178124
{
179125
auto one = natural_typet{}.one_expr();
@@ -209,40 +155,6 @@ exprt normalize_property(exprt expr)
209155
{
210156
expr = sva_s_eventually_exprt{to_sva_cycle_delay_star_expr(expr).op()};
211157
}
212-
else if(expr.id() == ID_sva_sequence_concatenation)
213-
{
214-
auto &sequence_concatenation = to_sva_sequence_concatenation_expr(expr);
215-
if(!is_SVA_sequence(sequence_concatenation.lhs()))
216-
{
217-
// a ##0 b --> a && b if a is not a sequence
218-
expr =
219-
and_exprt{sequence_concatenation.lhs(), sequence_concatenation.rhs()};
220-
}
221-
}
222-
else if(expr.id() == ID_sva_if)
223-
{
224-
auto &sva_if_expr = to_sva_if_expr(expr);
225-
auto false_case = sva_if_expr.false_case().is_nil()
226-
? true_exprt{}
227-
: sva_if_expr.false_case();
228-
expr = if_exprt{sva_if_expr.cond(), sva_if_expr.true_case(), false_case};
229-
}
230-
else if(expr.id() == ID_sva_disable_iff)
231-
{
232-
auto &disable_iff_expr = to_sva_disable_iff_expr(expr);
233-
expr = or_exprt{disable_iff_expr.lhs(), disable_iff_expr.rhs()};
234-
}
235-
else if(expr.id() == ID_sva_accept_on || expr.id() == ID_sva_sync_accept_on)
236-
{
237-
auto &sva_abort_expr = to_sva_abort_expr(expr);
238-
expr = or_exprt{sva_abort_expr.condition(), sva_abort_expr.property()};
239-
}
240-
else if(expr.id() == ID_sva_reject_on || expr.id() == ID_sva_sync_reject_on)
241-
{
242-
auto &sva_abort_expr = to_sva_abort_expr(expr);
243-
expr = and_exprt{
244-
not_exprt{sva_abort_expr.condition()}, sva_abort_expr.property()};
245-
}
246158
else if(expr.id() == ID_sva_strong)
247159
{
248160
expr = to_sva_strong_expr(expr).op();
@@ -251,16 +163,26 @@ exprt normalize_property(exprt expr)
251163
{
252164
expr = to_sva_weak_expr(expr).op();
253165
}
254-
else if(expr.id() == ID_sva_case)
255-
{
256-
expr = to_sva_case_expr(expr).lowering();
257-
}
258166

259167
// normalize the operands
260168
for(auto &op : expr.operands())
261-
op = normalize_property(op);
169+
op = normalize_property_rec(op); // recursive call
262170

263171
// post-traversal
264172

265173
return expr;
266174
}
175+
176+
exprt normalize_property(exprt expr)
177+
{
178+
// top-level only
179+
if(expr.id() == ID_sva_cover)
180+
expr = G_exprt{not_exprt{to_sva_cover_expr(expr).op()}};
181+
182+
expr = trivial_sva(expr);
183+
184+
// now do recursion
185+
expr = normalize_property_rec(expr);
186+
187+
return expr;
188+
}

src/temporal-logic/normalize_property.h

Lines changed: 0 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -21,30 +21,17 @@ Author: Daniel Kroening, [email protected]
2121
/// (a -> b) --> ¬a ∨ b
2222
///
2323
/// -----SVA-----
24-
/// a sva_iff b --> a <-> b
25-
/// a sva_implies b --> a -> b
26-
/// sva_not a --> ¬a
27-
/// a sva_and b --> a ∧ b if a and b are not SVA sequences
28-
/// a sva_or b --> a ∨ b if a and b are not SVA sequences
29-
/// sva_overlapped_implication --> ¬a ∨ b if a is not an SVA sequence
3024
/// sva_non_overlapped_implication --> ¬a ∨ always[1:1] b if a is not an SVA sequence
3125
/// sva_nexttime φ --> sva_always[1:1] φ
3226
/// sva_nexttime[i] φ --> sva_always[i:i] φ
3327
/// sva_s_nexttime φ --> sva_always[1:1] φ
3428
/// sva_s_nexttime[i] φ --> sva_s_always[i:i] φ
35-
/// sva_if --> ? :
3629
/// ##[0:$] φ --> s_eventually φ
3730
/// ##[i:$] φ --> s_nexttime[i] s_eventually φ
3831
/// ##[*] φ --> s_eventually φ
3932
/// ##[+] φ --> always[1:1] s_eventually φ
4033
/// strong(φ) --> φ
4134
/// weak(φ) --> φ
42-
/// sva_case --> ? :
43-
/// a sva_disable_iff b --> a ∨ b
44-
/// a sva_accept_on b --> a ∨ b
45-
/// a sva_reject_on b --> ¬a ∧ b
46-
/// a sva_sync_accept_on b --> a ∨ b
47-
/// a sva_sync_reject_on b --> ¬a ∧ b
4835
/// ¬ sva_s_eventually φ --> sva_always ¬φ
4936
/// ¬ sva_always φ --> sva_s_eventually ¬φ
5037
///

src/temporal-logic/trivial_sva.cpp

Lines changed: 94 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,94 @@
1+
/*******************************************************************\
2+
3+
Module: Trivial SVA
4+
5+
Author: Daniel Kroening, [email protected]
6+
7+
\*******************************************************************/
8+
9+
#include "trivial_sva.h"
10+
11+
#include <verilog/sva_expr.h>
12+
13+
#include "temporal_logic.h"
14+
15+
exprt trivial_sva(exprt expr)
16+
{
17+
// pre-traversal
18+
if(expr.id() == ID_sva_overlapped_implication)
19+
{
20+
// Same as regular implication if lhs and rhs are not sequences.
21+
auto &sva_implication = to_sva_overlapped_implication_expr(expr);
22+
if(
23+
!is_SVA_sequence(sva_implication.lhs()) &&
24+
!is_SVA_sequence(sva_implication.rhs()))
25+
{
26+
expr = implies_exprt{sva_implication.lhs(), sva_implication.rhs()};
27+
}
28+
}
29+
else if(expr.id() == ID_sva_iff)
30+
{
31+
auto &sva_iff = to_sva_iff_expr(expr);
32+
expr = equal_exprt{sva_iff.lhs(), sva_iff.rhs()};
33+
}
34+
else if(expr.id() == ID_sva_implies)
35+
{
36+
auto &sva_implies = to_sva_implies_expr(expr);
37+
expr = implies_exprt{sva_implies.lhs(), sva_implies.rhs()};
38+
}
39+
else if(expr.id() == ID_sva_and)
40+
{
41+
// Same as a ∧ b if lhs and rhs are not sequences.
42+
auto &sva_and = to_sva_and_expr(expr);
43+
if(!is_SVA_sequence(sva_and.lhs()) && !is_SVA_sequence(sva_and.rhs()))
44+
expr = and_exprt{sva_and.lhs(), sva_and.rhs()};
45+
}
46+
else if(expr.id() == ID_sva_or)
47+
{
48+
// Same as a ∧ b if lhs or rhs are not sequences.
49+
auto &sva_or = to_sva_or_expr(expr);
50+
if(!is_SVA_sequence(sva_or.lhs()) && !is_SVA_sequence(sva_or.rhs()))
51+
expr = or_exprt{sva_or.lhs(), sva_or.rhs()};
52+
}
53+
else if(expr.id() == ID_sva_not)
54+
{
55+
// Same as regular 'not'. These do not apply to sequences.
56+
expr = not_exprt{to_sva_not_expr(expr).op()};
57+
}
58+
else if(expr.id() == ID_sva_if)
59+
{
60+
auto &sva_if_expr = to_sva_if_expr(expr);
61+
auto false_case = sva_if_expr.false_case().is_nil()
62+
? true_exprt{}
63+
: sva_if_expr.false_case();
64+
expr = if_exprt{sva_if_expr.cond(), sva_if_expr.true_case(), false_case};
65+
}
66+
else if(expr.id() == ID_sva_disable_iff)
67+
{
68+
auto &disable_iff_expr = to_sva_disable_iff_expr(expr);
69+
expr = or_exprt{disable_iff_expr.lhs(), disable_iff_expr.rhs()};
70+
}
71+
else if(expr.id() == ID_sva_accept_on || expr.id() == ID_sva_sync_accept_on)
72+
{
73+
auto &sva_abort_expr = to_sva_abort_expr(expr);
74+
expr = or_exprt{sva_abort_expr.condition(), sva_abort_expr.property()};
75+
}
76+
else if(expr.id() == ID_sva_reject_on || expr.id() == ID_sva_sync_reject_on)
77+
{
78+
auto &sva_abort_expr = to_sva_abort_expr(expr);
79+
expr = and_exprt{
80+
not_exprt{sva_abort_expr.condition()}, sva_abort_expr.property()};
81+
}
82+
else if(expr.id() == ID_sva_case)
83+
{
84+
expr = to_sva_case_expr(expr).lowering();
85+
}
86+
87+
// rewrite the operands, recursively
88+
for(auto &op : expr.operands())
89+
op = trivial_sva(op);
90+
91+
// post-traversal
92+
93+
return expr;
94+
}

src/temporal-logic/trivial_sva.h

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
/*******************************************************************\
2+
3+
Module: Trivial SVA
4+
5+
Author: Daniel Kroening, [email protected]
6+
7+
\*******************************************************************/
8+
9+
#ifndef CPROVER_TEMPORAL_LOGIC_TRIVIAL_SVA_H
10+
#define CPROVER_TEMPORAL_LOGIC_TRIVIAL_SVA_H
11+
12+
#include <util/expr.h>
13+
14+
/// This applies the following rewrites, removing SVA operators
15+
/// that trivial in the sense that they are state predicates only.
16+
///
17+
/// a sva_iff b --> a <-> b
18+
/// a sva_implies b --> a -> b
19+
/// sva_not a --> ¬a
20+
/// a sva_and b --> a ∧ b if a and b are not sequences
21+
/// a sva_or b --> a ∨ b if a and b are not sequences
22+
/// sva_overlapped_implication --> a -> b if a and b are not sequences
23+
/// sva_if --> ? :
24+
/// sva_case --> ? :
25+
/// a sva_disable_iff b --> a ∨ b
26+
/// a sva_accept_on b --> a ∨ b
27+
/// a sva_reject_on b --> ¬a ∧ b
28+
/// a sva_sync_accept_on b --> a ∨ b
29+
/// a sva_sync_reject_on b --> ¬a ∧ b
30+
exprt trivial_sva(exprt);
31+
32+
#endif

0 commit comments

Comments
 (0)