exprt dereference_rec( const exprt &src, const ssa_value_domaint &ssa_value_domain, const std::string &nondet_prefix, const namespacet &ns) { if(src.id()==ID_dereference) { const exprt &pointer=dereference_rec( to_dereference_expr(src).pointer(), ssa_value_domain, nondet_prefix, ns); const typet &pointed_type=ns.follow(pointer.type().subtype()); const ssa_value_domaint::valuest values=ssa_value_domain(pointer, ns); exprt result; if(values.value_set.empty()) { result=pointed_object(pointer, ns); } else { auto it=values.value_set.begin(); if(values.null || values.unknown || (values.value_set.size()>1 && it->type().get_bool("#dynamic"))) { std::string dyn_type_name=pointed_type.id_string(); if(pointed_type.id()==ID_struct) dyn_type_name+="_"+id2string(to_struct_type(pointed_type).get_tag()); irep_idt identifier="ssa::"+dyn_type_name+"_obj$unknown"; result=symbol_exprt(identifier, src.type()); result.set("#unknown_obj", true); } else { result=ssa_alias_value(src, (it++)->get_expr(), ns); result.set("#heap_access", result.type().get_bool("#dynamic")); } for(; it!=values.value_set.end(); ++it) { exprt guard=ssa_alias_guard(src, it->get_expr(), ns); exprt value=ssa_alias_value(src, it->get_expr(), ns); result=if_exprt(guard, value, result); result.set( "#heap_access", result.get_bool("#heap_access") || value.type().get_bool("#dynamic")); } } return result; } else if(src.id()==ID_member) { member_exprt tmp=to_member_expr(src); tmp.struct_op()= dereference_rec(tmp.struct_op(), ssa_value_domain, nondet_prefix, ns); tmp.set("#heap_access", tmp.struct_op().get_bool("#heap_access")); #ifdef DEBUG std::cout << "dereference_rec tmp: " << from_expr(ns, "", tmp) << '\n'; #endif if(tmp.struct_op().is_nil()) return nil_exprt(); return lift_if(tmp); } else if(src.id()==ID_address_of) { address_of_exprt tmp=to_address_of_expr(src); tmp.object()= dereference_rec(tmp.object(), ssa_value_domain, nondet_prefix, ns); tmp.set("#heap_access", tmp.object().get_bool("#heap_access")); if(tmp.object().is_nil()) return nil_exprt(); return lift_if(tmp); } else { exprt tmp=src; Forall_operands(it, tmp) { *it=dereference_rec(*it, ssa_value_domain, nondet_prefix, ns); if(it->get_bool("#heap_access")) tmp.set("#heap_access", true); } return tmp; }
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); } }
exprt dereference_rec( const exprt &src, const ssa_value_domaint &ssa_value_domain, const std::string &nondet_prefix, const namespacet &ns) { if(src.id()==ID_dereference) { const exprt &pointer=to_dereference_expr(src).pointer(); exprt pointer_deref=dereference(pointer, ssa_value_domain, nondet_prefix, ns); // We use the identifier produced by // local_SSAt::replace_side_effects_rec exprt result=symbol_exprt(nondet_prefix, src.type()); // query the value sets const ssa_value_domaint::valuest values= ssa_value_domain(pointer, ns); for(ssa_value_domaint::valuest::value_sett::const_iterator it=values.value_set.begin(); it!=values.value_set.end(); it++) { exprt guard=ssa_alias_guard(src, it->get_expr(), ns); exprt value=ssa_alias_value(src, it->get_expr(), ns); result=if_exprt(guard, value, result); } return result; } else if(src.id()==ID_member) { member_exprt tmp=to_member_expr(src); tmp.struct_op()=dereference_rec(tmp.struct_op(), ssa_value_domain, nondet_prefix, ns); #ifdef DEBUG std::cout << "dereference_rec tmp: " << from_expr(ns, "", tmp) << '\n'; #endif if(tmp.struct_op().is_nil()) return nil_exprt(); return lift_if(tmp); } else if(src.id()==ID_address_of) { address_of_exprt tmp=to_address_of_expr(src); tmp.object()=dereference_rec(tmp.object(), ssa_value_domain, nondet_prefix, ns); if(tmp.object().is_nil()) return nil_exprt(); return lift_if(tmp); } else { exprt tmp=src; Forall_operands(it, tmp) *it=dereference_rec(*it, ssa_value_domain, nondet_prefix, ns); return tmp; } }
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; }