Skip to content

Commit 9964659

Browse files
committed
introduce sva_boolean_exprt
IEEE 1800-2017 16.6 Boolean expressions introduces rules on how to convert Boolean expressions into SVA sequences or properties. This introduces an expression for this conversion.
1 parent 3b326d1 commit 9964659

11 files changed

+134
-38
lines changed

src/ebmc/completeness_threshold.cpp

+12-4
Original file line numberDiff line numberDiff line change
@@ -68,10 +68,18 @@ bool has_low_completeness_threshold(const exprt &expr)
6868
expr.id() == ID_sva_implicit_strong || expr.id() == ID_sva_implicit_weak)
6969
{
7070
auto &sequence = to_sva_sequence_property_expr_base(expr).sequence();
71-
if(!is_SVA_sequence_operator(sequence))
72-
return true;
73-
else
74-
return false;
71+
return has_low_completeness_threshold(sequence);
72+
}
73+
else if(expr.id() == ID_sva_boolean)
74+
{
75+
return true;
76+
}
77+
else if(expr.id() == ID_sva_or || expr.id() == ID_sva_and)
78+
{
79+
for(auto &op : expr.operands())
80+
if(!has_low_completeness_threshold(op))
81+
return false;
82+
return true;
7583
}
7684
else if(expr.id() == ID_sva_sequence_property)
7785
{

src/hw_cbmc_irep_ids.h

+1
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,7 @@ IREP_ID_ONE(smv_EBG)
4545
IREP_ID_ONE(smv_ABG)
4646
IREP_ID_ONE(smv_ABU)
4747
IREP_ID_ONE(smv_EBU)
48+
IREP_ID_ONE(sva_boolean)
4849
IREP_ID_ONE(sva_accept_on)
4950
IREP_ID_ONE(sva_reject_on)
5051
IREP_ID_ONE(sva_sync_accept_on)

src/temporal-logic/nnf.cpp

+18
Original file line numberDiff line numberDiff line change
@@ -149,6 +149,24 @@ std::optional<exprt> negate_property_node(const exprt &expr)
149149
return sva_non_overlapped_implication_exprt{
150150
followed_by.antecedent(), not_b};
151151
}
152+
else if(expr.id() == ID_sva_overlapped_implication)
153+
{
154+
// 1800 2017 16.12.9
155+
// !(a |-> b) ---> a #-# !b
156+
auto &implication = to_sva_implication_base_expr(expr);
157+
auto not_b = not_exprt{implication.consequent()};
158+
return sva_followed_by_exprt{
159+
implication.antecedent(), ID_sva_overlapped_followed_by, not_b};
160+
}
161+
else if(expr.id() == ID_sva_non_overlapped_implication)
162+
{
163+
// 1800 2017 16.12.9
164+
// !(a |=> b) ---> a #=# !b
165+
auto &implication = to_sva_implication_base_expr(expr);
166+
auto not_b = not_exprt{implication.consequent()};
167+
return sva_followed_by_exprt{
168+
implication.antecedent(), ID_sva_nonoverlapped_followed_by, not_b};
169+
}
152170
else
153171
return {};
154172
}

src/temporal-logic/normalize_property.cpp

