Skip to content

Commit 5612fe0

Browse files
authored
Merge pull request #430 from diffblue/property-normalizer
ebmc: normalize properties
2 parents 40abc2a + b0031ef commit 5612fe0

14 files changed

+131
-32
lines changed

src/ebmc/bdd_engine.cpp

+11-9
Original file line numberDiff line numberDiff line change
@@ -165,7 +165,7 @@ int bdd_enginet::operator()()
165165
cmdline, transition_system, message.get_message_handler());
166166

167167
for(const propertyt &p : properties.properties)
168-
get_atomic_propositions(p.expr);
168+
get_atomic_propositions(p.normalized_expr);
169169

170170
message.status() << "Building BDD for netlist" << messaget::eom;
171171

@@ -376,7 +376,7 @@ void bdd_enginet::compute_counterexample(
376376

377377
::unwind(netlist, bmc_map, message, solver);
378378
::unwind_property(
379-
property.expr,
379+
property.normalized_expr,
380380
property.timeframe_literals,
381381
message.get_message_handler(),
382382
solver,
@@ -450,17 +450,18 @@ void bdd_enginet::check_property(propertyt &property)
450450
!has_temporal_operator(to_F_expr(to_G_expr(expr).op()).op());
451451
};
452452

453-
if(is_AGp(property.expr))
453+
if(is_AGp(property.normalized_expr))
454454
{
455455
AGp(property);
456456
}
457457
else if(
458-
is_AG_AFp(property.expr) || is_always_eventually(property.expr) ||
459-
is_GFp(property.expr))
458+
is_AG_AFp(property.normalized_expr) ||
459+
is_always_eventually(property.normalized_expr) ||
460+
is_GFp(property.normalized_expr))
460461
{
461462
AGAFp(property);
462463
}
463-
else if(!has_temporal_operator(property.expr))
464+
else if(!has_temporal_operator(property.normalized_expr))
464465
{
465466
just_p(property);
466467
}
@@ -482,7 +483,7 @@ Function: bdd_enginet::AGp
482483

