Skip to content

Commit ac6d13f

Browse files
committed
Fix fragment of SVA supported by word-level BMC
1 parent 98bae01 commit ac6d13f

File tree

5 files changed

+69
-36
lines changed

5 files changed

+69
-36
lines changed

src/temporal-logic/normalize_property.cpp

Lines changed: 13 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ Author: Daniel Kroening, [email protected]
99
#include "normalize_property.h"
1010

1111
#include <util/arith_tools.h>
12+
#include <util/mathematical_types.h>
1213
#include <util/std_expr.h>
1314

1415
#include <verilog/sva_expr.h>
@@ -75,9 +76,8 @@ exprt normalize_pre_implies(implies_exprt expr)
7576
exprt normalize_pre_sva_overlapped_implication(
7677
sva_overlapped_implication_exprt expr)
7778
{
78-
// Same as regular implication if lhs and rhs are not
79-
// sequences.
80-
if(!is_SVA_sequence(expr.lhs()) && !is_SVA_sequence(expr.rhs()))
79+
// Same as regular implication if the lhs is not a sequence.
80+
if(!is_SVA_sequence(expr.lhs()))
8181
return or_exprt{not_exprt{expr.lhs()}, expr.rhs()};
8282
else
8383
return std::move(expr);
@@ -86,8 +86,8 @@ exprt normalize_pre_sva_overlapped_implication(
8686
exprt normalize_pre_sva_non_overlapped_implication(
8787
sva_non_overlapped_implication_exprt expr)
8888
{
89-
// Same as a->Xb if lhs and rhs are not sequences.
90-
if(!is_SVA_sequence(expr.lhs()) && !is_SVA_sequence(expr.rhs()))
89+
// Same as a->Xb if lhs is not a sequence.
90+
if(!is_SVA_sequence(expr.lhs()))
9191
return or_exprt{not_exprt{expr.lhs()}, X_exprt{expr.rhs()}};
9292
else
9393
return std::move(expr);
@@ -125,13 +125,13 @@ exprt normalize_pre_sva_cycle_delay(sva_cycle_delay_exprt expr)
125125
expr.from().is_constant() &&
126126
numeric_cast_v<mp_integer>(to_constant_expr(expr.from())) == 0)
127127
{
128-
// ##[0:$] φ --> F φ
129-
return F_exprt{expr.op()};
128+
// ##[0:$] φ --> s_eventually φ
129+
return sva_s_eventually_exprt{expr.op()};
130130
}
131131
else
132132
{
133-
// ##[i:$] φ --> ##i F φ
134-
return sva_cycle_delay_exprt{expr.from(), F_exprt{expr.op()}};
133+
// ##[i:$] φ --> always[i:i] s_eventually φ
134+
return sva_ranged_always_exprt{expr.from(), expr.from(), expr.op()};
135135
}
136136
}
137137
else
@@ -176,7 +176,10 @@ exprt normalize_property(exprt expr)
176176
expr = sva_ranged_always_exprt{
177177
nexttime_expr.index(), nexttime_expr.index(), nexttime_expr.op()};
178178
else
179-
expr = X_exprt{nexttime_expr.op()};
179+
{
180+
auto one = from_integer(1, natural_typet{});
181+
expr = sva_ranged_always_exprt{one, one, nexttime_expr.op()};
182+
}
180183
}
181184
else if(expr.id() == ID_sva_s_nexttime)
182185
{

src/temporal-logic/normalize_property.h

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -21,11 +21,11 @@ Author: Daniel Kroening, [email protected]
2121
/// sva_not a --> ¬a
2222
/// a sva_and b --> a ∧ b if a and b are not SVA sequences
2323
/// a sva_or b --> a ∨ b if a and b are not SVA sequences
24-
/// sva_overlapped_implication --> ¬a ∨ b if a and b are not SVA sequences
25-
/// sva_non_overlapped_implication --> ¬a ∨ Xb if a and b are not SVA sequences
26-
/// sva_nexttime φ -->
24+
/// sva_overlapped_implication --> ¬a ∨ b if a is not an SVA sequence
25+
/// sva_non_overlapped_implication --> ¬a ∨ Xb if a is not an SVA sequence
26+
/// sva_nexttime φ --> sva_always[1:1] φ
2727
/// sva_nexttime[i] φ --> sva_always[i:i] φ
28-
/// sva_s_nexttime φ -->
28+
/// sva_s_nexttime φ --> sva_always[1:1] φ
2929
/// sva_s_nexttime[i] φ --> sva_s_always[i:i] φ
3030
/// sva_if --> ? :
3131
/// a sva_disable_iff b --> a ∨ b

src/temporal-logic/temporal_logic.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,7 @@ bool is_SVA_sequence(const exprt &);
4242
/// Returns true iff the given expression is an SVA temporal operator
4343
bool is_SVA_operator(const exprt &);
4444

45-
/// Returns true iff the given expression contains an SVA temporal operator
45+
/// Returns true iff the given expression is an SVA expression
4646
bool is_SVA(const exprt &);
4747

4848
#endif

src/trans-word-level/property.cpp

Lines changed: 45 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -146,31 +146,53 @@ Function: bmc_supports_SVA_property
146146

147147
bool bmc_supports_SVA_property(const exprt &expr)
148148
{
149-
if(!is_temporal_operator(expr))
149+
// Define 'SVA unbounded temporal operators' as one of
150+
// * always (not: ranged_always)
151+
// * s_eventually without range (not: eventually, which is ranged)
152+
// * until, s_until, until_with, s_until_with
153+
154+
// We support
155+
// * formulas that contain no unbounded temporal operator
156+
// * always φ, where φ is a supported property
157+
// * s_eventually φ, where φ contains no unbounded temporal operator
158+
// * s_nexttime/nexttime φ, where φ is a supported property
159+
// * conjunctions and disjunctions of supported SVA properties
160+
161+
auto unbounded_operator = [](const exprt &expr)
150162
{
151-
if(!has_temporal_operator(expr))
152-
return true; // initial state only
153-
else if(
154-
expr.id() == ID_and || expr.id() == ID_or || expr.id() == ID_implies)
155-
{
156-
for(auto &op : expr.operands())
157-
if(!bmc_supports_property(op))
158-
return false;
159-
return true;
160-
}
161-
else
162-
return false;
163+
return expr.id() == ID_sva_always || expr.id() == ID_sva_s_eventually ||
164+
expr.id() == ID_sva_until || expr.id() == ID_sva_s_until ||
165+
expr.id() == ID_sva_until_with || expr.id() == ID_sva_s_until_with;
166+
};
167+
168+
if(!has_subexpr(expr, unbounded_operator))
169+
{
170+
return true;
171+
}
172+
else if(expr.id() == ID_sva_s_eventually)
173+
{
174+
return !has_subexpr(
175+
to_sva_s_eventually_expr(expr).op(), unbounded_operator);
163176
}
164-
else if(expr.id() == ID_sva_cycle_delay)
165-
return !has_temporal_operator(to_sva_cycle_delay_expr(expr).op());
166-
else if(expr.id() == ID_sva_nexttime)
167-
return !has_temporal_operator(to_sva_nexttime_expr(expr).op());
168177
else if(expr.id() == ID_sva_s_nexttime)
169-
return !has_temporal_operator(to_sva_s_nexttime_expr(expr).op());
178+
{
179+
return bmc_supports_SVA_property(to_sva_s_nexttime_expr(expr).op());
180+
}
181+
else if(expr.id() == ID_sva_nexttime)
182+
{
183+
return bmc_supports_SVA_property(to_sva_nexttime_expr(expr).op());
184+
}
170185
else if(expr.id() == ID_sva_always)
186+
{
187+
return bmc_supports_SVA_property(to_sva_always_expr(expr).op());
188+
}
189+
else if(expr.id() == ID_and || expr.id() == ID_or)
190+
{
191+
for(auto &op : expr.operands())
192+
if(!bmc_supports_SVA_property(op))
193+
return false;
171194
return true;
172-
else if(expr.id() == ID_sva_ranged_always)
173-
return true;
195+
}
174196
else
175197
return false;
176198
}
@@ -193,8 +215,10 @@ bool bmc_supports_property(const exprt &expr)
193215
return bmc_supports_LTL_property(expr);
194216
else if(is_CTL(expr))
195217
return bmc_supports_CTL_property(expr);
196-
else
218+
else if(is_SVA(expr))
197219
return bmc_supports_SVA_property(expr);
220+
else
221+
return false; // unknown category
198222
}
199223

200224
/*******************************************************************\

src/verilog/sva_expr.h

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -146,6 +146,12 @@ class sva_s_nexttime_exprt : public binary_predicate_exprt
146146
{
147147
}
148148

149+
// indexed variant
150+
explicit sva_s_nexttime_exprt(exprt index, exprt op)
151+
: binary_predicate_exprt(std::move(index), ID_sva_s_nexttime, std::move(op))
152+
{
153+
}
154+
149155
bool is_indexed() const
150156
{
151157
return index().is_not_nil();

0 commit comments

Comments
 (0)