+22-3
Original file line numberDiff line numberDiff line change
@@ -23,12 +23,26 @@ Author: Daniel Kroening, [email protected]
2323
exprt normalize_pre_sva_non_overlapped_implication(
2424
sva_non_overlapped_implication_exprt expr)
2525
{
26-
// Same as a->always[1:1] b if lhs is not a sequence.
27-
if(!is_SVA_sequence_operator(expr.lhs()))
26+
// a|=>b is the same as a->always[1:1] b if lhs is not a proper sequence.
27+
if(expr.lhs().id() == ID_sva_boolean)
2828
{
29+
const auto &lhs_cond = to_sva_boolean_expr(expr.lhs()).op();
2930
auto one = natural_typet{}.one_expr();
3031
return or_exprt{
31-
not_exprt{expr.lhs()}, sva_ranged_always_exprt{one, one, expr.rhs()}};
32+
not_exprt{lhs_cond}, sva_ranged_always_exprt{one, one, expr.rhs()}};
33+
}
34+
else
35+
return std::move(expr);
36+
}
37+
38+
exprt normalize_pre_sva_overlapped_implication(
39+
sva_overlapped_implication_exprt expr)
40+
{
41+
// a|->b is the same as a->b if lhs is not a proper sequence.
42+
if(expr.lhs().id() == ID_sva_boolean)
43+
{
44+
const auto &lhs_cond = to_sva_boolean_expr(expr.lhs()).op();
45+
return implies_exprt{lhs_cond, expr.rhs()};
3246
}
3347
else
3448
return std::move(expr);
@@ -42,6 +56,11 @@ exprt normalize_property_rec(exprt expr)
4256
expr = normalize_pre_sva_non_overlapped_implication(
4357
to_sva_non_overlapped_implication_expr(expr));
4458
}
59+
else if(expr.id() == ID_sva_overlapped_implication)
60+
{
61+
expr = normalize_pre_sva_overlapped_implication(
62+
to_sva_overlapped_implication_expr(expr));
63+
}
4564
else if(expr.id() == ID_sva_nexttime)
4665
{
4766
auto one = natural_typet{}.one_expr();

src/temporal-logic/normalize_property.h

+2-3
Original file line numberDiff line numberDiff line change
@@ -13,15 +13,14 @@ Author: Daniel Kroening, [email protected]
1313

1414
/// This applies the following rewrites:
1515
///
16-
/// cover(φ) --> G¬φ
17-
///
1816
/// -----Propositional-----
1917
/// ¬(a ∨ b) --> ¬a ∧ ¬b
2018
/// ¬(a ∧ b) --> ¬a ∨ ¬b
2119
/// (a -> b) --> ¬a ∨ b
2220
///
2321
/// -----SVA-----
24-
/// sva_non_overlapped_implication --> ¬a ∨ always[1:1] b if a is not an SVA sequence
22+
/// a|=>b --> ¬a ∨ always[1:1] b if a is not an SVA sequence
23+
/// a|->b --> a⇒b if a is not an SVA sequence
2524
/// sva_nexttime φ --> sva_always[1:1] φ
2625
/// sva_nexttime[i] φ --> sva_always[i:i] φ
2726
/// sva_s_nexttime φ --> sva_always[1:1] φ

src/temporal-logic/sva_to_ltl.cpp

+2-2
Original file line numberDiff line numberDiff line change
@@ -42,10 +42,10 @@ struct ltl_sequence_matcht
4242

4343
std::vector<ltl_sequence_matcht> LTL_sequence_matches(const exprt &sequence)
4444
{
45-
if(!is_SVA_sequence_operator(sequence))
45+
if(sequence.id() == ID_sva_boolean)
4646
{
4747
// atomic proposition
48-
return {{sequence, 1}};
48+
return {{to_sva_boolean_expr(sequence).op(), 1}};
4949
}
5050
else if(sequence.id() == ID_sva_sequence_concatenation)
5151
{

src/temporal-logic/trivial_sva.cpp

+37-22
Original file line numberDiff line numberDiff line change
@@ -12,12 +12,10 @@ Author: Daniel Kroening, [email protected]
1212

1313
#include "temporal_logic.h"
1414

15-
static std::optional<exprt> is_state_formula(const exprt &expr)
15+
static std::optional<exprt> is_state_predicate(const exprt &expr)
1616
{
17-
if(expr.id() == ID_typecast && expr.type().id() == ID_verilog_sva_sequence)
18-
return to_typecast_expr(expr).op();
19-
else if(expr.type().id() == ID_bool)
20-
return expr;
17+
if(expr.id() == ID_sva_boolean)
18+
return to_sva_boolean_expr(expr).op();
2119
else
2220
return {};
2321
}
@@ -30,8 +28,8 @@ exprt trivial_sva(exprt expr)
3028
// Same as regular implication if lhs and rhs are not sequences.
3129
auto &sva_implication = to_sva_overlapped_implication_expr(expr);
3230

33-
auto lhs = is_state_formula(sva_implication.lhs());
34-
auto rhs = is_state_formula(sva_implication.rhs());
31+
auto lhs = is_state_predicate(sva_implication.lhs());
32+
auto rhs = is_state_predicate(sva_implication.rhs());
3533

3634
if(lhs.has_value() && rhs.has_value())
3735
expr = implies_exprt{*lhs, *rhs};
@@ -50,23 +48,39 @@ exprt trivial_sva(exprt expr)
5048
{
5149
auto &sva_and = to_sva_and_expr(expr);
5250

53-
// Same as a ∧ b if the expression is not a sequence.
54-
auto lhs = is_state_formula(sva_and.lhs());
55-
auto rhs = is_state_formula(sva_and.rhs());
56-
57-
if(lhs.has_value() && rhs.has_value())
58-
expr = and_exprt{*lhs, *rhs};
51+
// can be sequence or property
52+
if(expr.type().id() == ID_verilog_sva_sequence)
53+
{
54+
// Same as a ∧ b if the expression is not a sequence.
55+
auto lhs = is_state_predicate(sva_and.lhs());
56+
auto rhs = is_state_predicate(sva_and.rhs());
57+
58+
if(lhs.has_value() && rhs.has_value())
59+
expr = sva_boolean_exprt{and_exprt{*lhs, *rhs}, expr.type()};
60+
}
61+
else
62+
{
63+
expr = and_exprt{sva_and.lhs(), sva_and.rhs()};
64+
}
5965
}
6066
else if(expr.id() == ID_sva_or)
6167
{
6268
auto &sva_or = to_sva_or_expr(expr);
6369

64-
// Same as a ∨ b if the expression is not a sequence.
65-
auto lhs = is_state_formula(sva_or.lhs());
66-
auto rhs = is_state_formula(sva_or.rhs());
67-
68-
if(lhs.has_value() && rhs.has_value())
69-
expr = or_exprt{*lhs, *rhs};
70+
// can be sequence or property
71+
if(expr.type().id() == ID_verilog_sva_sequence)
72+
{
73+
// Same as a ∨ b if the expression is not a sequence.
74+
auto lhs = is_state_predicate(sva_or.lhs());
75+
auto rhs = is_state_predicate(sva_or.rhs());
76+
77+
if(lhs.has_value() && rhs.has_value())
78+
expr = sva_boolean_exprt{or_exprt{*lhs, *rhs}, expr.type()};
79+
}
80+
else
81+
{
82+
expr = or_exprt{sva_or.lhs(), sva_or.rhs()};
83+
}
7084
}
7185
else if(expr.id() == ID_sva_not)
7286
{
@@ -113,9 +127,10 @@ exprt trivial_sva(exprt expr)
113127
{
114128
// We simplify sequences to boolean expressions, and hence can drop
115129
// the sva_sequence_property converter
116-
auto &op = to_sva_sequence_property_expr_base(expr).sequence();
117-
if(op.type().id() == ID_bool)
118-
return op;
130+
auto &sequence = to_sva_sequence_property_expr_base(expr).sequence();
131+
auto pred_opt = is_state_predicate(sequence);
132+
if(pred_opt.has_value())
133+
return *pred_opt;
119134
}
120135

121136
return expr;

src/trans-word-level/sequence.cpp

+9-3
Original file line numberDiff line numberDiff line change
@@ -454,10 +454,16 @@ sequence_matchest instantiate_sequence(
454454

455455
return result;
456456
}
457-
else
457+
else if(expr.id() == ID_sva_boolean)
458458
{
459-
// not a sequence, evaluate as state predicate
460-
auto instantiated = instantiate_property(expr, t, no_timeframes);
459+
// a state predicate
460+
auto &predicate = to_sva_boolean_expr(expr).op();
461+
auto instantiated = instantiate_property(predicate, t, no_timeframes);
461462
return {{instantiated.first, instantiated.second}};
462463
}
464+
else
465+
{
466+
DATA_INVARIANT_WITH_DIAGNOSTICS(
467+
false, "unexpected sequence expression", expr.pretty());
468+
}
463469
}

src/verilog/expr2verilog.cpp

+6
Original file line numberDiff line numberDiff line change
@@ -1815,6 +1815,12 @@ expr2verilogt::resultt expr2verilogt::convert_rec(const exprt &src)
18151815
return convert_rec(to_sva_sequence_property_expr_base(src).sequence());
18161816
}
18171817

1818+
else if(src.id() == ID_sva_boolean)
1819+
{
1820+
// These are invisible
1821+
return convert_rec(to_sva_boolean_expr(src).op());
1822+
}
1823+
18181824
else if(src.id()==ID_sva_sequence_concatenation)
18191825
return convert_sva_sequence_concatenation(
18201826
to_binary_expr(src), precedence = verilog_precedencet::MIN);

src/verilog/sva_expr.h

+23
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,29 @@ Author: Daniel Kroening, [email protected]
1313

1414
#include "verilog_types.h"
1515

16+
/// 1800-2017 16.6 Boolean expressions
17+
/// Conversion of a Boolean expression into a sequence or property
18+
class sva_boolean_exprt : public unary_exprt
19+
{
20+
public:
21+
sva_boolean_exprt(exprt condition, typet __type)
22+
: unary_exprt(ID_sva_boolean, std::move(condition), std::move(__type))
23+
{
24+
}
25+
};
26+
27+
static inline const sva_boolean_exprt &to_sva_boolean_expr(const exprt &expr)
28+
{
29+
sva_boolean_exprt::check(expr, validation_modet::INVARIANT);
30+
return static_cast<const sva_boolean_exprt &>(expr);
31+
}
32+
33+
static inline sva_boolean_exprt &to_sva_boolean_expr(exprt &expr)
34+
{
35+
sva_boolean_exprt::check(expr, validation_modet::INVARIANT);
36+
return static_cast<sva_boolean_exprt &>(expr);
37+
}
38+
1639
/// accept_on, reject_on, sync_accept_on, sync_reject_on, disable_iff
1740
class sva_abort_exprt : public binary_predicate_exprt
1841
{

src/verilog/verilog_typecheck_sva.cpp

+2-1
Original file line numberDiff line numberDiff line change
@@ -35,8 +35,9 @@ void verilog_typecheck_exprt::require_sva_sequence(exprt &expr)
3535
}
3636
else
3737
{
38-
// state formula, can cast to sequence
38+
// state formula, can convert to sequence
3939
make_boolean(expr);
40+
expr = sva_boolean_exprt{std::move(expr), verilog_sva_sequence_typet{}};
4041
}
4142
}
4243
else

0 commit comments

Comments
 (0)