Skip to content

Commit b3ceea0

Browse files
committed
netlists can now track properties with arbitrary shapes
The netlist data structure can store properties to check about the netlist. This replaces the std::variant data structure for storing properties for a few special cases of temporal logic formulas by an encoding using expressions over literal_exprt.
1 parent bad2f99 commit b3ceea0

File tree

10 files changed

+226
-110
lines changed

10 files changed

+226
-110
lines changed

src/ebmc/bdd_engine.cpp

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ Author: Daniel Kroening, [email protected]
1414
#include <ebmc/liveness_to_safety.h>
1515
#include <ebmc/transition_system.h>
1616
#include <solvers/bdd/miniBDD/miniBDD.h>
17+
#include <solvers/prop/literal_expr.h>
1718
#include <solvers/sat/satcheck.h>
1819
#include <temporal-logic/ctl.h>
1920
#include <temporal-logic/ltl.h>
@@ -1057,7 +1058,14 @@ void bdd_enginet::build_BDDs()
10571058
// find the netlist property
10581059
auto netlist_property = netlist.properties.find(property.identifier);
10591060
CHECK_RETURN(netlist_property != netlist.properties.end());
1060-
auto l = std::get<netlistt::Gpt>(netlist_property->second).p;
1061+
DATA_INVARIANT(
1062+
netlist_property->second.id() == ID_sva_always,
1063+
"assumed property must be sva_always");
1064+
auto &p = to_sva_always_expr(netlist_property->second).op();
1065+
DATA_INVARIANT(
1066+
p.id() == ID_literal,
1067+
"assumed property must be sva_assume sva_assert literal");
1068+
auto l = to_literal_expr(p).get_literal();
10611069
constraints_BDDs.push_back(aig2bdd(l, BDDs));
10621070
}
10631071
}

src/temporal-logic/temporal_logic.cpp

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,8 @@ Author: Daniel Kroening, [email protected]
1010

1111
#include <util/expr_util.h>
1212

13+
#include <verilog/sva_expr.h>
14+
1315
bool is_temporal_operator(const exprt &expr)
1416
{
1517
return is_CTL_operator(expr) || is_LTL_operator(expr) ||
@@ -136,3 +138,17 @@ bool is_SVA(const exprt &expr)
136138

137139
return !has_subexpr(expr, non_SVA_operator);
138140
}
141+
142+
bool is_SVA_always_p(const exprt &expr)
143+
{
144+
return expr.id() == ID_sva_always &&
145+
!has_temporal_operator(to_sva_always_expr(expr).op());
146+
}
147+
148+
bool is_SVA_always_s_eventually_p(const exprt &expr)
149+
{
150+
return expr.id() == ID_sva_always &&
151+
to_sva_always_expr(expr).op().id() == ID_sva_s_eventually &&
152+
!has_temporal_operator(
153+
to_sva_s_eventually_expr(to_sva_always_expr(expr).op()).op());
154+
}

src/temporal-logic/temporal_logic.h

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -71,4 +71,10 @@ bool is_SVA_operator(const exprt &);
7171
/// Returns true iff the given expression is an SVA expression
7272
bool is_SVA(const exprt &);
7373

74+
/// Returns true iff the given expression is always p
75+
bool is_SVA_always_p(const exprt &);
76+
77+
/// Returns true iff the given expression is always s_eventually p
78+
bool is_SVA_always_s_eventually_p(const exprt &);
79+
7480
#endif

src/trans-netlist/instantiate_netlist.cpp

Lines changed: 85 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,8 @@ Author: Daniel Kroening, [email protected]
1414

1515
#include <ebmc/ebmc_error.h>
1616
#include <solvers/flattening/boolbv.h>
17+
#include <solvers/prop/literal_expr.h>
18+
#include <temporal-logic/temporal_logic.h>
1719
#include <verilog/sva_expr.h>
1820

1921
#include <cassert>
@@ -272,3 +274,86 @@ literalt instantiate_var_mapt::get_literal(
272274
return var_map.get_current(symbol, bit);
273275
}
274276

