Skip to content

Commit 0ed1544

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

File tree

6 files changed

+104
-41
lines changed

6 files changed

+104
-41
lines changed
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
CORE
2+
initial1.sv
3+
4+
^\[main\.a0\] always main\.x: ASSUMED$
5+
^\[main\.p0\] main\.x: PROVED \(CT=0\)$
6+
^EXIT=0$
7+
^SIGNAL=0$
8+
--
9+
^warning: ignoring
10+
--
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
module main(input clk, input x);
2+
3+
a0: assume property (x);
4+
5+
initial p0: assert property (x);
6+
7+
endmodule

regression/verilog/SVA/initial1.bmc.desc

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ initial1.sv
33
--module main
44
^\[main\.p0\] main\.counter == 0: PROVED .*$
55
^\[main\.p1\] main\.counter == 100: REFUTED$
6-
^\[main\.p2\] ##1 main\.counter == 1: PROVED up to bound 5$
6+
^\[main\.p2\] ##1 main\.counter == 1: PROVED \(CT=1\)$
77
^\[main\.p3\] ##1 main\.counter == 100: REFUTED$
88
^\[main\.p4\] s_nexttime main\.counter == 1: PROVED .*$
99
^\[main\.p5\] always \[1:1\] main\.counter == 1: PROVED .*$

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: 82 additions & 36 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 ||
@@ -38,66 +44,103 @@ bool has_low_completeness_threshold(const exprt &expr)
3844
{
3945
auto &always_expr = to_sva_ranged_always_expr(expr);
4046
if(has_temporal_operator(always_expr.op()))
41-
return false;
42-
else if(always_expr.to().is_constant())
47+
return {};
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 = numeric_cast_v<mp_integer>(s_always_expr.to());
69+
70+
if(to_int < 0)
71+
return {};
72+
73+
// increases the CT by to_int
74+
auto ct_op = completeness_threshold(s_always_expr.op());
75+
if(ct_op.has_value())
76+
return *ct_op + to_int;
5777
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-
}
78+
return {};
6379
}
6480
else if(
6581
expr.id() == ID_sva_strong || expr.id() == ID_sva_weak ||
6682
expr.id() == ID_sva_implicit_strong || expr.id() == ID_sva_implicit_weak)
6783
{
6884
auto &sequence = to_sva_sequence_property_expr_base(expr).sequence();
69-
return has_low_completeness_threshold(sequence);
85+
return completeness_threshold(sequence);
7086
}
7187
else if(expr.id() == ID_sva_boolean)
7288
{
73-
return true;
89+
return 0; // state predicate only
7490
}
75-
else if(expr.id() == ID_sva_or || expr.id() == ID_sva_and)
91+
else if(expr.id() == ID_sva_cycle_delay)
7692
{
77-
for(auto &op : expr.operands())
78-
if(!has_low_completeness_threshold(op))
79-
return false;
80-
return true;
93+
auto &cycle_delay = to_sva_cycle_delay_expr(expr);
94+
mp_integer ct_lhs = 0;
95+
96+
if(cycle_delay.lhs().is_not_nil())
97+
{
98+
auto ct_lhs_opt = completeness_threshold(cycle_delay.lhs());
99+
if(ct_lhs_opt.has_value())
100+
ct_lhs = ct_lhs_opt.value();
101+
else
102+
return {};
103+
}
104+
105+
if(cycle_delay.is_range())
106+
return {};
107+
else // singleton
108+
{
109+
auto ct_rhs = completeness_threshold(cycle_delay.rhs());
110+
if(ct_rhs.has_value())
111+
return ct_lhs + numeric_cast_v<mp_integer>(cycle_delay.from()) +
112+
*ct_rhs;
113+
else
114+
return {};
115+
}
81116
}
82117
else if(expr.id() == ID_sva_sequence_property)
83118
{
84119
PRECONDITION(false); // should have been turned into implicit weak/strong
85120
}
86121
else
87-
return false;
122+
return {};
88123
}
89124

90-
bool has_low_completeness_threshold(const ebmc_propertiest::propertyt &property)
125+
std::optional<mp_integer>
126+
completeness_threshold(const ebmc_propertiest::propertyt &property)
91127
{
92-
return has_low_completeness_threshold(property.normalized_expr);
128+
return completeness_threshold(property.normalized_expr);
93129
}
94130

95-
bool have_low_completeness_threshold(const ebmc_propertiest &properties)
131+
std::optional<mp_integer>
132+
completeness_threshold(const ebmc_propertiest &properties)
96133
{
134+
std::optional<mp_integer> max_ct;
135+
97136
for(auto &property : properties.properties)
98-
if(has_low_completeness_threshold(property))
99-
return true;
100-
return false;
137+
{
138+
auto ct_opt = completeness_threshold(property);
139+
if(ct_opt.has_value())
140+
max_ct = std::max(max_ct.value_or(0), *ct_opt);
141+
}
142+
143+
return max_ct;
101144
}
102145

103146
property_checker_resultt completeness_threshold(
@@ -107,14 +150,16 @@ property_checker_resultt completeness_threshold(
107150
const ebmc_solver_factoryt &solver_factory,
108151
message_handlert &message_handler)
109152
{
110-
// Do we have an eligibile property?
111-
if(!have_low_completeness_threshold(properties))
153+
// Do we have an eligible property?
154+
auto ct_opt = completeness_threshold(properties);
155+
156+
if(!ct_opt.has_value())
112157
return property_checker_resultt{properties}; // give up
113158

114-
// Do BMC with two timeframes
159+
// Do BMC, using the CT as the bound
115160
auto result = bmc(
116-
1, // bound
117-
false, // convert_only
161+
numeric_cast_v<std::size_t>(*ct_opt), // bound
162+
false, // convert_only
118163
cmdline.isset("bmc-with-assumptions"),
119164
transition_system,
120165
properties,
@@ -126,8 +171,9 @@ property_checker_resultt completeness_threshold(
126171
if(property.is_proved_with_bound())
127172
{
128173
// 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");
174+
auto property_ct_opt = completeness_threshold(property);
175+
if(property_ct_opt.has_value())
176+
property.proved("CT=" + integer2string(*property_ct_opt));
131177
else
132178
property.unknown();
133179
}

0 commit comments

Comments
 (0)