Skip to content

introduce sva_boolean_exprt #1083

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
May 13, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 12 additions & 4 deletions src/ebmc/completeness_threshold.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -68,10 +68,18 @@ bool has_low_completeness_threshold(const exprt &expr)
expr.id() == ID_sva_implicit_strong || expr.id() == ID_sva_implicit_weak)
{
auto &sequence = to_sva_sequence_property_expr_base(expr).sequence();
if(!is_SVA_sequence_operator(sequence))
return true;
else
return false;
return has_low_completeness_threshold(sequence);
}
else if(expr.id() == ID_sva_boolean)
{
return true;
}
else if(expr.id() == ID_sva_or || expr.id() == ID_sva_and)
{
for(auto &op : expr.operands())
if(!has_low_completeness_threshold(op))
return false;
return true;
}
else if(expr.id() == ID_sva_sequence_property)
{
Expand Down
1 change: 1 addition & 0 deletions src/hw_cbmc_irep_ids.h
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,7 @@ IREP_ID_ONE(smv_EBG)
IREP_ID_ONE(smv_ABG)
IREP_ID_ONE(smv_ABU)
IREP_ID_ONE(smv_EBU)
IREP_ID_ONE(sva_boolean)
IREP_ID_ONE(sva_accept_on)
IREP_ID_ONE(sva_reject_on)
IREP_ID_ONE(sva_sync_accept_on)
Expand Down
18 changes: 18 additions & 0 deletions src/temporal-logic/nnf.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -149,6 +149,24 @@ std::optional<exprt> negate_property_node(const exprt &expr)
return sva_non_overlapped_implication_exprt{
followed_by.antecedent(), not_b};
}
else if(expr.id() == ID_sva_overlapped_implication)
{
// 1800 2017 16.12.9
// !(a |-> b) ---> a #-# !b
auto &implication = to_sva_implication_base_expr(expr);
auto not_b = not_exprt{implication.consequent()};
return sva_followed_by_exprt{
implication.antecedent(), ID_sva_overlapped_followed_by, not_b};
}
else if(expr.id() == ID_sva_non_overlapped_implication)
{
// 1800 2017 16.12.9
// !(a |=> b) ---> a #=# !b
auto &implication = to_sva_implication_base_expr(expr);
auto not_b = not_exprt{implication.consequent()};
return sva_followed_by_exprt{
implication.antecedent(), ID_sva_nonoverlapped_followed_by, not_b};
}
else
return {};
}
Expand Down
25 changes: 22 additions & 3 deletions src/temporal-logic/normalize_property.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -23,12 +23,26 @@ Author: Daniel Kroening, [email protected]
exprt normalize_pre_sva_non_overlapped_implication(
sva_non_overlapped_implication_exprt expr)
{
// Same as a->always[1:1] b if lhs is not a sequence.
if(!is_SVA_sequence_operator(expr.lhs()))
// a|=>b is the same as a->always[1:1] b if lhs is not a proper sequence.
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What is the difference between a sequence and a "proper" sequence?

if(expr.lhs().id() == ID_sva_boolean)
{
const auto &lhs_cond = to_sva_boolean_expr(expr.lhs()).op();
auto one = natural_typet{}.one_expr();
return or_exprt{
not_exprt{expr.lhs()}, sva_ranged_always_exprt{one, one, expr.rhs()}};
not_exprt{lhs_cond}, sva_ranged_always_exprt{one, one, expr.rhs()}};
}
else
return std::move(expr);
}

