Skip to content

Commit c9beb46

Browse files
committed
BMC: completeness thresholds larger than one
The completeness threshold engine now considers some CTs that are bigger than one.
1 parent bf112c1 commit c9beb46

File tree

3 files changed

+71
-35
lines changed

3 files changed

+71
-35
lines changed

regression/verilog/SVA/sequence_and1.bmc.desc

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ sequence_and1.sv
55
^\[main\.p1\] strong\(main\.x == 0 and main\.x == 1\): REFUTED$
66
^\[main\.p2\] main\.x == 0 and \(nexttime main\.x == 1\): PROVED up to bound \d+$
77
^\[main\.p3\] \(nexttime main\.x == 1\) and main\.x == 0: PROVED up to bound \d+$
8-
^\[main\.p4\] \(main\.x == 0 and main\.x != 10\) |=> main\.x == 1: PROVED up to bound \d+$
8+
^\[main\.p4\] \(main\.x == 0 and main\.x != 10\) |=> main\.x == 1: PROVED$
99
^EXIT=10$
1010
^SIGNAL=0$
1111
--

regression/verilog/SVA/sequence_and2.bmc.desc

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,9 @@
11
CORE
22
sequence_and2.sv
33

4-
\[.*\] \(1 and \(##2 1\)\) \|-> main\.x == 2: PROVED up to bound 5$
5-
\[.*\] \(\(##2 1\) and 1\) \|-> main\.x == 2: PROVED up to bound 5$
6-
\[.*\] \(\(##2 1\) and 1\) #-# main\.x == 2: PROVED up to bound 5$
4+
^\[.*\] \(1 and \(##2 1\)\) \|-> main\.x == 2: PROVED up to bound 5$
5+
^\[.*\] \(\(##2 1\) and 1\) \|-> main\.x == 2: PROVED up to bound 5$
6+
^\[.*\] \(\(##2 1\) and 1\) #-# main\.x == 2: PROVED up to bound 5$
77
^EXIT=0$
88
^SIGNAL=0$
99
--

src/ebmc/completeness_threshold.cpp

Lines changed: 67 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -16,16 +16,22 @@ Author: Daniel Kroening, [email protected]
1616

1717
#include "bmc.h"
1818

19-
bool has_low_completeness_threshold(const exprt &expr)
19+
// counting number of transitions
20+
std::optional<mp_integer> completeness_threshold(const exprt &expr)
2021
{
2122
if(!has_temporal_operator(expr))
2223
{
23-
return true; // state predicate only
24+
return 0; // state predicate only
2425
}
2526
else if(expr.id() == ID_X)
2627
{
2728
// X p
28-
return !has_temporal_operator(to_X_expr(expr).op());
29+
// Increases the CT by one.
30+
auto ct_p = completeness_threshold(to_X_expr(expr).op());
31+
if(ct_p.has_value())
32+
return *ct_p + 1;
33+
else
34+
return {};
2935
}
3036
else if(
3137
expr.id() == ID_sva_nexttime || expr.id() == ID_sva_s_nexttime ||
@@ -39,65 +45,92 @@ bool has_low_completeness_threshold(const exprt &expr)
3945
auto &always_expr = to_sva_ranged_always_expr(expr);
4046
if(has_temporal_operator(always_expr.op()))
4147
return false;
42-
else if(always_expr.to().is_constant())
48+
49+
if(always_expr.is_range() && !always_expr.is_unbounded())
4350
{
44-
auto from_int = numeric_cast_v<mp_integer>(always_expr.from());
4551
auto to_int =
4652
numeric_cast_v<mp_integer>(to_constant_expr(always_expr.to()));
47-
return from_int >= 0 && from_int <= 1 && to_int >= 0 && to_int <= 1;
53+
54+
// increases the CT by to_int
55+
auto ct_op = completeness_threshold(always_expr.op());
56+
if(ct_op.has_value())
57+
return *ct_op + to_int;
58+
else
59+
return {};
4860
}
4961
else
50-
return false;
62+
return {};
5163
}
5264
else if(expr.id() == ID_sva_s_always)
5365
{
5466
auto &s_always_expr = to_sva_s_always_expr(expr);
55-
if(has_temporal_operator(s_always_expr.op()))
56-
return false;
67+
68+
auto to_int =
69+
numeric_cast_v<mp_integer>(s_always_expr.to());
70+
71+
if(to_int < 0)
72+
return {};
73+
74+
// increases the CT by to_int
75+
auto ct_op = completeness_threshold(s_always_expr.op());
76+
if(ct_op.has_value())
77+
return *ct_op + to_int;
5778
else
58-
{
59-
auto from_int = numeric_cast_v<mp_integer>(s_always_expr.from());
60-
auto to_int = numeric_cast_v<mp_integer>(s_always_expr.to());
61-
return from_int >= 0 && from_int <= 1 && to_int >= 0 && to_int <= 1;
62-
}
79+
return {};
6380
}
6481
else if(
6582
expr.id() == ID_sva_strong || expr.id() == ID_sva_weak ||
6683
expr.id() == ID_sva_implicit_strong || expr.id() == ID_sva_implicit_weak)
6784
{
6885
auto &sequence = to_sva_sequence_property_expr_base(expr).sequence();
69-
return has_low_completeness_threshold(sequence);
86+
return completeness_threshold(sequence);
7087
}
7188
else if(expr.id() == ID_sva_boolean)
7289
{
73-
return true;
90+
return 0; // state predicate only
7491
}
7592
else if(expr.id() == ID_sva_or || expr.id() == ID_sva_and)
7693
{
94+
mp_integer max_ct = 0;
95+
7796
for(auto &op : expr.operands())
78-
if(!has_low_completeness_threshold(op))
79-
return false;
80-
return true;
97+
{
98+
auto ct_op = completeness_threshold(op);
99+
if(ct_op.has_value())
100+
max_ct = std::max(*ct_op, max_ct);
101+
else
102+
return {}; // no CT
103+
}
104+
105+
return max_ct;
81106
}
82107
else if(expr.id() == ID_sva_sequence_property)
83108
{
84109
PRECONDITION(false); // should have been turned into implicit weak/strong
85110
}
86111
else
87-
return false;
112+
return {};
88113
}
89114

90-
bool has_low_completeness_threshold(const ebmc_propertiest::propertyt &property)
115+
std::optional<mp_integer>
116+
completeness_threshold(const ebmc_propertiest::propertyt &property)
91117
{
92-
return has_low_completeness_threshold(property.normalized_expr);
118+
return completeness_threshold(property.normalized_expr);
93119
}
94120

95-
bool have_low_completeness_threshold(const ebmc_propertiest &properties)
121+
std::optional<mp_integer>
122+
completeness_threshold(const ebmc_propertiest &properties)
96123
{
124+
std::optional<mp_integer> max_ct;
125+
97126
for(auto &property : properties.properties)
98-
if(has_low_completeness_threshold(property))
99-
return true;
100-
return false;
127+
{
128+
auto ct_opt = completeness_threshold(property);
129+
if(ct_opt.has_value())
130+
max_ct = std::max(max_ct.value_or(0), *ct_opt);
131+
}
132+
133+
return max_ct;
101134
}
102135

103136
property_checker_resultt completeness_threshold(
@@ -108,13 +141,15 @@ property_checker_resultt completeness_threshold(
108141
message_handlert &message_handler)
109142
{
110143
// Do we have an eligibile property?
111-
if(!have_low_completeness_threshold(properties))
144+
auto ct_opt = completeness_threshold(properties);
145+
146+
if(!ct_opt.has_value())
112147
return property_checker_resultt{properties}; // give up
113148

114149
// Do BMC with two timeframes
115150
auto result = bmc(
116-
1, // bound
117-
false, // convert_only
151+
numeric_cast_v<std::size_t>(*ct_opt), // bound
152+
false, // convert_only
118153
cmdline.isset("bmc-with-assumptions"),
119154
transition_system,
120155
properties,
@@ -126,8 +161,9 @@ property_checker_resultt completeness_threshold(
126161
if(property.is_proved_with_bound())
127162
{
128163
// Turn "PROVED up to bound k" into "PROVED" if k>=CT
129-
if(has_low_completeness_threshold(property) && property.bound >= 1)
130-
property.proved("CT=1");
164+
auto property_ct_opt = completeness_threshold(property);
165+
if(property_ct_opt.has_value())
166+
property.proved("CT=" + integer2string(*property_ct_opt));
131167
else
132168
property.unknown();
133169
}

0 commit comments

Comments
 (0)