Skip to content

Commit 90eb3c7

Browse files
authored
Merge pull request #757 from diffblue/followed-by1-fix
SVA: implement `#-#` and `#=#`
2 parents 5b7e801 + a3cb219 commit 90eb3c7

File tree

6 files changed

+119
-16
lines changed

6 files changed

+119
-16
lines changed

regression/verilog/SVA/sequence_followed_by1.desc renamed to regression/verilog/SVA/followed-by1.desc

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,9 @@
11
CORE
2-
sequence_followed_by1.sv
2+
followed-by1.sv
33
--bound 20 --numbered-trace
4-
^\[main\.p0\] main\.x == 0 #=# \(main\.x == 1 #=# main\.x == 2\): FAILURE: property not supported by BMC engine$
5-
^\[main\.p1\] main\.x == 0 #-# \(\(##1 main\.x == 1\) #-# \(##1 main\.x == 2\)\): FAILURE: property not supported by BMC engine$
6-
^EXIT=10$
4+
^\[main\.p0\] main\.x == 0 #=# \(main\.x == 1 #=# main\.x == 2\): PROVED up to bound 20$
5+
^\[main\.p1\] main\.x == 0 #-# \(\(##1 main\.x == 1\) #-# \(##1 main\.x == 2\)\): PROVED up to bound 20$
6+
^EXIT=0$
77
^SIGNAL=0$
88
--
99
^warning: ignoring