277+
/*******************************************************************\
278+
279+
Function: netlist_property
280+
281+
Inputs:
282+
283+
Outputs:
284+
285+
Purpose:
286+
287+
\*******************************************************************/
288+
289+
std::optional<exprt> netlist_property(
290+
propt &solver,
291+
const var_mapt &var_map,
292+
const exprt &expr,
293+
const namespacet &ns,
294+
message_handlert &message_handler)
295+
{
296+
if(is_temporal_operator(expr))
297+
{
298+
if(is_LTL_operator(expr) || is_CTL_operator(expr))
299+
{
300+
exprt copy = expr;
301+
for(auto &op : copy.operands())
302+
{
303+
auto op_opt =
304+
netlist_property(solver, var_map, op, ns, message_handler);
305+
if(op_opt.has_value())
306+
op = op_opt.value();
307+
else
308+
return {};
309+
}
310+
return copy;
311+
}
312+
else if(is_SVA_operator(expr))
313+
{
314+
if(expr.id() == ID_sva_always || expr.id() == ID_sva_assume)
315+
{
316+
auto copy = expr;
317+
auto &op = to_unary_expr(copy).op();
318+
auto op_opt =
319+
netlist_property(solver, var_map, op, ns, message_handler);
320+
if(op_opt.has_value())
321+
{
322+
op = op_opt.value();
323+
return copy;
324+
}
325+
else
326+
return {};
327+
}
328+
else
329+
return {};
330+
}
331+
else
332+
return {};
333+
}
334+
else if(!has_temporal_operator(expr))
335+
{
336+
auto l = instantiate_convert(solver, var_map, expr, ns, message_handler);
337+
return literal_exprt{l};
338+
}
339+
else if(
340+
expr.id() == ID_and || expr.id() == ID_or || expr.id() == ID_not ||
341+
expr.id() == ID_implies || expr.id() == ID_xor || expr.id() == ID_xnor)
342+
{
343+
exprt copy = expr;
344+
for(auto &op : copy.operands())
345+
{
346+
auto op_opt = netlist_property(solver, var_map, op, ns, message_handler);
347+
if(op_opt.has_value())
348+
op = op_opt.value();
349+
else
350+
return {};
351+
}
352+
return copy;
353+
}
354+
else
355+
{
356+
// contains temporal operator, but not propositional skeleton
357+
return {};
358+
}
359+
}

