Skip to content

Commit 9a64358

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 9a64358

File tree

6 files changed

+105
-41
lines changed

6 files changed

+105
-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: 83 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,104 @@ 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 =
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
}
75-
else if(expr.id() == ID_sva_or || expr.id() == ID_sva_and)
92+
else if(expr.id() == ID_sva_cycle_delay)
7693
{
77-
for(auto &op : expr.operands())
78-
if(!has_low_completeness_threshold(op))
79-
return false;
80-
return true;
94+
auto &cycle_delay = to_sva_cycle_delay_expr(expr);
95+
mp_integer ct_lhs = 0;
96+
97+
if(cycle_delay.lhs().is_not_nil())
98+
{
99+
auto ct_lhs_opt = completeness_threshold(cycle_delay.lhs());
100+
if(ct_lhs_opt.has_value())
101+
ct_lhs = ct_lhs_opt.value();
102+
else
103+
return {};
104+
}
105+
106+
if(cycle_delay.is_range())
107+
return {};
108+
else // singleton
109+
{
110+
auto ct_rhs = completeness_threshold(cycle_delay.rhs());
111+
if(ct_rhs.has_value())
112+
return ct_lhs + numeric_cast_v<mp_integer>(cycle_delay.from()) +
113+
*ct_rhs;
114+
else
115+
return {};
116+
}
81117
}
82118
else if(expr.id() == ID_sva_sequence_property)
83119
{
84120
PRECONDITION(false); // should have been turned into implicit weak/strong
85121
}
86122
else
87-
return false;
123+
return {};
88124
}
89125

90-
bool has_low_completeness_threshold(const ebmc_propertiest::propertyt &property)
126+
std::optional<mp_integer>
127+
completeness_threshold(const ebmc_propertiest::propertyt &property)
91128
{
92-
return has_low_completeness_threshold(property.normalized_expr);
129+
return completeness_threshold(property.normalized_expr);
93130
}
94131

95-
bool have_low_completeness_threshold(const ebmc_propertiest &properties)
132+
std::optional<mp_integer>
133+
completeness_threshold(const ebmc_propertiest &properties)
96134
{
135+
std::optional<mp_integer> max_ct;
136+
97137
for(auto &property : properties.properties)
98-
if(has_low_completeness_threshold(property))
99-
return true;
100-
return false;
138+
{
139+
auto ct_opt = completeness_threshold(property);
140+
if(ct_opt.has_value())
141+
max_ct = std::max(max_ct.value_or(0), *ct_opt);
142+
}
143+
144+
return max_ct;
101145
}
102146

103147
property_checker_resultt completeness_threshold(
@@ -107,14 +151,16 @@ property_checker_resultt completeness_threshold(
107151
const ebmc_solver_factoryt &solver_factory,
108152
message_handlert &message_handler)
109153
{
110-
// Do we have an eligibile property?
111-
if(!have_low_completeness_threshold(properties))
154+
// Do we have an eligible property?
155+
auto ct_opt = completeness_threshold(properties);
156+
157+
if(!ct_opt.has_value())
112158
return property_checker_resultt{properties}; // give up
113159

114-
// Do BMC with two timeframes
160+
// Do BMC, using the CT as the bound
115161
auto result = bmc(
116-
1, // bound
117-
false, // convert_only
162+
numeric_cast_v<std::size_t>(*ct_opt), // bound
163+
false, // convert_only
118164
cmdline.isset("bmc-with-assumptions"),
119165
transition_system,
120166
properties,
@@ -126,8 +172,9 @@ property_checker_resultt completeness_threshold(
126172
if(property.is_proved_with_bound())
127173
{
128174
// 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");
175+
auto property_ct_opt = completeness_threshold(property);
176+
if(property_ct_opt.has_value())
177+
property.proved("CT=" + integer2string(*property_ct_opt));
131178
else
132179
property.unknown();
133180
}

0 commit comments

Comments
 (0)