483484
void bdd_enginet::AGp(propertyt &property)
484485
{
485-
const exprt &sub_expr = to_unary_expr(property.expr).op();
486+
const exprt &sub_expr = to_unary_expr(property.normalized_expr).op();
486487
BDD p = property2BDD(sub_expr);
487488

488489
// Start with !p, and go backwards until saturation or we hit an
@@ -563,7 +564,8 @@ Function: bdd_enginet::AGAFp
563564

564565
void bdd_enginet::AGAFp(propertyt &property)
565566
{
566-
const exprt &sub_expr = to_unary_expr(to_unary_expr(property.expr).op()).op();
567+
const exprt &sub_expr =
568+
to_unary_expr(to_unary_expr(property.normalized_expr).op()).op();
567569
BDD p = property2BDD(sub_expr);
568570

569571
// Start with p, and go backwards until saturation.
@@ -648,7 +650,7 @@ void bdd_enginet::just_p(propertyt &property)
648650
{
649651
// We check whether the BDD for the negation of the property
650652
// contains an initial state.
651-
exprt negation = negate_property(property.expr);
653+
exprt negation = negate_property(property.normalized_expr);
652654
BDD states = property2BDD(negation);
653655

654656
// do we have an initial state?

src/ebmc/bmc.cpp

+2-2
Original file line numberDiff line numberDiff line change
@@ -47,14 +47,14 @@ void bmc(
4747
continue;
4848

4949
// Is it supported by the BMC engine?
50-
if(!bmc_supports_property(property.expr))
50+
if(!bmc_supports_property(property.normalized_expr))
5151
{
5252
property.failure("property not supported by BMC engine");
5353
continue;
5454
}
5555

5656
::property(
57-
property.expr,
57+
property.normalized_expr,
5858
property.timeframe_handles,
5959
message_handler,
6060
solver,

src/ebmc/ebmc_base.cpp

+1-1
Original file line numberDiff line numberDiff line change
@@ -200,7 +200,7 @@ int ebmc_baset::do_bit_level_bmc(cnft &solver, bool convert_only)
200200
continue;
201201

202202
::unwind_property(
203-
property.expr,
203+
property.normalized_expr,
204204
property.timeframe_literals,
205205
message.get_message_handler(),
206206
solver,

src/ebmc/ebmc_properties.cpp

+6-2
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ Author: Daniel Kroening, [email protected]
1111
#include <langapi/language.h>
1212
#include <langapi/language_util.h>
1313
#include <langapi/mode.h>
14+
#include <temporal-logic/normalize_property.h>
1415
#include <verilog/sva_expr.h>
1516

1617
#include "ebmc_error.h"
@@ -70,7 +71,9 @@ ebmc_propertiest ebmc_propertiest::from_transition_system(
7071
else
7172
properties.properties.back().name = symbol.pretty_name;
7273

73-
properties.properties.back().expr = symbol.value;
74+
properties.properties.back().original_expr = symbol.value;
75+
properties.properties.back().normalized_expr =
76+
normalize_property(symbol.value);
7477
properties.properties.back().location = symbol.location;
7578
properties.properties.back().expr_string = value_as_string;
7679
properties.properties.back().mode = symbol.mode;
@@ -156,7 +159,8 @@ ebmc_propertiest ebmc_propertiest::from_command_line(
156159
ebmc_propertiest properties;
157160
properties.properties.push_back(propertyt());
158161
auto &p = properties.properties.back();
159-
p.expr = expr;
162+
p.original_expr = expr;
163+
p.normalized_expr = normalize_property(expr);
160164
p.expr_string = expr_as_string;
161165
p.mode = transition_system.main_symbol->mode;
162166
p.location.make_nil();

src/ebmc/ebmc_properties.h

+3-2
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,8 @@ class ebmc_propertiest
2929
source_locationt location;
3030
std::string expr_string;
3131
irep_idt mode;
32-
exprt expr;
32+
exprt original_expr;
33+
exprt normalized_expr;
3334
bvt timeframe_literals; // bit level
3435
exprt::operandst timeframe_handles; // word level
3536
std::string description;
@@ -143,7 +144,7 @@ class ebmc_propertiest
143144

144145
bool requires_lasso_constraints() const
145146
{
146-
return ::requires_lasso_constraints(expr);
147+
return ::requires_lasso_constraints(normalized_expr);
147148
}
148149
};
149150

src/ebmc/k_induction.cpp

+2-2
Original file line numberDiff line numberDiff line change
@@ -71,7 +71,7 @@ class k_inductiont
7171

7272
static bool supported(const ebmc_propertiest::propertyt &p)
7373
{
74-
auto &expr = p.expr;
74+
auto &expr = p.normalized_expr;
7575
if(expr.id() == ID_sva_always || expr.id() == ID_AG || expr.id() == ID_G)
7676
{
7777
// Must be AG p or equivalent.
@@ -264,7 +264,7 @@ void k_inductiont::induction_step()
264264
ns,
265265
false);
266266

267-
const exprt property(p_it.expr);
267+
const exprt property(p_it.normalized_expr);
268268
const exprt &p = to_unary_expr(property).op();
269269

270270
// assumption: time frames 0,...,k-1

src/ebmc/liveness_to_safety.cpp

+8-5
Original file line numberDiff line numberDiff line change
@@ -248,9 +248,11 @@ void liveness_to_safetyt::operator()()
248248
{
249249
// We want GFp.
250250
if(
251-
property.expr.id() == ID_sva_always &&
252-
(to_sva_always_expr(property.expr).op().id() == ID_sva_eventually ||
253-
to_sva_always_expr(property.expr).op().id() == ID_sva_s_eventually))
251+
property.normalized_expr.id() == ID_sva_always &&
252+
(to_sva_always_expr(property.normalized_expr).op().id() ==
253+
ID_sva_eventually ||
254+
to_sva_always_expr(property.normalized_expr).op().id() ==
255+
ID_sva_s_eventually))
254256
{
255257
translate_GFp(property);
256258
}
@@ -265,7 +267,7 @@ void liveness_to_safetyt::operator()()
265267

266268
void liveness_to_safetyt::translate_GFp(propertyt &property)
267269
{
268-
auto &p = to_unary_expr(to_unary_expr(property.expr).op()).op();
270+
auto &p = to_unary_expr(to_unary_expr(property.normalized_expr).op()).op();
269271

270272
// create the 'live' symbol, one for each liveness property
271273
{
@@ -299,7 +301,8 @@ void liveness_to_safetyt::translate_GFp(propertyt &property)
299301
conjunction({transition_system.trans_expr.trans(), std::move(live_trans)});
300302

301303
// replace the liveness property
302-
property.expr = safety_replacement(property.name, property.expr);
304+
property.normalized_expr =
305+
safety_replacement(property.name, property.normalized_expr);
303306
}
304307

305308
void liveness_to_safety(

src/ebmc/neural_liveness.cpp

+6-5
Original file line numberDiff line numberDiff line change
@@ -162,13 +162,14 @@ void neural_livenesst::validate_properties()
162162
{
163163
// ignore
164164
}
165-
else if(property.expr.id() == ID_AF)
165+
else if(property.normalized_expr.id() == ID_AF)
166166
{
167167
// ok
168168
}
169169
else if(
170-
property.expr.id() == ID_sva_always &&
171-
to_sva_always_expr(property.expr).op().id() == ID_sva_s_eventually)
170+
property.normalized_expr.id() == ID_sva_always &&
171+
to_sva_always_expr(property.normalized_expr).op().id() ==
172+
ID_sva_s_eventually)
172173
{
173174
// ok
174175
}
@@ -188,7 +189,7 @@ void neural_livenesst::set_live_signal(
188189
auto main_symbol_writeable = transition_system.symbol_table.get_writeable(
189190
transition_system.main_symbol->name);
190191
main_symbol_writeable->value = original_trans_expr; // copy
191-
::set_live_signal(transition_system, property.expr);
192+
::set_live_signal(transition_system, property.normalized_expr);
192193
}
193194

194195
std::function<void(trans_tracet)>
@@ -301,7 +302,7 @@ tvt neural_livenesst::verify(
301302

302303
auto result = is_ranking_function(
303304
transition_system,
304-
property.expr,
305+
property.normalized_expr,
305306
candidate,
306307
solver_factory,
307308
message.get_message_handler());

src/ebmc/ranking_function.cpp

+1-1
Original file line numberDiff line numberDiff line change
@@ -109,7 +109,7 @@ int do_ranking_function(
109109

110110
auto result = is_ranking_function(
111111
transition_system,
112-
property.expr,
112+
property.normalized_expr,
113113
ranking_function,
114114
solver_factory,
115115
message_handler);

src/ic3/r1ead_input.cc

+2-2
Original file line numberDiff line numberDiff line change
@@ -36,9 +36,9 @@ void ic3_enginet::find_prop_lit()
3636
bool found = find_prop(Prop);
3737

3838
assert(found);
39-
assert(Prop.expr.id() == ID_sva_always);
39+
assert(Prop.normalized_expr.id() == ID_sva_always);
4040

41-
exprt Oper = to_unary_expr(Prop.expr).op();
41+
exprt Oper = to_unary_expr(Prop.normalized_expr).op();
4242

4343
found = banned_expr(Oper);
4444
if (found) {

src/temporal-logic/Makefile

+1
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
SRC = negate_property.cpp \
2+
normalize_property.cpp \
23
temporal_logic.cpp \
34
#empty line
45

+65
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,65 @@
1+
/*******************************************************************\
2+
3+
Module: Property Normalization
4+
5+
Author: Daniel Kroening, [email protected]
6+
7+
\*******************************************************************/
8+
9+
#include "normalize_property.h"
10+
11+
#include <util/std_expr.h>
12+
13+
#include <verilog/sva_expr.h>
14+
15+
#include "temporal_expr.h"
16+
17+
exprt normalize_pre_not(not_exprt expr)
18+
{
19+
const auto &op = expr.op();
20+
21+
if(op.id() == ID_and)
22+
{
23+
auto operands = op.operands();
24+
for(auto &op : operands)
25+
op = not_exprt{op};
26+
return or_exprt{std::move(operands)};
27+
}
28+
else if(op.id() == ID_or)
29+
{
30+
auto operands = op.operands();
31+
for(auto &op : operands)
32+
op = not_exprt{op};
33+
return and_exprt{std::move(operands)};
34+
}
35+
else if(op.id() == ID_not)
36+
{
37+
return to_not_expr(op).op();
38+
}
39+
40+
return std::move(expr);
41+
}
42+
43+
exprt normalize_pre_implies(implies_exprt expr)
44+
{
45+
return or_exprt{not_exprt{expr.lhs()}, expr.rhs()};
46+
}
47+
48+
exprt normalize_property(exprt expr)
49+
{
50+
// pre-traversal
51+
if(expr.id() == ID_not)
52+
expr = normalize_pre_not(to_not_expr(expr));
53+
else if(expr.id() == ID_implies)
54+
expr = normalize_pre_implies(to_implies_expr(expr));
55+
else if(expr.id() == ID_sva_cover)
56+
expr = G_exprt{not_exprt{to_sva_cover_expr(expr).op()}};
57+
58+
// normalize the operands
59+
for(auto &op : expr.operands())
60+
op = normalize_property(op);
61+
62+
// post-traversal
63+
64+
return expr;
65+
}
+21
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
/*******************************************************************\
2+
3+
Module: Property Normalization
4+
5+
Author: Daniel Kroening, [email protected]
6+
7+
\*******************************************************************/
8+
9+
#ifndef CPROVER_TEMPORAL_LOGIC_NORMALIZE_PROPERTY_H
10+
#define CPROVER_TEMPORAL_LOGIC_NORMALIZE_PROPERTY_H
11+
12+
#include <util/expr.h>
13+
14+
/// This applies the following rewrites:
15+
/// cover(φ) --> G¬φ
16+
/// ¬(a ∨ b) --> ¬a ∧ ¬b
17+
/// ¬(a ∧ b) --> ¬a ∨ ¬b
18+
/// ¬¬φ --> φ
19+
exprt normalize_property(exprt);
20+
21+
#endif

src/verilog/verilog_synthesis.cpp

+2-1
Original file line numberDiff line numberDiff line change
@@ -1850,7 +1850,8 @@ void verilog_synthesist::synth_assert_cover(
18501850

18511851
if(module_item.id() == ID_verilog_assert_property)
18521852
{
1853-
// Concurrent assertions come with an implicit 'always'.
1853+
// Concurrent assertions come with an implicit 'always'
1854+
// (1800-2017 Sec 16.12.11).
18541855
if(cond.id() != ID_sva_always)
18551856
cond = sva_always_exprt(cond);
18561857
}

0 commit comments

Comments
 (0)