regression/verilog/SVA/followed-by2.desc

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,9 @@
11
CORE
22
followed-by2.sv
33
--bound 20
4-
^\[main\.p0\] always \(\(main\.a #-# main\.b\) iff \(not \(main\.a |-> \(not main\.b\)\)\)\): FAILURE: property not supported by BMC engine$
5-
^\[main\.p1\] always \(\(main\.a #=# main\.b\) iff \(not \(main\.a |=> \(not main\.b\)\)\)\): FAILURE: property not supported by BMC engine$
6-
^EXIT=10$
4+
^\[main\.p0\] always \(\(main\.a #-# main\.b\) iff \(not \(main\.a |-> \(not main\.b\)\)\)\): PROVED up to bound 20$
5+
^\[main\.p1\] always \(\(main\.a #=# main\.b\) iff \(not \(main\.a |=> \(not main\.b\)\)\)\): PROVED up to bound 20$
6+
^EXIT=0$
77
^SIGNAL=0$
88
--
99
^warning: ignoring

src/temporal-logic/nnf.cpp

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -73,6 +73,13 @@ std::optional<exprt> negate_property_node(const exprt &expr)
7373
// not always p --> s_eventually not p
7474
return sva_s_eventually_exprt{not_exprt{to_sva_always_expr(expr).op()}};
7575
}
76+
else if(expr.id() == ID_sva_ranged_always)
77+
{
78+
// not always [x:y] p --> s_eventually [x:y] not p
79+
auto &always = to_sva_ranged_always_expr(expr);
80+
return sva_ranged_s_eventually_exprt{
81+
always.lower(), always.upper(), not_exprt{always.op()}};
82+
}
7683
else if(expr.id() == ID_sva_s_eventually)
7784
{
7885
// not s_eventually p --> always not p
@@ -113,6 +120,22 @@ std::optional<exprt> negate_property_node(const exprt &expr)
113120
auto strong_R = strong_R_exprt{s_until_with.rhs(), s_until_with.lhs()};
114121
return weak_U_exprt{not_exprt{strong_R.lhs()}, not_exprt{strong_R.rhs()}};
115122
}
123+
else if(expr.id() == ID_sva_overlapped_followed_by)
124+
{
125+
// 1800 2017 16.12.9
126+
// !(a #-# b) ---> a |-> !b
127+
auto &followed_by = to_sva_followed_by_expr(expr);
128+
auto not_b = not_exprt{followed_by.property()};
129+
return sva_overlapped_implication_exprt{followed_by.lhs(), not_b};
130+
}
131+
else if(expr.id() == ID_sva_nonoverlapped_followed_by)
132+
{
133+
// 1800 2017 16.12.9
134+
// !(a #=# b) ---> a |=> !b
135+
auto &followed_by = to_sva_followed_by_expr(expr);
136+
auto not_b = not_exprt{followed_by.property()};
137+
return sva_non_overlapped_implication_exprt{followed_by.lhs(), not_b};
138+
}
116139
else
117140
return {};
118141
}

src/trans-word-level/property.cpp

Lines changed: 45 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@ Author: Daniel Kroening, [email protected]
2424

2525
#include "instantiate_word_level.h"
2626
#include "obligations.h"
27+
#include "sequence.h"
2728

2829
#include <cstdlib>
2930

@@ -109,14 +110,6 @@ Function: bmc_supports_SVA_property
109110

110111
bool bmc_supports_SVA_property(const exprt &expr)
111112
{
112-
// sva_nonoverlapped_followed_by is not supported yet
113-
if(has_subexpr(expr, ID_sva_nonoverlapped_followed_by))
114-
return false;
115-
116-
// sva_overlapped_followed_by is not supported yet
117-
if(has_subexpr(expr, ID_sva_overlapped_followed_by))
118-
return false;
119-
120113
return true;
121114
}
122115

@@ -552,6 +545,50 @@ static obligationst property_obligations_rec(
552545
auto equal_expr = equal_exprt{sva_iff_expr.lhs(), sva_iff_expr.rhs()};
553546
return property_obligations_rec(equal_expr, current, no_timeframes);
554547
}
548+
else if(
549+
property_expr.id() == ID_sva_nonoverlapped_followed_by ||
550+
property_expr.id() == ID_sva_overlapped_followed_by)
551+
{
552+
// The LHS is a sequence, the RHS is a property expression,
553+
// the result is a property expression.
554+
auto &followed_by = to_sva_followed_by_expr(property_expr);
555+
556+
// get match points for LHS sequence
557+
auto match_points =
558+
instantiate_sequence(followed_by.sequence(), current, no_timeframes);
559+
560+
exprt::operandst disjuncts;
561+
mp_integer t = current;
562+
563+
for(auto &match_point : match_points)
564+
{
565+
mp_integer property_start = match_point.first;
566+
567+
// #=# advances the clock by one from the sequence match point
568+
if(property_expr.id() == ID_sva_nonoverlapped_followed_by)
569+
property_start += 1;
570+
571+
// at the end?
572+
if(property_start >= no_timeframes)
573+
{
574+
// relies on NNF
575+
t = std::max(t, no_timeframes - 1);
576+
disjuncts.push_back(match_point.second);
577+
}
578+
else
579+
{
580+
auto obligations_rec =
581+
property_obligations_rec(
582+
followed_by.property(), property_start, no_timeframes)
583+
.conjunction();
584+
585+
disjuncts.push_back(
586+
and_exprt{match_point.second, obligations_rec.second});
587+
t = std::max(t, obligations_rec.first);
588+
}
589+
}
590+
return obligationst{t, disjunction(disjuncts)};
591+
}
555592
else
556593
{
557594
return obligationst{

src/verilog/sva_expr.h

Lines changed: 44 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -349,7 +349,7 @@ class sva_ranged_s_eventually_exprt : public sva_ranged_predicate_exprt
349349
public:
350350
explicit sva_ranged_s_eventually_exprt(exprt lower, exprt upper, exprt op)
351351
: sva_ranged_predicate_exprt(
352-
ID_sva_s_eventually,
352+
ID_sva_ranged_s_eventually,
353353
std::move(lower),
354354
std::move(upper),
355355
std::move(op))
@@ -793,6 +793,49 @@ static inline sva_or_exprt &to_sva_or_expr(exprt &expr)
793793
return static_cast<sva_or_exprt &>(expr);
794794
}
795795

796+
class sva_followed_by_exprt : public binary_predicate_exprt
797+
{
798+
public:
799+
const exprt &sequence() const
800+
{
801+
return op0();
802+
}
803+
804+
exprt &sequence()
805+
{
806+
return op0();
807+
}
808+
809+
const exprt &property() const
810+
{
811+
return op1();
812+
}
813+
814+
exprt &property()
815+
{
816+
return op1();
817+
}
818+
};
819+
820+
static inline const sva_followed_by_exprt &
821+
to_sva_followed_by_expr(const exprt &expr)
822+
{
823+
PRECONDITION(
824+
expr.id() == ID_sva_overlapped_followed_by ||
825+
expr.id() == ID_sva_nonoverlapped_followed_by);
826+
sva_followed_by_exprt::check(expr, validation_modet::INVARIANT);
827+
return static_cast<const sva_followed_by_exprt &>(expr);
828+
}
829+
830+
static inline sva_followed_by_exprt &to_sva_followed_by_expr(exprt &expr)
831+
{
832+
PRECONDITION(
833+
expr.id() == ID_sva_overlapped_followed_by ||
834+
expr.id() == ID_sva_nonoverlapped_followed_by);
835+
sva_followed_by_exprt::check(expr, validation_modet::INVARIANT);
836+
return static_cast<sva_followed_by_exprt &>(expr);
837+
}
838+
796839
class sva_cycle_delay_exprt : public ternary_exprt
797840
{
798841
public:

0 commit comments

Comments
 (0)