From eb194ca2491ab5ff8138f9cdd7209bd3890cfb21 Mon Sep 17 00:00:00 2001 From: Daniel Poetzl Date: Tue, 11 Sep 2018 16:50:33 +0100 Subject: [PATCH 1/2] Error handling cleanup in solvers/flattening Files boolbv_quantifier.cpp to boolbv_typecast.cpp --- src/solvers/flattening/boolbv_quantifier.cpp | 23 +++++---- src/solvers/flattening/boolbv_reduction.cpp | 14 +++--- src/solvers/flattening/boolbv_replication.cpp | 29 ++++++------ src/solvers/flattening/boolbv_shift.cpp | 11 ++--- src/solvers/flattening/boolbv_struct.cpp | 47 +++++++++---------- src/solvers/flattening/boolbv_typecast.cpp | 43 +++++++++++------ src/util/std_expr.h | 4 ++ 7 files changed, 93 insertions(+), 78 deletions(-) diff --git a/src/solvers/flattening/boolbv_quantifier.cpp b/src/solvers/flattening/boolbv_quantifier.cpp index 23f8857f80d..d079621f014 100644 --- a/src/solvers/flattening/boolbv_quantifier.cpp +++ b/src/solvers/flattening/boolbv_quantifier.cpp @@ -8,9 +8,8 @@ Author: Daniel Kroening, kroening@kroening.com #include "boolbv.h" -#include - #include +#include #include #include @@ -32,8 +31,8 @@ exprt get_quantifier_var_min( const exprt &var_expr, const exprt &quantifier_expr) { - assert(quantifier_expr.id()==ID_or || - quantifier_expr.id()==ID_and); + PRECONDITION(quantifier_expr.id() == ID_or || quantifier_expr.id() == ID_and); + exprt res; res.make_false(); if(quantifier_expr.id()==ID_or) @@ -80,8 +79,7 @@ exprt get_quantifier_var_max( const exprt &var_expr, const exprt &quantifier_expr) { - assert(quantifier_expr.id()==ID_or || - quantifier_expr.id()==ID_and); + PRECONDITION(quantifier_expr.id() == ID_or || quantifier_expr.id() == ID_and); exprt res; res.make_false(); if(quantifier_expr.id()==ID_or) @@ -140,11 +138,14 @@ exprt get_quantifier_var_max( bool instantiate_quantifier(exprt &expr, const namespacet &ns) { - if(!(expr.id()==ID_forall || expr.id()==ID_exists)) - return true; + PRECONDITION(expr.id() == ID_forall || expr.id() == ID_exists); - assert(expr.operands().size()==2); - assert(expr.op0().id()==ID_symbol); + DATA_INVARIANT( + expr.operands().size() == 2, + "quantifier expressions shall have two operands"); + + DATA_INVARIANT( + expr.op0().id() == ID_symbol, "quantified variable shall be a symbol"); exprt var_expr=expr.op0(); @@ -203,6 +204,8 @@ bool instantiate_quantifier(exprt &expr, literalt boolbvt::convert_quantifier(const exprt &src) { + PRECONDITION(src.id() == ID_forall || src.id() == ID_exists); + exprt expr(src); if(!instantiate_quantifier(expr, ns)) return SUB::convert_rest(src); diff --git a/src/solvers/flattening/boolbv_reduction.cpp b/src/solvers/flattening/boolbv_reduction.cpp index 056f5d05676..ff825f569bd 100644 --- a/src/solvers/flattening/boolbv_reduction.cpp +++ b/src/solvers/flattening/boolbv_reduction.cpp @@ -13,8 +13,9 @@ literalt boolbvt::convert_reduction(const unary_exprt &expr) { const bvt &op_bv=convert_bv(expr.op()); - if(op_bv.empty()) - throw "reduction operators take one non-empty operand"; + INVARIANT( + !op_bv.empty(), + "reduction operand bitvector shall have width at least one"); enum { O_OR, O_AND, O_XOR } op; @@ -27,7 +28,7 @@ literalt boolbvt::convert_reduction(const unary_exprt &expr) else if(id==ID_reduction_xor || id==ID_reduction_xnor) op=O_XOR; else - throw "unexpected reduction operator"; + UNREACHABLE; literalt l=op_bv[0]; @@ -53,8 +54,9 @@ bvt boolbvt::convert_bv_reduction(const unary_exprt &expr) { const bvt &op_bv=convert_bv(expr.op()); - if(op_bv.empty()) - throw "reduction operators take one non-empty operand"; + INVARIANT( + !op_bv.empty(), + "reduction operand bitvector shall have width at least one"); enum { O_OR, O_AND, O_XOR } op; @@ -67,7 +69,7 @@ bvt boolbvt::convert_bv_reduction(const unary_exprt &expr) else if(id==ID_reduction_xor || id==ID_reduction_xnor) op=O_XOR; else - throw "unexpected reduction operator"; + UNREACHABLE; const typet &op_type=expr.op().type(); diff --git a/src/solvers/flattening/boolbv_replication.cpp b/src/solvers/flattening/boolbv_replication.cpp index c7368cc1830..c1e8c7068fb 100644 --- a/src/solvers/flattening/boolbv_replication.cpp +++ b/src/solvers/flattening/boolbv_replication.cpp @@ -17,30 +17,29 @@ bvt boolbvt::convert_replication(const replication_exprt &expr) if(width==0) return conversion_failed(expr); - mp_integer times; - if(to_integer(expr.op0(), times)) - throw "replication takes constant as first parameter"; + mp_integer times = numeric_cast_v(expr.times()); bvt bv; bv.resize(width); const std::size_t u_times=integer2unsigned(times); - const bvt &op=convert_bv(expr.op1()); - std::size_t offset=0; + const bvt &op = convert_bv(expr.op()); - for(std::size_t i=0; iwidth) - throw "replication operand width too big"; + INVARIANT( + op.size() * u_times == bv.size(), + "result bitvector width shall be equal to the operand bitvector width times" + "the number of replications"); - for(std::size_t i=0; i(expr.op1()); std::size_t distance; diff --git a/src/solvers/flattening/boolbv_struct.cpp b/src/solvers/flattening/boolbv_struct.cpp index e1dbe90601f..e5a589b915c 100644 --- a/src/solvers/flattening/boolbv_struct.cpp +++ b/src/solvers/flattening/boolbv_struct.cpp @@ -19,17 +19,16 @@ bvt boolbvt::convert_struct(const struct_exprt &expr) const struct_typet::componentst &components=struct_type.components(); - if(expr.operands().size()!=components.size()) - { - error().source_location=expr.find_source_location(); - error() << "struct: wrong number of arguments" << eom; - throw 0; - } + DATA_INVARIANT_WITH_DIAGNOSTICS( + expr.operands().size() == components.size(), + "number of operands of a struct expression shall equal the number of" + "components as indicated by its type", + expr.find_source_location()); bvt bv; bv.resize(width); - std::size_t offset=0; + std::size_t bit_idx = 0; exprt::operandst::const_iterator op_it=expr.operands().begin(); for(const auto &comp : components) @@ -37,35 +36,35 @@ bvt boolbvt::convert_struct(const struct_exprt &expr) const typet &subtype=comp.type(); const exprt &op=*op_it; - if(!base_type_eq(subtype, op.type(), ns)) - { - error().source_location=expr.find_source_location(); - error() << "struct: component type does not match: " - << subtype.pretty() << " vs. " - << op.type().pretty() << eom; - throw 0; - } + DATA_INVARIANT_WITH_DIAGNOSTICS( + base_type_eq(subtype, op.type(), ns), + "type of a struct expression operand shall equal the type of the " + "corresponding struct component", + expr.find_source_location(), + subtype.pretty(), + op.type().pretty()); std::size_t subtype_width=boolbv_width(subtype); if(subtype_width!=0) { - const bvt &op_bv=convert_bv(op); - - assert(offset(expr); } @@ -4593,6 +4595,8 @@ inline quantifier_exprt &to_quantifier_expr(exprt &expr) { DATA_INVARIANT(expr.operands().size()==2, "quantifier expressions must have two operands"); + DATA_INVARIANT( + expr.op0().id() == ID_symbol, "quantified variable shall be a symbol"); return static_cast(expr); } From 44503dd06cfa6f08826298d058cd0115365e8384 Mon Sep 17 00:00:00 2001 From: Daniel Poetzl Date: Mon, 24 Sep 2018 20:04:57 +0100 Subject: [PATCH 2/2] Refactor quantifier instantiation in solvers/flattening --- src/solvers/flattening/boolbv.cpp | 4 +- src/solvers/flattening/boolbv.h | 2 +- src/solvers/flattening/boolbv_quantifier.cpp | 68 +++++++++----------- 3 files changed, 33 insertions(+), 41 deletions(-) diff --git a/src/solvers/flattening/boolbv.cpp b/src/solvers/flattening/boolbv.cpp index 53f1cdcb44e..f3661a3334b 100644 --- a/src/solvers/flattening/boolbv.cpp +++ b/src/solvers/flattening/boolbv.cpp @@ -463,9 +463,9 @@ literalt boolbvt::convert_rest(const exprt &expr) else if(expr.id()==ID_extractbit) return convert_extractbit(to_extractbit_expr(expr)); else if(expr.id()==ID_forall) - return convert_quantifier(expr); + return convert_quantifier(to_quantifier_expr(expr)); else if(expr.id()==ID_exists) - return convert_quantifier(expr); + return convert_quantifier(to_quantifier_expr(expr)); else if(expr.id()==ID_let) { bvt bv=convert_let(to_let_expr(expr)); diff --git a/src/solvers/flattening/boolbv.h b/src/solvers/flattening/boolbv.h index c51f3a3803b..af925e1e437 100644 --- a/src/solvers/flattening/boolbv.h +++ b/src/solvers/flattening/boolbv.h @@ -131,7 +131,7 @@ class boolbvt:public arrayst virtual literalt convert_verilog_case_equality( const binary_relation_exprt &expr); virtual literalt convert_ieee_float_rel(const exprt &expr); - virtual literalt convert_quantifier(const exprt &expr); + virtual literalt convert_quantifier(const quantifier_exprt &expr); virtual bvt convert_index(const exprt &array, const mp_integer &index); virtual bvt convert_index(const index_exprt &expr); diff --git a/src/solvers/flattening/boolbv_quantifier.cpp b/src/solvers/flattening/boolbv_quantifier.cpp index d079621f014..1e3dfd55550 100644 --- a/src/solvers/flattening/boolbv_quantifier.cpp +++ b/src/solvers/flattening/boolbv_quantifier.cpp @@ -10,6 +10,7 @@ Author: Daniel Kroening, kroening@kroening.com #include #include +#include #include #include @@ -135,83 +136,74 @@ exprt get_quantifier_var_max( return res; } -bool instantiate_quantifier(exprt &expr, - const namespacet &ns) +optionalt +instantiate_quantifier(const quantifier_exprt &expr, const namespacet &ns) { PRECONDITION(expr.id() == ID_forall || expr.id() == ID_exists); - DATA_INVARIANT( - expr.operands().size() == 2, - "quantifier expressions shall have two operands"); - - DATA_INVARIANT( - expr.op0().id() == ID_symbol, "quantified variable shall be a symbol"); - - exprt var_expr=expr.op0(); + const symbol_exprt &var_expr = expr.symbol(); /** * We need to rewrite the forall/exists quantifier into * an OR/AND expr. **/ - exprt re(expr); - exprt tmp(re.op1()); - re.swap(tmp); - re=simplify_expr(re, ns); + + const exprt &re = simplify_expr(expr.where(), ns); if(re.is_true() || re.is_false()) { - expr=re; - return true; + return re; } - exprt min_i=get_quantifier_var_min(var_expr, re); - exprt max_i=get_quantifier_var_max(var_expr, re); - exprt body_expr=re; - if(var_expr.is_false() || - min_i.is_false() || - max_i.is_false() || - body_expr.is_false()) - return false; + const exprt &min_i = get_quantifier_var_min(var_expr, re); + const exprt &max_i = get_quantifier_var_max(var_expr, re); - mp_integer lb, ub; - to_integer(min_i, lb); - to_integer(max_i, ub); + if(min_i.is_false() || max_i.is_false()) + return nullopt; + + mp_integer lb = numeric_cast_v(min_i); + mp_integer ub = numeric_cast_v(max_i); if(lb>ub) - return false; + return nullopt; - bool res=true; std::vector expr_insts; for(mp_integer i=lb; i<=ub; ++i) { - exprt constraint_expr=body_expr; + exprt constraint_expr = re; replace_expr(var_expr, from_integer(i, var_expr.type()), constraint_expr); expr_insts.push_back(constraint_expr); } + if(expr.id()==ID_forall) { - expr=conjunction(expr_insts); + return conjunction(expr_insts); } - if(expr.id()==ID_exists) + else if(expr.id() == ID_exists) { - expr=disjunction(expr_insts); + return disjunction(expr_insts); } - return res; + UNREACHABLE; + return nullopt; } -literalt boolbvt::convert_quantifier(const exprt &src) +literalt boolbvt::convert_quantifier(const quantifier_exprt &src) { PRECONDITION(src.id() == ID_forall || src.id() == ID_exists); - exprt expr(src); - if(!instantiate_quantifier(expr, ns)) + quantifier_exprt expr(src); + const auto res = instantiate_quantifier(expr, ns); + + if(!res) + { return SUB::convert_rest(src); + } quantifiert quantifier; - quantifier.expr=expr; + quantifier.expr = *res; quantifier_list.push_back(quantifier); literalt l=prop.new_variable();