src/trans-netlist/instantiate_netlist.h

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,14 @@ literalt instantiate_convert(
3030
const exprt &expr,
3131
const namespacet &,
3232
message_handlert &);
33-
33+
34+
std::optional<exprt> netlist_property(
35+
propt &solver,
36+
const var_mapt &var_map,
37+
const exprt &expr,
38+
const namespacet &,
39+
message_handlert &);
40+
3441
void instantiate_convert(
3542
propt &solver,
3643
const var_mapt &var_map,

src/trans-netlist/netlist.cpp

Lines changed: 77 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -6,11 +6,19 @@ Author: Daniel Kroening, [email protected]
66
77
\*******************************************************************/
88

9-
#include <ctype.h>
9+
#include "netlist.h"
10+
11+
#include <util/namespace.h>
12+
#include <util/symbol_table.h>
1013

14+
#include <smvlang/expr2smv.h>
1115
#include <solvers/flattening/boolbv_width.h>
16+
#include <solvers/prop/literal_expr.h>
17+
#include <temporal-logic/temporal_logic.h>
18+
#include <verilog/sva_expr.h>
1219

13-
#include "netlist.h"
20+
#include <ctype.h>
21+
#include <sstream>
1422

1523
/*******************************************************************\
1624
@@ -352,30 +360,54 @@ void netlistt::output_smv(std::ostream &out) const
352360
out << "-- Properties" << '\n';
353361
out << '\n';
354362

355-
for(auto &[id, property] : properties)
363+
for(auto &[id, netlist_expr] : properties)
356364
{
357-
if(std::holds_alternative<Gpt>(property))
365+
if(is_CTL(netlist_expr))
358366
{
359367
out << "-- " << id << '\n';
360-
out << "LTLSPEC G ";
361-
print_smv(out, std::get<Gpt>(property).p);
368+
out << "CTLSPEC ";
369+
print_smv(out, netlist_expr);
362370
out << '\n';
363371
}
364-
else if(std::holds_alternative<GFpt>(property))
372+
else if(is_LTL(netlist_expr))
365373
{
366374
out << "-- " << id << '\n';
367-
out << "LTLSPEC G F ";
368-
print_smv(out, std::get<GFpt>(property).p);
375+
out << "LTLSPEC ";
376+
print_smv(out, netlist_expr);
369377
out << '\n';
370378
}
371-
else if(std::holds_alternative<not_translatedt>(property))
379+
else if(is_SVA(netlist_expr))
380+
{
381+
if(is_SVA_always_p(netlist_expr))
382+
{
383+
out << "-- " << id << '\n';
384+
out << "CTLSPEC AG ";
385+
print_smv(out, to_sva_always_expr(netlist_expr).op());
386+
out << '\n';
387+
}
388+
else if(is_SVA_always_s_eventually_p(netlist_expr))
389+
{
390+
out << "-- " << id << '\n';
391+
out << "CTLSPEC AG AF ";
392+
print_smv(
393+
out,
394+
to_sva_s_eventually_expr(to_sva_always_expr(netlist_expr).op()).op());
395+
out << '\n';
396+
}
397+
else
398+
{
399+
out << "-- " << id << '\n';
400+
out << "-- not translated\n";
401+
out << '\n';
402+
}
403+
}
404+
else
372405
{
406+
// neither LTL nor CTL nor SVA
373407
out << "-- " << id << '\n';
374408
out << "-- not translated\n";
375409
out << '\n';
376410
}
377-
else
378-
UNREACHABLE;
379411
}
380412
}
381413

@@ -467,3 +499,36 @@ void netlistt::print_smv(
467499
out << "unknown";
468500
}
469501

502+
/*******************************************************************\
503+
504+
Function: netlistt::print_smv
505+
506+
Inputs:
507+
508+
Outputs:
509+
510+
Purpose:
511+
512+
\*******************************************************************/
513+
514+
void netlistt::print_smv(std::ostream &out, const exprt &expr) const
515+
{
516+
symbol_tablet symbol_table;
517+
namespacet ns{symbol_table};
518+
519+
// replace literal expressions by symbols
520+
521+
exprt replaced = expr;
522+
replaced.visit_pre(
523+
[this](exprt &node)
524+
{
525+
if(node.id() == ID_literal)
526+
{
527+
std::ostringstream buffer;
528+
print_smv(buffer, to_literal_expr(node).get_literal());
529+
node = symbol_exprt{buffer.str(), node.type()};
530+
}
531+
});
532+
533+
out << expr2smv(replaced, ns);
534+
}

src/trans-netlist/netlist.h

Lines changed: 7 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,8 @@ Author: Daniel Kroening, [email protected]
99
#ifndef CPROVER_TRANS_NETLIST_H
1010
#define CPROVER_TRANS_NETLIST_H
1111

12+
#include <util/expr.h>
13+
1214
#include "aig.h"
1315
#include "var_map.h"
1416

@@ -53,29 +55,15 @@ class netlistt:public aig_plus_constraintst
5355
bvt initial;
5456
bvt transition;
5557

56-
struct Gpt
57-
{
58-
literalt p;
59-
};
60-
61-
struct GFpt
62-
{
63-
literalt p;
64-
};
65-
66-
struct not_translatedt
67-
{
68-
};
69-
70-
using propertyt = std::variant<Gpt, GFpt, not_translatedt>;
71-
72-
// map from property ID to property netlist nodes
73-
using propertiest = std::map<irep_idt, propertyt>;
58+
// Map from property ID to a netlist property,
59+
// which uses literal_exprt.
60+
using propertiest = std::map<irep_idt, exprt>;
7461
propertiest properties;
7562

7663
protected:
7764
static std::string id2smv(const irep_idt &id);
78-
void print_smv(std::ostream &out, literalt l) const;
65+
void print_smv(std::ostream &, literalt) const;
66+
void print_smv(std::ostream &, const exprt &) const;
7967
};
8068

8169
#endif

0 commit comments

Comments
 (0)