void goto_symext::process_array_expr_rec( exprt &expr, const typet &type) const { if(expr.id()==ID_if) { if_exprt &if_expr=to_if_expr(expr); process_array_expr_rec(if_expr.true_case(), type); process_array_expr_rec(if_expr.false_case(), type); } else if(expr.id()==ID_index) { // strip index index_exprt &index_expr=to_index_expr(expr); exprt tmp=index_expr.array(); expr.swap(tmp); } else if(expr.id()==ID_typecast) { // strip exprt tmp=to_typecast_expr(expr).op0(); expr.swap(tmp); process_array_expr_rec(expr, type); } else if(expr.id()==ID_address_of) { // strip exprt tmp=to_address_of_expr(expr).op0(); expr.swap(tmp); process_array_expr_rec(expr, type); } else if(expr.id()==ID_symbol && expr.get_bool(ID_C_SSA_symbol) && to_ssa_expr(expr).get_original_expr().id()==ID_index) { const ssa_exprt &ssa=to_ssa_expr(expr); const index_exprt &index_expr=to_index_expr(ssa.get_original_expr()); exprt tmp=index_expr.array(); expr.swap(tmp); } else Forall_operands(it, expr) process_array_expr_rec(*it, it->type()); if(!base_type_eq(expr.type(), type, ns)) { byte_extract_exprt be(byte_extract_id()); be.type()=type; be.op()=expr; be.offset()=gen_zero(index_type()); expr.swap(be); } }
void goto_symext::process_array_expr(exprt &expr) { // This may change the type of the expression! if(expr.id()==ID_if) { if_exprt &if_expr=to_if_expr(expr); process_array_expr(if_expr.true_case()); process_array_expr_rec(if_expr.false_case(), if_expr.true_case().type()); if_expr.type()=if_expr.true_case().type(); } else if(expr.id()==ID_index) { // strip index index_exprt &index_expr=to_index_expr(expr); exprt tmp=index_expr.array(); expr.swap(tmp); } else if(expr.id()==ID_typecast) { // strip exprt tmp=to_typecast_expr(expr).op0(); expr.swap(tmp); process_array_expr(expr); } else if(expr.id()==ID_address_of) { // strip exprt tmp=to_address_of_expr(expr).op0(); expr.swap(tmp); process_array_expr(expr); } else if(expr.id()==ID_symbol && expr.get_bool(ID_C_SSA_symbol) && to_ssa_expr(expr).get_original_expr().id()==ID_index) { const ssa_exprt &ssa=to_ssa_expr(expr); const index_exprt &index_expr=to_index_expr(ssa.get_original_expr()); exprt tmp=index_expr.array(); expr.swap(tmp); } else Forall_operands(it, expr) process_array_expr(*it); }
bool clang_c_convertert::convert_integer_literal( const clang::IntegerLiteral &integer_literal, exprt &dest) { typet type; if(get_type(integer_literal.getType(), type)) return true; assert(type.is_unsignedbv() || type.is_signedbv()); llvm::APInt val = integer_literal.getValue(); exprt the_val; if (type.is_unsignedbv()) { the_val = constant_exprt( integer2binary(val.getZExtValue(), bv_width(type)), integer2string(val.getZExtValue()), type); } else { the_val = constant_exprt( integer2binary(val.getSExtValue(), bv_width(type)), integer2string(val.getSExtValue()), type); } dest.swap(the_val); return false; }
void cpp_typecheckt::new_temporary( const source_locationt &source_location, const typet &type, const exprt::operandst &ops, exprt &temporary) { // create temporary object exprt tmp_object_expr=exprt(ID_side_effect, type); tmp_object_expr.set(ID_statement, ID_temporary_object); tmp_object_expr.add_source_location()= source_location; exprt new_object(ID_new_object); new_object.add_source_location()=tmp_object_expr.source_location(); new_object.set(ID_C_lvalue, true); new_object.type()=tmp_object_expr.type(); already_typechecked(new_object); codet new_code = cpp_constructor(source_location, new_object, ops); if(new_code.is_not_nil()) { if(new_code.get(ID_statement)==ID_assign) tmp_object_expr.move_to_operands(new_code.op1()); else tmp_object_expr.add(ID_initializer)=new_code; } temporary.swap(tmp_object_expr); }
bool simplify_exprt::simplify_ieee_float_relation(exprt &expr) { assert(expr.id()==ID_ieee_float_equal || expr.id()==ID_ieee_float_notequal); exprt::operandst &operands=expr.operands(); if(expr.type().id()!=ID_bool) return true; if(operands.size()!=2) return true; // types must match if(expr.op0().type()!=expr.op1().type()) return true; if(expr.op0().type().id()!=ID_floatbv) return true; // first see if we compare to a constant if(expr.op0().is_constant() && expr.op1().is_constant()) { ieee_floatt f0(to_constant_expr(expr.op0())); ieee_floatt f1(to_constant_expr(expr.op1())); if(expr.id()==ID_ieee_float_notequal) expr.make_bool(f0.ieee_not_equal(f1)); else if(expr.id()==ID_ieee_float_equal) expr.make_bool(f0.ieee_equal(f1)); else assert(false); return false; } if(expr.op0()==expr.op1()) { // x!=x is the same as saying isnan(op) exprt isnan(ID_isnan, bool_typet()); isnan.copy_to_operands(expr.op0()); if(expr.id()==ID_ieee_float_notequal) { } else if(expr.id()==ID_ieee_float_equal) isnan.make_not(); else assert(false); expr.swap(isnan); return false; } return true; }
void c_typecastt::do_typecast(exprt &expr, const typet &type) { // special case: array -> pointer is actually // something like address_of const typet &expr_type=ns.follow(expr.type()); if(expr_type.id()==ID_array) { index_exprt index; index.array()=expr; index.index()=gen_zero(index_type()); index.type()=expr_type.subtype(); expr=address_of_exprt(index); if(ns.follow(expr.type())!=ns.follow(type)) expr.make_typecast(type); return; } if(expr_type!=type) { // C booleans are special: we compile to ?0:1 if(type.get(ID_C_c_type)==ID_bool) { if(expr_type.id()==ID_bool) // bool -> _Bool { exprt result=if_exprt(expr, gen_one(type), gen_zero(type)); expr.swap(result); } else // * -> _Bool { equal_exprt equal_zero(expr, gen_zero(expr_type)); exprt result=if_exprt(equal_zero, gen_zero(type), gen_one(type)); expr.swap(result); } } else { expr.make_typecast(type); } } }
void convert_string_literal(const std::string &src, exprt &dest) { std::string value; convert_string_literal(src, value); string_constantt result; result.set_value(value); dest.swap(result); }
void preconditiont::compute_rec(exprt &dest) { if(dest.id()==ID_address_of) { // only do index! assert(dest.operands().size()==1); compute_address_of(dest.op0()); } else if(dest.id()==ID_symbol) { if(dest.get(ID_identifier)== s.get_original_name(SSA_step.ssa_lhs.get_identifier())) { dest=SSA_step.ssa_rhs; s.get_original_name(dest); } } else if(dest.id()==ID_dereference) { assert(dest.operands().size()==1); const irep_idt &lhs_identifier= s.get_original_name(SSA_step.ssa_lhs.get_identifier()); // aliasing may happen here value_setst::valuest expr_set; value_sets.get_values(target, dest.op0(), expr_set); hash_set_cont<irep_idt, irep_id_hash> symbols; for(value_setst::valuest::const_iterator it=expr_set.begin(); it!=expr_set.end(); it++) find_symbols(*it, symbols); if(symbols.find(lhs_identifier)!=symbols.end()) { // may alias! exprt tmp; tmp.swap(dest.op0()); dereference(target, tmp, ns, value_sets); dest.swap(tmp); compute_rec(dest); } else { // nah, ok compute_rec(dest.op0()); } } else Forall_operands(it, dest) compute_rec(*it); }
bool value_sett::eval_pointer_offset( exprt &expr, const namespacet &ns) const { bool mod=false; if(expr.id()==ID_pointer_offset) { assert(expr.operands().size()==1); object_mapt reference_set; get_value_set(expr.op0(), reference_set, ns, true); exprt new_expr; mp_integer previous_offset=0; const object_map_dt &object_map=reference_set.read(); for(object_map_dt::const_iterator it=object_map.begin(); it!=object_map.end(); it++) if(!it->second.offset_is_set) return false; else { const exprt &object=object_numbering[it->first]; mp_integer ptr_offset=compute_pointer_offset(object, ns); if(ptr_offset<0) return false; ptr_offset+=it->second.offset; if(mod && ptr_offset!=previous_offset) return false; new_expr=from_integer(ptr_offset, index_type()); previous_offset=ptr_offset; mod=true; } if(mod) expr.swap(new_expr); } else { Forall_operands(it, expr) mod=eval_pointer_offset(*it, ns) || mod; } return mod; }
bool clang_c_convertert::convert_string_literal( const clang::StringLiteral &string_literal, exprt &dest) { typet type; if(get_type(string_literal.getType(), type)) return true; string_constantt string(string_literal.getBytes().str(), type); dest.swap(string); return false; }
void goto_symext::replace_nondet(exprt &expr) { if(expr.id()==ID_side_effect && expr.get(ID_statement)==ID_nondet) { exprt new_expr(ID_nondet_symbol, expr.type()); new_expr.set(ID_identifier, "symex::nondet"+std::to_string(nondet_count++)); new_expr.add_source_location()=expr.source_location(); expr.swap(new_expr); } else Forall_operands(it, expr) replace_nondet(*it); }
void goto_symext::rewrite_quantifiers(exprt &expr, statet &state) { if(expr.id()==ID_forall) { // forall X. P -> P // we keep the quantified variable unique by means of L2 renaming assert(expr.operands().size()==2); assert(expr.op0().id()==ID_symbol); symbol_exprt tmp0= to_symbol_expr(to_ssa_expr(expr.op0()).get_original_expr()); symex_decl(state, tmp0); exprt tmp=expr.op1(); expr.swap(tmp); } }
void goto_convertt::rewrite_boolean(exprt &expr) { assert(expr.id()==ID_and || expr.id()==ID_or); if(!expr.is_boolean()) throw "`"+expr.id_string()+"' " "must be Boolean, but got "+expr.pretty(); // re-write "a && b" into nested a?b:0 // re-write "a || b" into nested a?1:b exprt tmp; if(expr.id()==ID_and) tmp=true_exprt(); else // ID_or tmp=false_exprt(); exprt::operandst &ops=expr.operands(); // start with last one for(int i=int(ops.size())-1; i>=0; i--) { exprt &op=ops[i]; if(!op.is_boolean()) throw "`"+expr.id_string()+"' takes Boolean " "operands only, but got "+op.pretty(); if(expr.id()==ID_and) { if_exprt if_e(op, tmp, false_exprt()); tmp.swap(if_e); } else // ID_or { if_exprt if_e(op, true_exprt(), tmp); tmp.swap(if_e); } } expr.swap(tmp); }
void cnf_join_binary(exprt &expr) { Forall_operands(it, expr) cnf_join_binary(*it); if(expr.id()==ID_and || expr.id()==ID_or || expr.id()==ID_xor || expr.id()==ID_bitand || expr.id()==ID_bitor || expr.id()==ID_bitxor) { exprt tmp; if(expr.operands().size()==1) { tmp.swap(expr.op0()); expr.swap(tmp); } else { unsigned count=0; forall_operands(it, expr) { if(it->id()==expr.id()) count+=it->operands().size(); else count++; } tmp.operands().reserve(count); Forall_operands(it, expr) { if(it->id()==expr.id()) { Forall_operands(it2, *it) tmp.move_to_operands(*it2); } else tmp.move_to_operands(*it); } expr.operands().swap(tmp.operands()); } }
void gen_binary(exprt &expr, const std::string &id, bool default_value) { if(expr.operands().size()==0) { if(default_value) expr.make_true(); else expr.make_false(); } else if(expr.operands().size()==1) { exprt tmp; tmp.swap(expr.op0()); expr.swap(tmp); } else { expr.id(id); expr.type()=typet("bool"); } }
void guardt::guard_expr(exprt &dest) const { if(is_true()) { // do nothing } else { if(dest.is_false()) { dest=as_expr(); dest.make_not(); } else { implies_exprt tmp; tmp.op0()=as_expr(); tmp.op1().swap(dest); dest.swap(tmp); } } }
bool simplify_exprt::simplify_address_of(exprt &expr) { if(expr.operands().size()!=1) return true; if(ns.follow(expr.type()).id()!=ID_pointer) return true; exprt &object=expr.op0(); bool result=simplify_address_of_arg(object); if(object.id()==ID_index) { index_exprt &index_expr=to_index_expr(object); if(!index_expr.index().is_zero()) { // we normalize &a[i] to (&a[0])+i exprt offset; offset.swap(index_expr.op1()); index_expr.op1()=gen_zero(offset.type()); exprt addition(ID_plus, expr.type()); addition.move_to_operands(expr, offset); expr.swap(addition); return false; } } else if(object.id()==ID_dereference) { // simplify &*p to p assert(object.operands().size()==1); exprt tmp=object.op0(); expr=tmp; return false; } return result; }
void local_SSAt::replace_side_effects_rec( exprt &expr, locationt loc, unsigned &counter) const { Forall_operands(it, expr) replace_side_effects_rec(*it, loc, counter); if(expr.id()==ID_side_effect) { const side_effect_exprt &side_effect_expr= to_side_effect_expr(expr); const irep_idt statement=side_effect_expr.get_statement(); if(statement==ID_nondet) { // turn into nondet_symbol exprt nondet_symbol(ID_nondet_symbol, expr.type()); counter++; const irep_idt identifier= "ssa::nondet"+ i2string(loc->location_number)+ "."+i2string(counter)+suffix; nondet_symbol.set(ID_identifier, identifier); expr.swap(nondet_symbol); } else if(statement==ID_malloc) { counter++; std::string tmp_suffix= i2string(loc->location_number)+ "."+i2string(counter)+suffix; expr=malloc_ssa(side_effect_expr, tmp_suffix, ns); } else throw "unexpected side effect: "+id2string(statement); } }
void make_it_a_predicate( const predicatest &predicates, exprt &expr, const namespacet &ns) { bool negation; canonicalize(expr, negation, ns); // see if we have it unsigned nr; if(predicates.find(expr, nr)) { // yes, we do! // see if it is a constant if(predicates[nr].is_true()) expr.make_true(); else if(predicates[nr].is_false()) expr.make_false(); else { expr=exprt(ID_predicate_symbol, typet(ID_bool)); expr.set(ID_identifier, nr); } if(negation) expr.make_not(); } else { // nah, we don't // make it nondeterministic choice exprt tmp(ID_nondet_symbol, typet(ID_bool)); tmp.add(ID_expression).swap(expr); expr.swap(tmp); } }
void goto_symext::replace_array_equal(exprt &expr) { if(expr.id()==ID_array_equal) { assert(expr.operands().size()==2); // we expect two index expressions process_array_expr(expr.op0()); process_array_expr(expr.op1()); // type checking if(ns.follow(expr.op0().type())!= ns.follow(expr.op1().type())) expr=false_exprt(); else { equal_exprt equality_expr(expr.op0(), expr.op1()); expr.swap(equality_expr); } } Forall_operands(it, expr) replace_array_equal(*it); }
bool simplify_exprt::simplify_index(exprt &expr) { bool result=true; // extra arithmetic optimizations const exprt &index=to_index_expr(expr).index(); const exprt &array=to_index_expr(expr).array(); if(index.id()==ID_div && index.operands().size()==2) { if(index.op0().id()==ID_mult && index.op0().operands().size()==2 && index.op0().op1()==index.op1()) { exprt tmp=index.op0().op0(); expr.op1()=tmp; result=false; } else if(index.op0().id()==ID_mult && index.op0().operands().size()==2 && index.op0().op0()==index.op1()) { exprt tmp=index.op0().op1(); expr.op1()=tmp; result=false; } } if(array.id()==ID_lambda) { // simplify (lambda i: e)(x) to e[i/x] const exprt &lambda_expr=array; if(lambda_expr.operands().size()!=2) return true; if(expr.op1().type()==lambda_expr.op0().type()) { exprt tmp=lambda_expr.op1(); replace_expr(lambda_expr.op0(), expr.op1(), tmp); expr.swap(tmp); return false; } } else if(array.id()==ID_with) { // we have (a WITH [i:=e])[j] const exprt &with_expr=array; if(with_expr.operands().size()!=3) return true; if(with_expr.op1()==expr.op1()) { // simplify (e with [i:=v])[i] to v exprt tmp=with_expr.op2(); expr.swap(tmp); return false; } else { // Turn (a with i:=x)[j] into (i==j)?x:a[j]. // watch out that the type of i and j might be different. equal_exprt equality_expr(expr.op1(), with_expr.op1()); if(equality_expr.lhs().type()!=equality_expr.rhs().type()) equality_expr.rhs().make_typecast(equality_expr.lhs().type()); simplify_inequality(equality_expr); index_exprt new_index_expr; new_index_expr.type()=expr.type(); new_index_expr.array()=with_expr.op0(); new_index_expr.index()=expr.op1(); simplify_index(new_index_expr); // recursive call if(equality_expr.is_true()) { expr=with_expr.op2(); return false; } else if(equality_expr.is_false()) { expr.swap(new_index_expr); return false; } if_exprt if_expr(equality_expr, with_expr.op2(), new_index_expr); simplify_if(if_expr); expr.swap(if_expr); return false; } } else if(array.id()==ID_constant || array.id()==ID_array) { mp_integer i; if(to_integer(expr.op1(), i)) { } else if(i<0 || i>=array.operands().size()) { // out of bounds } else { // ok exprt tmp=array.operands()[integer2size_t(i)]; expr.swap(tmp); return false; } } else if(array.id()==ID_string_constant) { mp_integer i; const irep_idt &value=array.get(ID_value); if(to_integer(expr.op1(), i)) { } else if(i<0 || i>value.size()) { // out of bounds } else { // terminating zero? char v=(i==value.size())?0:value[integer2size_t(i)]; exprt tmp=from_integer(v, expr.type()); expr.swap(tmp); return false; } } else if(array.id()==ID_array_of) { if(array.operands().size()==1) { exprt tmp=array.op0(); expr.swap(tmp); return false; } } else if(array.id()=="array-list") { // These are index/value pairs, alternating. for(size_t i=0; i<array.operands().size()/2; i++) { exprt tmp_index=array.operands()[i*2]; tmp_index.make_typecast(index.type()); simplify(tmp_index); if(tmp_index==index) { exprt tmp=array.operands()[i*2+1]; expr.swap(tmp); return false; } } } else if(array.id()==ID_byte_extract_little_endian || array.id()==ID_byte_extract_big_endian) { const typet &array_type=ns.follow(array.type()); if(array_type.id()==ID_array) { // This rewrites byte_extract(s, o, array_type)[i] // to byte_extract(s, o+offset, sub_type) mp_integer sub_size=pointer_offset_size(array_type.subtype(), ns); if(sub_size==-1) return true; // add offset to index mult_exprt offset(from_integer(sub_size, array.op1().type()), index); plus_exprt final_offset(array.op1(), offset); simplify_node(final_offset); exprt result(array.id(), expr.type()); result.copy_to_operands(array.op0(), final_offset); expr.swap(result); simplify_rec(expr); return false; } } else if(array.id()==ID_if) { const if_exprt &if_expr=to_if_expr(array); exprt cond=if_expr.cond(); index_exprt idx_false=to_index_expr(expr); idx_false.array()=if_expr.false_case(); to_index_expr(expr).array()=if_expr.true_case(); expr=if_exprt(cond, expr, idx_false, expr.type()); simplify_rec(expr); return false; } return result; }
void goto_convertt::clean_expr( exprt &expr, goto_programt &dest, bool result_is_used) { // this cleans: // && || ?: comma (control-dependency) // function calls // object constructors like arrays, string constants, structs // ++ -- // compound assignments // compound literals if(!needs_cleaning(expr)) return; if(expr.id()==ID_and || expr.id()==ID_or) { // rewrite into ?: rewrite_boolean(expr); // recursive call clean_expr(expr, dest, result_is_used); return; } else if(expr.id()==ID_if) { // first clean condition clean_expr(to_if_expr(expr).cond(), dest, true); // possibly done now if(!needs_cleaning(to_if_expr(expr).true_case()) && !needs_cleaning(to_if_expr(expr).false_case())) return; // copy expression if_exprt if_expr=to_if_expr(expr); if(!if_expr.cond().is_boolean()) throw "first argument of `if' must be boolean, but got " +if_expr.cond().to_string(); const locationt location=expr.find_location(); // We do some constant-folding here, to mimic // what typical compilers do. { exprt tmp_cond=if_expr.cond(); simplify(tmp_cond, ns); if(tmp_cond.is_true()) { clean_expr(if_expr.true_case(), dest, result_is_used); expr=if_expr.true_case(); return; } else if(tmp_cond.is_false()) { clean_expr(if_expr.false_case(), dest, result_is_used); expr=if_expr.false_case(); return; } } goto_programt tmp_true; clean_expr(if_expr.true_case(), tmp_true, result_is_used); goto_programt tmp_false; clean_expr(if_expr.false_case(), tmp_false, result_is_used); if(result_is_used) { symbolt &new_symbol= new_tmp_symbol(expr.type(), "if_expr", dest, location); code_assignt assignment_true; assignment_true.lhs()=new_symbol.symbol_expr(); assignment_true.rhs()=if_expr.true_case(); assignment_true.location()=location; convert(assignment_true, tmp_true); code_assignt assignment_false; assignment_false.lhs()=new_symbol.symbol_expr(); assignment_false.rhs()=if_expr.false_case(); assignment_false.location()=location; convert(assignment_false, tmp_false); // overwrites expr expr=new_symbol.symbol_expr(); } else { // preserve the expressions for possible later checks if(if_expr.true_case().is_not_nil()) { code_expressiont code_expression(if_expr.true_case()); convert(code_expression, tmp_true); } if(if_expr.false_case().is_not_nil()) { code_expressiont code_expression(if_expr.false_case()); convert(code_expression, tmp_false); } expr=nil_exprt(); } // generate guard for argument side-effects generate_ifthenelse( if_expr.cond(), tmp_true, tmp_false, location, dest); return; } else if(expr.id()==ID_comma) { if(result_is_used) { exprt result; Forall_operands(it, expr) { bool last=(it==--expr.operands().end()); // special treatment for last one if(last) { result.swap(*it); clean_expr(result, dest, true); } else { clean_expr(*it, dest, false); // remember these for later checks if(it->is_not_nil()) convert(code_expressiont(*it), dest); } } expr.swap(result); } else // result not used {
bool simplify_exprt::simplify_pointer_offset(exprt &expr) { if(expr.operands().size()!=1) return true; exprt &ptr=expr.op0(); if(ptr.id()==ID_if && ptr.operands().size()==3) { if_exprt if_expr=lift_if(expr, 0); simplify_pointer_offset(if_expr.true_case()); simplify_pointer_offset(if_expr.false_case()); simplify_if(if_expr); expr.swap(if_expr); return false; } if(ptr.type().id()!=ID_pointer) return true; if(ptr.id()==ID_address_of) { if(ptr.operands().size()!=1) return true; mp_integer offset=compute_pointer_offset(ptr.op0(), ns); if(offset!=-1) { expr=from_integer(offset, expr.type()); return false; } } else if(ptr.id()==ID_typecast) // pointer typecast { if(ptr.operands().size()!=1) return true; const typet &op_type=ns.follow(ptr.op0().type()); if(op_type.id()==ID_pointer) { // Cast from pointer to pointer. // This just passes through, remove typecast. exprt tmp=ptr.op0(); ptr=tmp; // recursive call simplify_node(expr); return false; } else if(op_type.id()==ID_signedbv || op_type.id()==ID_unsignedbv) { // Cast from integer to pointer, say (int *)x. if(ptr.op0().is_constant()) { // (T *)0x1234 -> 0x1234 exprt tmp=ptr.op0(); tmp.make_typecast(expr.type()); simplify_node(tmp); expr.swap(tmp); return false; } else { // We do a bit of special treatment for (TYPE *)(a+(int)&o), // which is re-written to 'a'. typet type=ns.follow(expr.type()); exprt tmp=ptr.op0(); if(tmp.id()==ID_plus && tmp.operands().size()==2) { if(tmp.op0().id()==ID_typecast && tmp.op0().operands().size()==1 && tmp.op0().op0().id()==ID_address_of) { expr=tmp.op1(); if(type!=expr.type()) expr.make_typecast(type); simplify_node(expr); return false; } else if(tmp.op1().id()==ID_typecast && tmp.op1().operands().size()==1 && tmp.op1().op0().id()==ID_address_of) { expr=tmp.op0(); if(type!=expr.type()) expr.make_typecast(type); simplify_node(expr); return false; } } } } } else if(ptr.id()==ID_plus) // pointer arithmetic { exprt::operandst ptr_expr; exprt::operandst int_expr; for(const auto & op : ptr.operands()) { if(op.type().id()==ID_pointer) ptr_expr.push_back(op); else if(!op.is_zero()) { exprt tmp=op; if(tmp.type()!=expr.type()) { tmp.make_typecast(expr.type()); simplify_node(tmp); } int_expr.push_back(tmp); } } if(ptr_expr.size()!=1 || int_expr.empty()) return true; typet pointer_type=ptr_expr.front().type(); mp_integer element_size= pointer_offset_size(pointer_type.subtype(), ns); if(element_size==0) return true; // this might change the type of the pointer! exprt pointer_offset(ID_pointer_offset, expr.type()); pointer_offset.copy_to_operands(ptr_expr.front()); simplify_node(pointer_offset); exprt sum; if(int_expr.size()==1) sum=int_expr.front(); else { sum=exprt(ID_plus, expr.type()); sum.operands()=int_expr; } simplify_node(sum); exprt size_expr= from_integer(element_size, expr.type()); binary_exprt product(sum, ID_mult, size_expr, expr.type()); simplify_node(product); expr=binary_exprt(pointer_offset, ID_plus, product, expr.type()); simplify_node(expr); return false; } else if(ptr.id()==ID_constant && ptr.get(ID_value)==ID_NULL) { expr=gen_zero(expr.type()); simplify_node(expr); return false; } return true; }
bool simplify_exprt::simplify_floatbv_typecast(exprt &expr) { // These casts usually reduce precision, and thus, usually round. assert(expr.operands().size()==2); const typet &dest_type=ns.follow(expr.type()); const typet &src_type=ns.follow(expr.op0().type()); // eliminate redundant casts if(dest_type==src_type) { expr=expr.op0(); return false; } exprt op0=expr.op0(); exprt op1=expr.op1(); // rounding mode // We can soundly re-write (float)((double)x op (double)y) // to x op y. True for any rounding mode! #if 0 if(op0.id()==ID_floatbv_div || op0.id()==ID_floatbv_mult || op0.id()==ID_floatbv_plus || op0.id()==ID_floatbv_minus) { if(op0.operands().size()==3 && op0.op0().id()==ID_typecast && op0.op1().id()==ID_typecast && op0.op0().operands().size()==1 && op0.op1().operands().size()==1 && ns.follow(op0.op0().type())==dest_type && ns.follow(op0.op1().type())==dest_type) { exprt result(op0.id(), expr.type()); result.operands().resize(3); result.op0()=op0.op0().op0(); result.op1()=op0.op1().op0(); result.op2()=op1; simplify_node(result); expr.swap(result); return false; } } #endif // constant folding if(op0.is_constant() && op1.is_constant()) { mp_integer rounding_mode; if(!to_integer(op1, rounding_mode)) { if(src_type.id()==ID_floatbv) { if(dest_type.id()==ID_floatbv) // float to float { ieee_floatt result(to_constant_expr(op0)); result.rounding_mode=(ieee_floatt::rounding_modet)integer2size_t(rounding_mode); result.change_spec(to_floatbv_type(dest_type)); expr=result.to_expr(); return false; } else if(dest_type.id()==ID_signedbv || dest_type.id()==ID_unsignedbv) { if(rounding_mode==ieee_floatt::ROUND_TO_ZERO) { ieee_floatt result(to_constant_expr(op0)); result.rounding_mode=(ieee_floatt::rounding_modet)integer2size_t(rounding_mode); mp_integer value=result.to_integer(); expr=from_integer(value, dest_type); return false; } } } else if(src_type.id()==ID_signedbv || src_type.id()==ID_unsignedbv) { mp_integer value; if(!to_integer(op0, value)) { if(dest_type.id()==ID_floatbv) // int to float { ieee_floatt result; result.rounding_mode=(ieee_floatt::rounding_modet)integer2size_t(rounding_mode); result.spec=to_floatbv_type(dest_type); result.from_integer(value); expr=result.to_expr(); return false; } } } } } #if 0 // (T)(a?b:c) --> a?(T)b:(T)c if(expr.op0().id()==ID_if && expr.op0().operands().size()==3) { exprt tmp_op1=binary_exprt(expr.op0().op1(), ID_floatbv_typecast, expr.op1(), dest_type); exprt tmp_op2=binary_exprt(expr.op0().op2(), ID_floatbv_typecast, expr.op1(), dest_type); simplify_floatbv_typecast(tmp_op1); simplify_floatbv_typecast(tmp_op2); expr=if_exprt(expr.op0().op0(), tmp_op1, tmp_op2, dest_type); simplify_if(expr); return false; } #endif return true; }
void goto_program_dereferencet::dereference_rec( exprt &expr, guardt &guard, const value_set_dereferencet::modet mode) { if(!dereference.has_dereference(expr)) return; if(expr.id()==ID_and || expr.id()==ID_or) { if(!expr.is_boolean()) throw expr.id_string()+" must be Boolean, but got "+ expr.pretty(); guardt old_guard=guard; for(unsigned i=0; i<expr.operands().size(); i++) { exprt &op=expr.operands()[i]; if(!op.is_boolean()) throw expr.id_string()+" takes Boolean operands only, but got "+ op.pretty(); if(dereference.has_dereference(op)) dereference_rec(op, guard, value_set_dereferencet::modet::READ); if(expr.id()==ID_or) { exprt tmp(op); tmp.make_not(); guard.add(tmp); } else guard.add(op); } guard.swap(old_guard); return; } else if(expr.id()==ID_if) { if(expr.operands().size()!=3) throw "if takes three arguments"; if(!expr.op0().is_boolean()) { std::string msg= "first argument of if must be boolean, but got " +expr.op0().pretty(); throw msg; } dereference_rec(expr.op0(), guard, value_set_dereferencet::modet::READ); bool o1=dereference.has_dereference(expr.op1()); bool o2=dereference.has_dereference(expr.op2()); if(o1) { guardt old_guard=guard; guard.add(expr.op0()); dereference_rec(expr.op1(), guard, mode); guard.swap(old_guard); } if(o2) { guardt old_guard=guard; exprt tmp(expr.op0()); tmp.make_not(); guard.add(tmp); dereference_rec(expr.op2(), guard, mode); guard.swap(old_guard); } return; } if(expr.id()==ID_address_of || expr.id()=="reference_to") { // turn &*p to p // this has *no* side effect! assert(expr.operands().size()==1); if(expr.op0().id()==ID_dereference) { assert(expr.op0().operands().size()==1); exprt tmp; tmp.swap(expr.op0().op0()); if(tmp.type()!=expr.type()) tmp.make_typecast(expr.type()); expr.swap(tmp); } } Forall_operands(it, expr) dereference_rec(*it, guard, mode); if(expr.id()==ID_dereference) { if(expr.operands().size()!=1) throw "dereference expects one operand"; dereference_location=expr.find_source_location(); exprt tmp=dereference.dereference( expr.op0(), guard, mode); expr.swap(tmp); } else if(expr.id()==ID_index) { // this is old stuff and will go away if(expr.operands().size()!=2) throw "index expects two operands"; if(expr.op0().type().id()==ID_pointer) { dereference_location=expr.find_source_location(); exprt tmp1(ID_plus, expr.op0().type()); tmp1.operands().swap(expr.operands()); exprt tmp2=dereference.dereference(tmp1, guard, mode); tmp2.swap(expr); } } }
void simplify_byte_expr(exprt &dest, const namespacet &ns) { /* * byte_update(byte_update(e, i, v, t), i, v', t) * ----------------------- * root * => * byte_update(e, i, v', t) */ if(dest.id()==ID_byte_update_little_endian || dest.id()==ID_byte_update_big_endian) { exprt &root=dest.op0(); exprt &offset=dest.op1(); const typet &type=root.type(); if(root.id()==ID_byte_update_little_endian || root.id()==ID_byte_update_big_endian) { exprt &nested_root=root.op0(); exprt &nested_offset=root.op1(); const typet &nested_type=root.type(); if(offset == nested_offset && type == nested_type) { #ifdef DEBUG std::cout << "simplify_byte_expr " << from_expr(dest) << std::endl; #endif root.swap(nested_root); #ifdef DEBUG std::cout << " ==> " << from_expr(dest) << std::endl; #endif } } } /* * byte_extract(byte_update(e, i, v, t), i, t) * => * v */ else if(dest.id()==ID_byte_extract_little_endian || dest.id()==ID_byte_extract_big_endian) { exprt &root=dest.op0(); exprt &offset=dest.op1(); const typet &type=dest.type(); if(root.id()==ID_byte_update_little_endian || root.id()==ID_byte_update_big_endian) { exprt &nested_offset=root.op1(); exprt &nested_with=root.op2(); const typet &nested_type=root.type(); if(offset == nested_offset && type == nested_type) { #ifdef DEBUG std::cout << "simplify_byte_expr " << from_expr(dest) << std::endl; #endif dest.swap(nested_with); //#ifdef DEBUG std::cout << " ==> " << from_expr(dest) << std::endl; //#endif } } } if(dest.has_operands()) Forall_operands(it, dest) simplify_byte_expr(*it, ns); }
bool simplify_exprt::simplify_address_of_arg(exprt &expr) { if(expr.id()==ID_index) { if(expr.operands().size()==2) { bool result=true; if(!simplify_address_of_arg(expr.op0())) result=false; if(!simplify_rec(expr.op1())) result=false; // rewrite (*(type *)int) [index] by // pushing the index inside mp_integer address; if(is_dereference_integer_object(expr.op0(), address)) { // push index into address mp_integer step_size, index; step_size=pointer_offset_size(expr.type(), ns); if(!to_integer(expr.op1(), index) && step_size!=-1) { unsignedbv_typet int_type(config.ansi_c.pointer_width); pointer_typet pointer_type; pointer_type.subtype()=expr.type(); typecast_exprt typecast_expr( from_integer(step_size*index+address, int_type), pointer_type); exprt new_expr=dereference_exprt(typecast_expr, expr.type()); expr=new_expr; result=true; } } return result; } } else if(expr.id()==ID_member) { if(expr.operands().size()==1) { bool result=true; if(!simplify_address_of_arg(expr.op0())) result=false; const typet &op_type=ns.follow(expr.op0().type()); if(op_type.id()==ID_struct) { // rewrite NULL -> member by // pushing the member inside mp_integer address; if(is_dereference_integer_object(expr.op0(), address)) { const struct_typet &struct_type=to_struct_type(op_type); const irep_idt &member=to_member_expr(expr).get_component_name(); mp_integer offset=member_offset(struct_type, member, ns); if(offset!=-1) { unsignedbv_typet int_type(config.ansi_c.pointer_width); pointer_typet pointer_type; pointer_type.subtype()=expr.type(); typecast_exprt typecast_expr( from_integer(address+offset, int_type), pointer_type); exprt new_expr=dereference_exprt(typecast_expr, expr.type()); expr=new_expr; result=true; } } } return result; } } else if(expr.id()==ID_dereference) { if(expr.operands().size()==1) return simplify_rec(expr.op0()); } else if(expr.id()==ID_if) { if(expr.operands().size()==3) { bool result=true; if(!simplify_rec(expr.op0())) result=false; if(!simplify_address_of_arg(expr.op1())) result=false; if(!simplify_address_of_arg(expr.op2())) result=false; // op0 is a constant? if(expr.op0().is_true()) { result=false; exprt tmp; tmp.swap(expr.op1()); expr.swap(tmp); } else if(expr.op0().is_false()) { result=false; exprt tmp; tmp.swap(expr.op2()); expr.swap(tmp); } return result; } } return true; }
void abstract_expression( const predicatest &predicates, exprt &expr, const namespacet &ns) { if(expr.type().id()!=ID_bool) throw "abstract_expression expects expression of type Boolean"; simplify(expr, ns); if(is_valid(expr, ns)) { // If expr is valid, we can abstract it as 'true' expr.make_true(); } else if(is_unsatisfiable(expr, ns)) { // If expr is unsatisfiable, we can abstract it as 'false' expr.make_false(); } else if(expr.id()==ID_and || expr.id()==ID_or || expr.id()==ID_implies || expr.id()==ID_xor) { Forall_operands(it, expr) abstract_expression(predicates, *it, ns); } else if(expr.id()==ID_not) { assert(expr.operands().size()==1); abstract_expression(predicates, expr.op0(), ns); // remove double negation if(expr.op0().id()==ID_not && expr.op0().operands().size()==1) { exprt tmp; tmp.swap(expr.op0().op0()); expr.swap(tmp); } } else if(expr.id()==ID_if) { assert(expr.operands().size()==3); Forall_operands(it, expr) abstract_expression(predicates, *it, ns); exprt true_expr(ID_and, bool_typet()); true_expr.copy_to_operands(expr.op0(), expr.op1()); exprt false_expr(ID_and, bool_typet()); false_expr.copy_to_operands(gen_not(expr.op0()), expr.op2()); exprt or_expr(ID_or, bool_typet()); or_expr.move_to_operands(true_expr, false_expr); expr.swap(or_expr); } else if(expr.id()==ID_equal || expr.id()==ID_notequal) { if(expr.operands().size()!=2) throw expr.id_string()+" takes two operands"; // Is it equality on Booleans? if(expr.op0().type().id()==ID_bool && expr.op1().type().id()==ID_bool) { // leave it in Forall_operands(it, expr) abstract_expression(predicates, *it, ns); } else // other types, make it a predicate { if(has_non_boolean_if(expr)) { lift_if(expr); abstract_expression(predicates, expr, ns); } else make_it_a_predicate(predicates, expr, ns); } } else if(expr.is_constant()) { // leave it as is } else if(has_non_boolean_if(expr)) { lift_if(expr); abstract_expression(predicates, expr, ns); } else { make_it_a_predicate(predicates, expr, ns); } }
bool simplify_exprt::simplify_floatbv_op(exprt &expr) { const typet &type=ns.follow(expr.type()); if(type.id()!=ID_floatbv) return true; assert(expr.operands().size()==3); exprt op0=expr.op0(); exprt op1=expr.op1(); exprt op2=expr.op2(); // rounding mode assert(ns.follow(op0.type())==type); assert(ns.follow(op1.type())==type); // Remember that floating-point addition is _NOT_ associative. // Thus, we don't re-sort the operands. // We only merge constants! if(op0.is_constant() && op1.is_constant() && op2.is_constant()) { ieee_floatt v0(to_constant_expr(op0)); ieee_floatt v1(to_constant_expr(op1)); mp_integer rounding_mode; if(!to_integer(op2, rounding_mode)) { v0.rounding_mode=(ieee_floatt::rounding_modet)integer2size_t(rounding_mode); v1.rounding_mode=v0.rounding_mode; ieee_floatt result=v0; if(expr.id()==ID_floatbv_plus) result+=v1; else if(expr.id()==ID_floatbv_minus) result-=v1; else if(expr.id()==ID_floatbv_mult) result*=v1; else if(expr.id()==ID_floatbv_div) result/=v1; else assert(false); expr=result.to_expr(); return false; } } // division by one? Exact for all rounding modes. if (expr.id()==ID_floatbv_div && op1.is_constant() && op1.is_one()) { exprt tmp; tmp.swap(op0); expr.swap(tmp); return false; } return true; }
bool ranking_synthesis_seneschalt::read_output(exprt &rf) { // Check if there is a result at all... std::ifstream err("seneschal.err"); bool result_found=false; while(err) { std::string line; std::getline(err, line); if(line=="Solving ... no solution" || line=="Solving ... found a solution") { result_found = true; break; } } err.close(); if(!result_found) return false; // There is a result! std::ifstream in("seneschal.out"); std::string rank_string; std::string bound_string; while(in) { std::string line; std::getline(in, line); if(line.substr(0,7)=="Ranking") { std::vector<std::string> tokens; tokenize(line, tokens, " =[],\tr"); bool work=false; for(std::vector<std::string>::const_iterator it=tokens.begin(); it!=tokens.end(); it++) { // std::cout << "TOKEN: " << *it << std::endl; if(*it=="Ranking") { result_found=true; work=true; } else if(*it=="function:") /* SKIP */ ; else if(work) { rank_string += " " + *it; } } } else if(line.substr(0,25)=="Lower bound (post-state):") { std::vector<std::string> tokens; tokenize(line, tokens, " =[],\t"); std::vector<std::string>::const_iterator it=tokens.begin(); it++; it++; it++; if(it!=tokens.end()) { //std::cout << "TOKEN: " << *it << std::endl; bound_string = *it; } }; } if(rank_string!="") { bound = string2integer(bound_string); if(bound!=0) rank_string = "(" + rank_string + ") - (" + bound_string + ")"; exprt rfl; if(parse_rank_function(rank_string, trans_context, ns, *message_handler, rfl)) throw ("RF EXTRACTION ERROR"); replace_expr(variable_map, rfl); std::cout << "FOUND FUNCTION: " << from_expr(ns, "", rfl) << std::endl; rf.swap(rfl); std::cout << "BOUND: " << bound << std::endl; } return true; }