exprt normalize_pre_sva_overlapped_implication(
sva_overlapped_implication_exprt expr)
{
// a|->b is the same as a->b if lhs is not a proper sequence.
if(expr.lhs().id() == ID_sva_boolean)
{
const auto &lhs_cond = to_sva_boolean_expr(expr.lhs()).op();
return implies_exprt{lhs_cond, expr.rhs()};
}
else
return std::move(expr);
Expand All @@ -42,6 +56,11 @@ exprt normalize_property_rec(exprt expr)
expr = normalize_pre_sva_non_overlapped_implication(
to_sva_non_overlapped_implication_expr(expr));
}
else if(expr.id() == ID_sva_overlapped_implication)
{
expr = normalize_pre_sva_overlapped_implication(
to_sva_overlapped_implication_expr(expr));
}
else if(expr.id() == ID_sva_nexttime)
{
auto one = natural_typet{}.one_expr();
Expand Down
5 changes: 2 additions & 3 deletions src/temporal-logic/normalize_property.h
Original file line number Diff line number Diff line change
Expand Up @@ -13,15 +13,14 @@ Author: Daniel Kroening, [email protected]

/// This applies the following rewrites:
///
/// cover(φ) --> G¬φ
///
/// -----Propositional-----
/// ¬(a ∨ b) --> ¬a ∧ ¬b
/// ¬(a ∧ b) --> ¬a ∨ ¬b
/// (a -> b) --> ¬a ∨ b
///
/// -----SVA-----
/// sva_non_overlapped_implication --> ¬a ∨ always[1:1] b if a is not an SVA sequence
/// a|=>b --> ¬a ∨ always[1:1] b if a is not an SVA sequence
/// a|->b --> a⇒b if a is not an SVA sequence
/// sva_nexttime φ --> sva_always[1:1] φ
/// sva_nexttime[i] φ --> sva_always[i:i] φ
/// sva_s_nexttime φ --> sva_always[1:1] φ
Expand Down
4 changes: 2 additions & 2 deletions src/temporal-logic/sva_to_ltl.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -42,10 +42,10 @@ struct ltl_sequence_matcht

std::vector<ltl_sequence_matcht> LTL_sequence_matches(const exprt &sequence)
{
if(!is_SVA_sequence_operator(sequence))
if(sequence.id() == ID_sva_boolean)
{
// atomic proposition
return {{sequence, 1}};
return {{to_sva_boolean_expr(sequence).op(), 1}};
}
else if(sequence.id() == ID_sva_sequence_concatenation)
{
Expand Down
59 changes: 37 additions & 22 deletions src/temporal-logic/trivial_sva.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -12,12 +12,10 @@ Author: Daniel Kroening, [email protected]

#include "temporal_logic.h"

static std::optional<exprt> is_state_formula(const exprt &expr)
static std::optional<exprt> is_state_predicate(const exprt &expr)
{
if(expr.id() == ID_typecast && expr.type().id() == ID_verilog_sva_sequence)
return to_typecast_expr(expr).op();
else if(expr.type().id() == ID_bool)
return expr;
if(expr.id() == ID_sva_boolean)
return to_sva_boolean_expr(expr).op();
else
return {};
}
Expand All @@ -30,8 +28,8 @@ exprt trivial_sva(exprt expr)
// Same as regular implication if lhs and rhs are not sequences.
auto &sva_implication = to_sva_overlapped_implication_expr(expr);

auto lhs = is_state_formula(sva_implication.lhs());
auto rhs = is_state_formula(sva_implication.rhs());
auto lhs = is_state_predicate(sva_implication.lhs());
auto rhs = is_state_predicate(sva_implication.rhs());

if(lhs.has_value() && rhs.has_value())
expr = implies_exprt{*lhs, *rhs};
Expand All @@ -50,23 +48,39 @@ exprt trivial_sva(exprt expr)
{
auto &sva_and = to_sva_and_expr(expr);

// Same as a ∧ b if the expression is not a sequence.
auto lhs = is_state_formula(sva_and.lhs());
auto rhs = is_state_formula(sva_and.rhs());

if(lhs.has_value() && rhs.has_value())
expr = and_exprt{*lhs, *rhs};
// can be sequence or property
if(expr.type().id() == ID_verilog_sva_sequence)
{
// Same as a ∧ b if the expression is not a sequence.
auto lhs = is_state_predicate(sva_and.lhs());
auto rhs = is_state_predicate(sva_and.rhs());

if(lhs.has_value() && rhs.has_value())
expr = sva_boolean_exprt{and_exprt{*lhs, *rhs}, expr.type()};
}
else
{
expr = and_exprt{sva_and.lhs(), sva_and.rhs()};
}
}
else if(expr.id() == ID_sva_or)
{
auto &sva_or = to_sva_or_expr(expr);

// Same as a ∨ b if the expression is not a sequence.
auto lhs = is_state_formula(sva_or.lhs());
auto rhs = is_state_formula(sva_or.rhs());

if(lhs.has_value() && rhs.has_value())
expr = or_exprt{*lhs, *rhs};
// can be sequence or property
if(expr.type().id() == ID_verilog_sva_sequence)
{
// Same as a ∨ b if the expression is not a sequence.
auto lhs = is_state_predicate(sva_or.lhs());
auto rhs = is_state_predicate(sva_or.rhs());

if(lhs.has_value() && rhs.has_value())
expr = sva_boolean_exprt{or_exprt{*lhs, *rhs}, expr.type()};
}
else
{
expr = or_exprt{sva_or.lhs(), sva_or.rhs()};
}
}
else if(expr.id() == ID_sva_not)
{
Expand Down Expand Up @@ -113,9 +127,10 @@ exprt trivial_sva(exprt expr)
{
// We simplify sequences to boolean expressions, and hence can drop
// the sva_sequence_property converter
auto &op = to_sva_sequence_property_expr_base(expr).sequence();
if(op.type().id() == ID_bool)
return op;
auto &sequence = to_sva_sequence_property_expr_base(expr).sequence();
auto pred_opt = is_state_predicate(sequence);
if(pred_opt.has_value())
return *pred_opt;
}

return expr;
Expand Down
12 changes: 9 additions & 3 deletions src/trans-word-level/sequence.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -454,10 +454,16 @@ sequence_matchest instantiate_sequence(

return result;
}
else
else if(expr.id() == ID_sva_boolean)
{
// not a sequence, evaluate as state predicate
auto instantiated = instantiate_property(expr, t, no_timeframes);
// a state predicate
auto &predicate = to_sva_boolean_expr(expr).op();
auto instantiated = instantiate_property(predicate, t, no_timeframes);
return {{instantiated.first, instantiated.second}};
}
else
{
DATA_INVARIANT_WITH_DIAGNOSTICS(
false, "unexpected sequence expression", expr.pretty());
}
}
6 changes: 6 additions & 0 deletions src/verilog/expr2verilog.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1815,6 +1815,12 @@ expr2verilogt::resultt expr2verilogt::convert_rec(const exprt &src)
return convert_rec(to_sva_sequence_property_expr_base(src).sequence());
}

else if(src.id() == ID_sva_boolean)
{
// These are invisible
return convert_rec(to_sva_boolean_expr(src).op());
}

else if(src.id()==ID_sva_sequence_concatenation)
return convert_sva_sequence_concatenation(
to_binary_expr(src), precedence = verilog_precedencet::MIN);
Expand Down
23 changes: 23 additions & 0 deletions src/verilog/sva_expr.h
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,29 @@ Author: Daniel Kroening, [email protected]

#include "verilog_types.h"

/// 1800-2017 16.6 Boolean expressions
/// Conversion of a Boolean expression into a sequence or property
class sva_boolean_exprt : public unary_exprt
{
public:
sva_boolean_exprt(exprt condition, typet __type)
: unary_exprt(ID_sva_boolean, std::move(condition), std::move(__type))
{
}
};

static inline const sva_boolean_exprt &to_sva_boolean_expr(const exprt &expr)
{
sva_boolean_exprt::check(expr, validation_modet::INVARIANT);
return static_cast<const sva_boolean_exprt &>(expr);
}

static inline sva_boolean_exprt &to_sva_boolean_expr(exprt &expr)
{
sva_boolean_exprt::check(expr, validation_modet::INVARIANT);
return static_cast<sva_boolean_exprt &>(expr);
}

/// accept_on, reject_on, sync_accept_on, sync_reject_on, disable_iff
class sva_abort_exprt : public binary_predicate_exprt
{
Expand Down
3 changes: 2 additions & 1 deletion src/verilog/verilog_typecheck_sva.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -35,8 +35,9 @@ void verilog_typecheck_exprt::require_sva_sequence(exprt &expr)
}
else
{
// state formula, can cast to sequence
// state formula, can convert to sequence
make_boolean(expr);
expr = sva_boolean_exprt{std::move(expr), verilog_sva_sequence_typet{}};
}
}
else
Expand Down
Loading