From 7b91923d1a0e824880356f925e2bb93d6d37a55c Mon Sep 17 00:00:00 2001 From: Daniel Kroening Date: Wed, 23 Apr 2025 09:22:33 -0700 Subject: [PATCH 1/2] introduce verilog_sva_property_typet This introduces a type for Verilog SVA properties to distinguish properties from state predicates and sequences. --- src/hw_cbmc_irep_ids.h | 1 + src/temporal-logic/normalize_property.cpp | 2 +- src/temporal-logic/trivial_sva.cpp | 2 +- src/trans-word-level/property.cpp | 9 +- src/verilog/sva_expr.cpp | 4 +- src/verilog/sva_expr.h | 161 ++++++++++++++-------- src/verilog/verilog_typecheck_sva.cpp | 33 +++-- src/verilog/verilog_types.h | 9 ++ 8 files changed, 142 insertions(+), 79 deletions(-) diff --git a/src/hw_cbmc_irep_ids.h b/src/hw_cbmc_irep_ids.h index 399325f7d..34bf8d86c 100644 --- a/src/hw_cbmc_irep_ids.h +++ b/src/hw_cbmc_irep_ids.h @@ -140,6 +140,7 @@ IREP_ID_ONE(verilog_null) IREP_ID_ONE(verilog_event) IREP_ID_ONE(verilog_event_trigger) IREP_ID_ONE(verilog_string) +IREP_ID_ONE(verilog_sva_property) IREP_ID_ONE(verilog_sva_sequence) IREP_ID_ONE(reg) IREP_ID_ONE(macromodule) diff --git a/src/temporal-logic/normalize_property.cpp b/src/temporal-logic/normalize_property.cpp index 4caaafce2..f6945f114 100644 --- a/src/temporal-logic/normalize_property.cpp +++ b/src/temporal-logic/normalize_property.cpp @@ -105,7 +105,7 @@ exprt normalize_property(exprt expr) { // top-level only if(expr.id() == ID_sva_cover) - expr = sva_always_exprt{not_exprt{to_sva_cover_expr(expr).op()}}; + expr = sva_always_exprt{sva_not_exprt{to_sva_cover_expr(expr).op()}}; expr = trivial_sva(expr); diff --git a/src/temporal-logic/trivial_sva.cpp b/src/temporal-logic/trivial_sva.cpp index 242cc22b2..62cf435d8 100644 --- a/src/temporal-logic/trivial_sva.cpp +++ b/src/temporal-logic/trivial_sva.cpp @@ -84,7 +84,7 @@ exprt trivial_sva(exprt expr) } else if(expr.id() == ID_sva_not) { - // Same as regular 'not'. These do not apply to sequences. + // Same as boolean 'not'. These do not apply to sequences. expr = not_exprt{to_sva_not_expr(expr).op()}; } else if(expr.id() == ID_sva_if) diff --git a/src/trans-word-level/property.cpp b/src/trans-word-level/property.cpp index ab63e691d..cfbaa563e 100644 --- a/src/trans-word-level/property.cpp +++ b/src/trans-word-level/property.cpp @@ -530,10 +530,10 @@ static obligationst property_obligations_rec( return property_obligations_rec( to_typecast_expr(property_expr).op(), current, no_timeframes); } - else if(property_expr.id() == ID_not) + else if(property_expr.id() == ID_sva_not) { // We need NNF, try to eliminate the negation. - auto &op = to_not_expr(property_expr).op(); + auto &op = to_sva_not_expr(property_expr).op(); auto op_negated_opt = negate_property_node(op); @@ -570,8 +570,9 @@ static obligationst property_obligations_rec( else { // state formula - return obligationst{ - current, instantiate_property(property_expr, current, no_timeframes)}; + auto sampled = + instantiate_property(not_exprt{op}, current, no_timeframes); + return obligationst{current, sampled}; } } else if(property_expr.id() == ID_sva_implies) diff --git a/src/verilog/sva_expr.cpp b/src/verilog/sva_expr.cpp index 613007d10..3cd641747 100644 --- a/src/verilog/sva_expr.cpp +++ b/src/verilog/sva_expr.cpp @@ -118,7 +118,9 @@ exprt sva_sequence_repetition_star_exprt::lower() const { auto n_expr = from_integer(n, integer_typet{}); result = sva_or_exprt{ - std::move(result), sva_sequence_repetition_star_exprt{op(), n_expr}}; + std::move(result), + sva_sequence_repetition_star_exprt{op(), n_expr}, + verilog_sva_sequence_typet{}}; } return result; diff --git a/src/verilog/sva_expr.h b/src/verilog/sva_expr.h index 436005349..4c95d4262 100644 --- a/src/verilog/sva_expr.h +++ b/src/verilog/sva_expr.h @@ -37,11 +37,15 @@ static inline sva_boolean_exprt &to_sva_boolean_expr(exprt &expr) } /// accept_on, reject_on, sync_accept_on, sync_reject_on, disable_iff -class sva_abort_exprt : public binary_predicate_exprt +class sva_abort_exprt : public binary_exprt { public: sva_abort_exprt(irep_idt id, exprt condition, exprt property) - : binary_predicate_exprt(std::move(condition), id, std::move(property)) + : binary_exprt( + std::move(condition), + id, + std::move(property), + verilog_sva_property_typet{}) { } @@ -66,8 +70,8 @@ class sva_abort_exprt : public binary_predicate_exprt } protected: - using binary_predicate_exprt::op0; - using binary_predicate_exprt::op1; + using binary_exprt::op0; + using binary_exprt::op1; }; static inline const sva_abort_exprt &to_sva_abort_expr(const exprt &expr) @@ -110,11 +114,11 @@ static inline sva_disable_iff_exprt &to_sva_disable_iff_expr(exprt &expr) } /// nonindexed variant -class sva_nexttime_exprt : public unary_predicate_exprt +class sva_nexttime_exprt : public unary_exprt { public: explicit sva_nexttime_exprt(exprt op) - : unary_predicate_exprt(ID_sva_nexttime, std::move(op)) + : unary_exprt(ID_sva_nexttime, std::move(op), verilog_sva_property_typet{}) { } }; @@ -134,11 +138,14 @@ static inline sva_nexttime_exprt &to_sva_nexttime_expr(exprt &expr) } /// nonindexed variant -class sva_s_nexttime_exprt : public unary_predicate_exprt +class sva_s_nexttime_exprt : public unary_exprt { public: explicit sva_s_nexttime_exprt(exprt op) - : unary_predicate_exprt(ID_sva_s_nexttime, std::move(op)) + : unary_exprt( + ID_sva_s_nexttime, + std::move(op), + verilog_sva_property_typet{}) { } }; @@ -159,14 +166,15 @@ static inline sva_s_nexttime_exprt &to_sva_s_nexttime_expr(exprt &expr) } /// indexed variant of sva_nexttime_exprt -class sva_indexed_nexttime_exprt : public binary_predicate_exprt +class sva_indexed_nexttime_exprt : public binary_exprt { public: sva_indexed_nexttime_exprt(constant_exprt index, exprt op) - : binary_predicate_exprt( + : binary_exprt( std::move(index), ID_sva_indexed_nexttime, - std::move(op)) + std::move(op), + verilog_sva_property_typet{}) { } @@ -191,8 +199,8 @@ class sva_indexed_nexttime_exprt : public binary_predicate_exprt } protected: - using binary_predicate_exprt::op0; - using binary_predicate_exprt::op1; + using binary_exprt::op0; + using binary_exprt::op1; }; static inline const sva_indexed_nexttime_exprt & @@ -212,14 +220,15 @@ to_sva_indexed_nexttime_expr(exprt &expr) } /// indexed variant of sva_s_nexttime_exprt -class sva_indexed_s_nexttime_exprt : public binary_predicate_exprt +class sva_indexed_s_nexttime_exprt : public binary_exprt { public: sva_indexed_s_nexttime_exprt(constant_exprt index, exprt op) - : binary_predicate_exprt( + : binary_exprt( std::move(index), ID_sva_indexed_s_nexttime, - std::move(op)) + std::move(op), + verilog_sva_property_typet{}) { } @@ -244,8 +253,8 @@ class sva_indexed_s_nexttime_exprt : public binary_predicate_exprt } protected: - using binary_predicate_exprt::op0; - using binary_predicate_exprt::op1; + using binary_exprt::op0; + using binary_exprt::op1; }; static inline const sva_indexed_s_nexttime_exprt & @@ -280,7 +289,7 @@ class sva_ranged_predicate_exprt : public ternary_exprt std::move(__from), std::move(__to), std::move(__op), - bool_typet{}) + verilog_sva_property_typet{}) { } @@ -402,11 +411,14 @@ static inline sva_eventually_exprt &to_sva_eventually_expr(exprt &expr) return static_cast(expr); } -class sva_s_eventually_exprt : public unary_predicate_exprt +class sva_s_eventually_exprt : public unary_exprt { public: explicit sva_s_eventually_exprt(exprt op) - : unary_predicate_exprt(ID_sva_s_eventually, std::move(op)) + : unary_exprt( + ID_sva_s_eventually, + std::move(op), + verilog_sva_property_typet{}) { } }; @@ -458,11 +470,11 @@ to_sva_ranged_s_eventually_expr(exprt &expr) return static_cast(expr); } -class sva_always_exprt : public unary_predicate_exprt +class sva_always_exprt : public unary_exprt { public: explicit sva_always_exprt(exprt op) - : unary_predicate_exprt(ID_sva_always, std::move(op)) + : unary_exprt(ID_sva_always, std::move(op), verilog_sva_property_typet{}) { } }; @@ -536,11 +548,11 @@ static inline sva_s_always_exprt &to_sva_s_always_expr(exprt &expr) return static_cast(expr); } -class sva_cover_exprt : public unary_predicate_exprt +class sva_cover_exprt : public unary_exprt { public: explicit sva_cover_exprt(exprt op) - : unary_predicate_exprt(ID_sva_cover, std::move(op)) + : unary_exprt(ID_sva_cover, std::move(op), verilog_sva_property_typet{}) { } }; @@ -559,11 +571,11 @@ static inline sva_cover_exprt &to_sva_cover_expr(exprt &expr) return static_cast(expr); } -class sva_assume_exprt : public unary_predicate_exprt +class sva_assume_exprt : public unary_exprt { public: explicit sva_assume_exprt(exprt op) - : unary_predicate_exprt(ID_sva_assume, std::move(op)) + : unary_exprt(ID_sva_assume, std::move(op), verilog_sva_property_typet{}) { } }; @@ -582,11 +594,15 @@ static inline sva_assume_exprt &to_sva_assume_expr(exprt &expr) return static_cast(expr); } -class sva_until_exprt : public binary_predicate_exprt +class sva_until_exprt : public binary_exprt { public: explicit sva_until_exprt(exprt op0, exprt op1) - : binary_predicate_exprt(std::move(op0), ID_sva_until, std::move(op1)) + : binary_exprt( + std::move(op0), + ID_sva_until, + std::move(op1), + verilog_sva_property_typet{}) { } }; @@ -605,11 +621,15 @@ static inline sva_until_exprt &to_sva_until_expr(exprt &expr) return static_cast(expr); } -class sva_s_until_exprt : public binary_predicate_exprt +class sva_s_until_exprt : public binary_exprt { public: explicit sva_s_until_exprt(exprt op0, exprt op1) - : binary_predicate_exprt(std::move(op0), ID_sva_s_until, std::move(op1)) + : binary_exprt( + std::move(op0), + ID_sva_s_until, + std::move(op1), + verilog_sva_property_typet{}) { } }; @@ -629,11 +649,15 @@ static inline sva_s_until_exprt &to_sva_s_until_expr(exprt &expr) } /// SVA until_with operator -- like LTL (weak) R, but lhs/rhs swapped -class sva_until_with_exprt : public binary_predicate_exprt +class sva_until_with_exprt : public binary_exprt { public: explicit sva_until_with_exprt(exprt op0, exprt op1) - : binary_predicate_exprt(std::move(op0), ID_sva_until_with, std::move(op1)) + : binary_exprt( + std::move(op0), + ID_sva_until_with, + std::move(op1), + verilog_sva_property_typet{}) { } }; @@ -654,14 +678,15 @@ static inline sva_until_with_exprt &to_sva_until_with_expr(exprt &expr) } /// SVA s_until_with operator -- like LTL strong R, but lhs/rhs swapped -class sva_s_until_with_exprt : public binary_predicate_exprt +class sva_s_until_with_exprt : public binary_exprt { public: explicit sva_s_until_with_exprt(exprt op0, exprt op1) - : binary_predicate_exprt( + : binary_exprt( std::move(op0), ID_sva_s_until_with, - std::move(op1)) + std::move(op1), + verilog_sva_property_typet{}) { } }; @@ -682,17 +707,18 @@ static inline sva_s_until_with_exprt &to_sva_s_until_with_expr(exprt &expr) } /// base class for |->, |=>, #-#, #=# -class sva_implication_base_exprt : public binary_predicate_exprt +class sva_implication_base_exprt : public binary_exprt { public: explicit sva_implication_base_exprt( exprt __antecedent, irep_idt __id, exprt __consequent) - : binary_predicate_exprt( + : binary_exprt( std::move(__antecedent), __id, - std::move(__consequent)) + std::move(__consequent), + verilog_sva_property_typet{}) { } @@ -815,11 +841,11 @@ to_sva_non_overlapped_implication_expr(exprt &expr) return static_cast(expr); } -class sva_not_exprt : public unary_predicate_exprt +class sva_not_exprt : public unary_exprt { public: explicit sva_not_exprt(exprt op) - : unary_predicate_exprt(ID_sva_not, std::move(op)) + : unary_exprt(ID_sva_not, std::move(op), verilog_sva_property_typet{}) { } }; @@ -838,11 +864,16 @@ static inline sva_not_exprt &to_sva_not_expr(exprt &expr) return static_cast(expr); } -class sva_and_exprt : public binary_predicate_exprt +class sva_and_exprt : public binary_exprt { public: - explicit sva_and_exprt(exprt op0, exprt op1) - : binary_predicate_exprt(std::move(op0), ID_sva_and, std::move(op1)) + // can be a sequence or property, depending on operands + explicit sva_and_exprt(exprt op0, exprt op1, typet __type) + : binary_exprt( + std::move(op0), + ID_sva_and, + std::move(op1), + std::move(__type)) { } }; @@ -890,11 +921,15 @@ to_sva_sequence_concatenation_expr(exprt &expr) return static_cast(expr); } -class sva_iff_exprt : public binary_predicate_exprt +class sva_iff_exprt : public binary_exprt { public: explicit sva_iff_exprt(exprt op0, exprt op1) - : binary_predicate_exprt(std::move(op0), ID_sva_iff, std::move(op1)) + : binary_exprt( + std::move(op0), + ID_sva_iff, + std::move(op1), + verilog_sva_property_typet{}) { } }; @@ -913,11 +948,15 @@ static inline sva_iff_exprt &to_sva_iff_expr(exprt &expr) return static_cast(expr); } -class sva_implies_exprt : public binary_predicate_exprt +class sva_implies_exprt : public binary_exprt { public: explicit sva_implies_exprt(exprt op0, exprt op1) - : binary_predicate_exprt(std::move(op0), ID_sva_implies, std::move(op1)) + : binary_exprt( + std::move(op0), + ID_sva_implies, + std::move(op1), + verilog_sva_property_typet{}) { } }; @@ -936,11 +975,12 @@ static inline sva_implies_exprt &to_sva_implies_expr(exprt &expr) return static_cast(expr); } -class sva_or_exprt : public binary_predicate_exprt +class sva_or_exprt : public binary_exprt { public: - explicit sva_or_exprt(exprt op0, exprt op1) - : binary_predicate_exprt(std::move(op0), ID_sva_or, std::move(op1)) + // These can be sequences or properties, depending on the operands + explicit sva_or_exprt(exprt op0, exprt op1, typet __type) + : binary_exprt(std::move(op0), ID_sva_or, std::move(op1), std::move(__type)) { } }; @@ -1155,7 +1195,7 @@ class sva_if_exprt : public ternary_exprt std::move(__cond), std::move(__true_case), std::move(__false_case), - bool_typet()) + verilog_sva_property_typet{}) { } @@ -1212,11 +1252,11 @@ static inline sva_if_exprt &to_sva_if_expr(exprt &expr) /// Base class for sequence property expressions. /// 1800-2017 16.12.2 Sequence property -class sva_sequence_property_expr_baset : public unary_predicate_exprt +class sva_sequence_property_expr_baset : public unary_exprt { public: sva_sequence_property_expr_baset(irep_idt __id, exprt __op) - : unary_predicate_exprt(__id, std::move(__op)) + : unary_exprt(__id, std::move(__op), verilog_sva_property_typet{}) { } @@ -1231,7 +1271,7 @@ class sva_sequence_property_expr_baset : public unary_predicate_exprt } protected: - using unary_predicate_exprt::op; + using unary_exprt::op; }; inline const sva_sequence_property_expr_baset & @@ -1296,14 +1336,15 @@ inline sva_weak_exprt &to_sva_weak_expr(exprt &expr) return static_cast(expr); } -class sva_case_exprt : public binary_predicate_exprt +class sva_case_exprt : public binary_exprt { public: explicit sva_case_exprt(exprt __case_op, exprt __cases) - : binary_predicate_exprt( + : binary_exprt( std::move(__case_op), ID_sva_case, - std::move(__cases)) + std::move(__cases), + verilog_sva_property_typet{}) { } @@ -1360,8 +1401,8 @@ class sva_case_exprt : public binary_predicate_exprt exprt lower() const; protected: - using binary_predicate_exprt::op0; - using binary_predicate_exprt::op1; + using binary_exprt::op0; + using binary_exprt::op1; }; inline const sva_case_exprt &to_sva_case_expr(const exprt &expr) diff --git a/src/verilog/verilog_typecheck_sva.cpp b/src/verilog/verilog_typecheck_sva.cpp index a9d01de20..d7b42b5cb 100644 --- a/src/verilog/verilog_typecheck_sva.cpp +++ b/src/verilog/verilog_typecheck_sva.cpp @@ -40,6 +40,11 @@ void verilog_typecheck_exprt::require_sva_sequence(exprt &expr) expr = sva_boolean_exprt{std::move(expr), verilog_sva_sequence_typet{}}; } } + else if(type.id() == ID_verilog_sva_property) + { + throw errort().with_location(expr.source_location()) + << "sequence required, but got property"; + } else { throw errort().with_location(expr.source_location()) @@ -59,6 +64,10 @@ void verilog_typecheck_exprt::require_sva_property(exprt &expr) // or cover. expr = sva_sequence_property_exprt{std::move(expr)}; } + else if(type.id() == ID_verilog_sva_property) + { + // good as is + } else if( type.id() == ID_bool || type.id() == ID_unsignedbv || type.id() == ID_signedbv || type.id() == ID_verilog_unsignedbv || @@ -83,7 +92,7 @@ exprt verilog_typecheck_exprt::convert_unary_sva(unary_exprt expr) { convert_sva(expr.op()); require_sva_property(expr.op()); - expr.type() = bool_typet{}; // always boolean, never x + expr.type() = verilog_sva_property_typet{}; // always boolean, never x return std::move(expr); } else if( @@ -100,7 +109,7 @@ exprt verilog_typecheck_exprt::convert_unary_sva(unary_exprt expr) { convert_sva(expr.op()); require_sva_sequence(expr.op()); - expr.type() = bool_typet{}; + expr.type() = verilog_sva_property_typet{}; return std::move(expr); } else @@ -134,7 +143,7 @@ exprt verilog_typecheck_exprt::convert_binary_sva(binary_exprt expr) require_sva_property(expr.lhs()); require_sva_property(expr.rhs()); // always boolean, never x - expr.type() = bool_typet{}; + expr.type() = verilog_sva_property_typet{}; } return std::move(expr); @@ -148,7 +157,7 @@ exprt verilog_typecheck_exprt::convert_binary_sva(binary_exprt expr) require_sva_property(expr.rhs()); // always boolean, never x - expr.type() = bool_typet{}; + expr.type() = verilog_sva_property_typet{}; return std::move(expr); } @@ -164,7 +173,7 @@ exprt verilog_typecheck_exprt::convert_binary_sva(binary_exprt expr) convert_sva(to_sva_abort_expr(expr).property()); require_sva_property(to_sva_abort_expr(expr).property()); - expr.type() = bool_typet{}; + expr.type() = verilog_sva_property_typet{}; return std::move(expr); } @@ -175,7 +184,7 @@ exprt verilog_typecheck_exprt::convert_binary_sva(binary_exprt expr) auto &op = to_sva_indexed_nexttime_expr(expr).op(); convert_sva(op); require_sva_property(op); - expr.type() = bool_typet{}; + expr.type() = verilog_sva_property_typet{}; return std::move(expr); } @@ -186,7 +195,7 @@ exprt verilog_typecheck_exprt::convert_binary_sva(binary_exprt expr) auto &op = to_sva_indexed_s_nexttime_expr(expr).op(); convert_sva(op); require_sva_property(op); - expr.type() = bool_typet{}; + expr.type() = verilog_sva_property_typet{}; return std::move(expr); } @@ -205,7 +214,7 @@ exprt verilog_typecheck_exprt::convert_binary_sva(binary_exprt expr) convert_sva(expr.rhs()); require_sva_property(expr.rhs()); - expr.type() = bool_typet{}; + expr.type() = verilog_sva_property_typet{}; return std::move(expr); } else if( @@ -218,7 +227,7 @@ exprt verilog_typecheck_exprt::convert_binary_sva(binary_exprt expr) convert_sva(expr.rhs()); require_sva_property(expr.rhs()); - expr.type() = bool_typet{}; + expr.type() = verilog_sva_property_typet{}; return std::move(expr); } @@ -286,7 +295,7 @@ exprt verilog_typecheck_exprt::convert_binary_sva(binary_exprt expr) require_sva_property(case_item.result()); } - expr.type() = bool_typet{}; + expr.type() = verilog_sva_property_typet{}; return std::move(expr); } else @@ -396,7 +405,7 @@ exprt verilog_typecheck_exprt::convert_ternary_sva(ternary_exprt expr) convert_sva(expr.op2()); require_sva_property(expr.op2()); - expr.type() = bool_typet{}; + expr.type() = verilog_sva_property_typet{}; return std::move(expr); } @@ -415,7 +424,7 @@ exprt verilog_typecheck_exprt::convert_ternary_sva(ternary_exprt expr) } // These are always property expressions - expr.type() = bool_typet{}; + expr.type() = verilog_sva_property_typet{}; return std::move(expr); } diff --git a/src/verilog/verilog_types.h b/src/verilog/verilog_types.h index b3d8aec77..5c5916d77 100644 --- a/src/verilog/verilog_types.h +++ b/src/verilog/verilog_types.h @@ -739,6 +739,15 @@ inline verilog_package_scope_typet &to_verilog_package_scope_type(typet &type) return static_cast(type); } +/// SVA properties +class verilog_sva_property_typet : public typet +{ +public: + verilog_sva_property_typet() : typet(ID_verilog_sva_property) + { + } +}; + /// SVA sequences class verilog_sva_sequence_typet : public typet { From 3b3cd4e672d3c739f3905812c0c408612437a43f Mon Sep 17 00:00:00 2001 From: Daniel Kroening Date: Thu, 5 Jun 2025 10:00:08 -0700 Subject: [PATCH 2/2] fx --- src/temporal-logic/trivial_sva.cpp | 26 +++++++++++++++++++++----- 1 file changed, 21 insertions(+), 5 deletions(-) diff --git a/src/temporal-logic/trivial_sva.cpp b/src/temporal-logic/trivial_sva.cpp index 62cf435d8..283e625f5 100644 --- a/src/temporal-logic/trivial_sva.cpp +++ b/src/temporal-logic/trivial_sva.cpp @@ -32,17 +32,29 @@ exprt trivial_sva(exprt expr) auto rhs = is_state_predicate(sva_implication.rhs()); if(lhs.has_value() && rhs.has_value()) - expr = implies_exprt{*lhs, *rhs}; + expr = sva_boolean_exprt{implies_exprt{*lhs, *rhs}, verilog_sva_property_typet{}}; } else if(expr.id() == ID_sva_iff) { + // same as boolean iff when both lhs/rhs are state predicates auto &sva_iff = to_sva_iff_expr(expr); - expr = equal_exprt{sva_iff.lhs(), sva_iff.rhs()}; + + auto lhs = is_state_predicate(sva_iff.lhs()); + auto rhs = is_state_predicate(sva_iff.rhs()); + + if(lhs.has_value() && rhs.has_value()) + expr = sva_boolean_exprt{equal_exprt{*lhs, *rhs}, verilog_sva_property_typet{}}; } else if(expr.id() == ID_sva_implies) { + // same as boolean implication when both lhs/rhs are state predicates auto &sva_implies = to_sva_implies_expr(expr); - expr = implies_exprt{sva_implies.lhs(), sva_implies.rhs()}; + + auto lhs = is_state_predicate(sva_implies.lhs()); + auto rhs = is_state_predicate(sva_implies.rhs()); + + if(lhs.has_value() && rhs.has_value()) + expr = sva_boolean_exprt{implies_exprt{*lhs, *rhs}, verilog_sva_property_typet{}}; } else if(expr.id() == ID_sva_and) { @@ -84,11 +96,15 @@ exprt trivial_sva(exprt expr) } else if(expr.id() == ID_sva_not) { - // Same as boolean 'not'. These do not apply to sequences. - expr = not_exprt{to_sva_not_expr(expr).op()}; + // Same as boolean 'not' when applied to a state predicate. + auto &op = to_sva_not_expr(expr).op(); + auto predicate = is_state_predicate(op); + if(predicate.has_value()) + expr = sva_boolean_exprt{not_exprt{*predicate}, verilog_sva_property_typet{}}; } else if(expr.id() == ID_sva_if) { + // same as boolean 'if' when both cases are state predicates. auto &sva_if_expr = to_sva_if_expr(expr); auto false_case = sva_if_expr.false_case().is_nil() ? true_exprt{}