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); }
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 {
void interval_domaint::assume_rec( const exprt &lhs, irep_idt id, const exprt &rhs) { if(lhs.id()==ID_typecast) return assume_rec(to_typecast_expr(lhs).op(), id, rhs); if(rhs.id()==ID_typecast) return assume_rec(lhs, id, to_typecast_expr(rhs).op()); if(id==ID_equal) { assume_rec(lhs, ID_ge, rhs); assume_rec(lhs, ID_le, rhs); return; } if(id==ID_notequal) return; // won't do split if(id==ID_ge) return assume_rec(rhs, ID_le, lhs); if(id==ID_gt) return assume_rec(rhs, ID_lt, lhs); // we now have lhs < rhs or // lhs <= rhs assert(id==ID_lt || id==ID_le); #ifdef DEBUG std::cout << "assume_rec: " << from_expr(lhs) << " " << id << " " << from_expr(rhs) << "\n"; #endif if(lhs.id()==ID_symbol && rhs.id()==ID_constant) { irep_idt lhs_identifier=to_symbol_expr(lhs).get_identifier(); if(is_int(lhs.type()) && is_int(rhs.type())) { mp_integer tmp; to_integer(rhs, tmp); if(id==ID_lt) --tmp; integer_intervalt &ii=int_map[lhs_identifier]; ii.make_le_than(tmp); if(ii.is_bottom()) make_bottom(); } else if(is_float(lhs.type()) && is_float(rhs.type())) { ieee_floatt tmp(to_constant_expr(rhs)); if(id==ID_lt) tmp.decrement(); ieee_float_intervalt &fi=float_map[lhs_identifier]; fi.make_le_than(tmp); if(fi.is_bottom()) make_bottom(); } } else if(lhs.id()==ID_constant && rhs.id()==ID_symbol) { irep_idt rhs_identifier=to_symbol_expr(rhs).get_identifier(); if(is_int(lhs.type()) && is_int(rhs.type())) { mp_integer tmp; to_integer(lhs, tmp); if(id==ID_lt) ++tmp; integer_intervalt &ii=int_map[rhs_identifier]; ii.make_ge_than(tmp); if(ii.is_bottom()) make_bottom(); } else if(is_float(lhs.type()) && is_float(rhs.type())) { ieee_floatt tmp(to_constant_expr(lhs)); if(id==ID_lt) tmp.increment(); ieee_float_intervalt &fi=float_map[rhs_identifier]; fi.make_ge_than(tmp); if(fi.is_bottom()) make_bottom(); } } else if(lhs.id()==ID_symbol && rhs.id()==ID_symbol) { irep_idt lhs_identifier=to_symbol_expr(lhs).get_identifier(); irep_idt rhs_identifier=to_symbol_expr(rhs).get_identifier(); if(is_int(lhs.type()) && is_int(rhs.type())) { integer_intervalt &lhs_i=int_map[lhs_identifier]; integer_intervalt &rhs_i=int_map[rhs_identifier]; lhs_i.meet(rhs_i); rhs_i=lhs_i; if(rhs_i.is_bottom()) make_bottom(); } else if(is_float(lhs.type()) && is_float(rhs.type())) { ieee_float_intervalt &lhs_i=float_map[lhs_identifier]; ieee_float_intervalt &rhs_i=float_map[rhs_identifier]; lhs_i.meet(rhs_i); rhs_i=lhs_i; if(rhs_i.is_bottom()) make_bottom(); } } }
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)integer2long(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; }
exprt c_typecheck_baset::do_initializer_rec( const exprt &value, const typet &type, bool force_constant) { const typet &full_type=follow(type); if(full_type.id()==ID_incomplete_struct) { err_location(value); error() << "type `" << to_string(full_type) << "' is still incomplete -- cannot initialize" << eom; throw 0; } if(value.id()==ID_initializer_list) return do_initializer_list(value, type, force_constant); if(value.id()==ID_array && value.get_bool(ID_C_string_constant) && full_type.id()==ID_array && (full_type.subtype().id()==ID_signedbv || full_type.subtype().id()==ID_unsignedbv) && full_type.subtype().get(ID_width)==value.type().subtype().get(ID_width)) { exprt tmp=value; // adjust char type tmp.type().subtype()=full_type.subtype(); Forall_operands(it, tmp) it->type()=full_type.subtype(); if(full_type.id()==ID_array && to_array_type(full_type).is_complete()) { // check size mp_integer array_size; if(to_integer(to_array_type(full_type).size(), array_size)) { err_location(value); error() << "array size needs to be constant, got " << to_string(to_array_type(full_type).size()) << eom; throw 0; } if(array_size<0) { err_location(value); error() << "array size must not be negative" << eom; throw 0; } if(mp_integer(tmp.operands().size())>array_size) { // cut off long strings. gcc does a warning for this tmp.operands().resize(integer2size_t(array_size)); tmp.type()=type; } else if(mp_integer(tmp.operands().size())<array_size) { // fill up tmp.type()=type; exprt zero=zero_initializer(full_type.subtype(), value.source_location(), *this, get_message_handler()); tmp.operands().resize(integer2size_t(array_size), zero); } } return tmp; } if(value.id()==ID_string_constant && full_type.id()==ID_array && (full_type.subtype().id()==ID_signedbv || full_type.subtype().id()==ID_unsignedbv) && full_type.subtype().get(ID_width)==char_type().get(ID_width)) { // will go away, to be replaced by the above block string_constantt tmp1=to_string_constant(value); // adjust char type tmp1.type().subtype()=full_type.subtype(); exprt tmp2=tmp1.to_array_expr(); if(full_type.id()==ID_array && to_array_type(full_type).is_complete()) { // check size mp_integer array_size; if(to_integer(to_array_type(full_type).size(), array_size)) { err_location(value); error() << "array size needs to be constant, got " << to_string(to_array_type(full_type).size()) << eom; throw 0; } if(array_size<0) { err_location(value); error() << "array size must not be negative" << eom; throw 0; } if(mp_integer(tmp2.operands().size())>array_size) { // cut off long strings. gcc does a warning for this tmp2.operands().resize(integer2size_t(array_size)); tmp2.type()=type; } else if(mp_integer(tmp2.operands().size())<array_size) { // fill up tmp2.type()=type; exprt zero=zero_initializer(full_type.subtype(), value.source_location(), *this, get_message_handler()); tmp2.operands().resize(integer2size_t(array_size), zero); } } return tmp2; } if(full_type.id()==ID_array && to_array_type(full_type).size().is_nil()) { err_location(value); error() << "type `" << to_string(full_type) << "' cannot be initialized with `" << to_string(value) << "'" << eom; throw 0; } if(value.id()==ID_designated_initializer) { err_location(value); error() << "type `" << to_string(full_type) << "' cannot be initialized with designated initializer" << eom; throw 0; } exprt result=value; implicit_typecast(result, type); return result; }
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 boolbvt::convert_constraint_select_one(const exprt &expr, bvt &bv) { const exprt::operandst &operands=expr.operands(); if(expr.id()!="constraint_select_one") throw "expected constraint_select_one expression"; if(operands.size()<2) throw "constraint_select_one takes at least two operands"; if(expr.type()!=expr.op0().type()) throw "constraint_select_one expects matching types"; if(prop.has_set_to()) { std::vector<bvt> op_bv; op_bv.reserve(expr.operands().size()); forall_operands(it, expr) op_bv.push_back(convert_bv(*it)); bv=op_bv[0]; // add constraints bvt equal_bv; equal_bv.resize(bv.size()); bvt b; b.reserve(op_bv.size()-1); for(unsigned i=1; i<op_bv.size(); i++) { if(op_bv[i].size()!=bv.size()) throw "constraint_select_one expects matching width"; for(unsigned j=0; j<bv.size(); j++) equal_bv[j]=prop.lequal(bv[j], op_bv[i][j]); b.push_back(prop.land(equal_bv)); } prop.l_set_to_true(prop.lor(b)); } else { unsigned op_nr=0; forall_operands(it, expr) { const bvt &op_bv=convert_bv(*it); if(op_nr==0) bv=op_bv; else { if(op_bv.size()!=bv.size()) return conversion_failed(expr, bv); for(unsigned i=0; i<op_bv.size(); i++) bv[i]=prop.lselect(prop.new_variable(), bv[i], op_bv[i]); } op_nr++; } } }
void convert_float_literal(const std::string &src, exprt &dest) { mp_integer significand; mp_integer exponent; bool is_float, is_long; unsigned base; parse_float(src, significand, exponent, base, is_float, is_long); dest = exprt("constant"); dest.cformat(src); if(is_float) { dest.type() = float_type(); dest.type().set("#cpp_type", "float"); } else if(is_long) { dest.type() = long_double_type(); dest.type().set("#cpp_type", "long_double"); } else { dest.type() = double_type(); dest.type().set("#cpp_type", "double"); } if(config.ansi_c.use_fixed_for_float) { unsigned width = atoi(dest.type().width().c_str()); unsigned fraction_bits; const std::string &integer_bits = dest.type().integer_bits().as_string(); if(integer_bits == "") fraction_bits = width / 2; else fraction_bits = width - atoi(integer_bits.c_str()); mp_integer factor = mp_integer(1) << fraction_bits; mp_integer value = significand * factor; if(value != 0) { if(exponent < 0) value /= power(base, -exponent); else { value *= power(base, exponent); if(value >= power(2, width - 1)) { // saturate: use "biggest value" value = power(2, width - 1) - 1; } else if(value <= -power(2, width - 1) - 1) { // saturate: use "smallest value" value = -power(2, width - 1); } } } dest.value(integer2binary(value, width)); } else { ieee_floatt a; a.spec = to_floatbv_type(dest.type()); if(base == 10) a.from_base10(significand, exponent); else if(base == 2) // hex a.build(significand, exponent); else assert(false); dest.value(integer2binary(a.pack(), a.spec.width())); } }
void arrayst::collect_arrays(const exprt &a) { const array_typet &array_type= to_array_type(ns.follow(a.type())); if(a.id()==ID_with) { if(a.operands().size()!=3) throw "with expected to have three operands"; // check types if(!base_type_eq(array_type, a.op0().type(), ns)) { std::cout << a.pretty() << std::endl; throw "collect_arrays got with without matching types"; } arrays.make_union(a, a.op0()); collect_arrays(a.op0()); // make sure this shows as an application index_exprt index_expr; index_expr.type()=array_type.subtype(); index_expr.array()=a.op0(); index_expr.index()=a.op1(); record_array_index(index_expr); } else if(a.id()==ID_if) { if(a.operands().size()!=3) throw "if expected to have three operands"; // check types if(!base_type_eq(array_type, a.op1().type(), ns)) { std::cout << a.pretty() << std::endl; throw "collect_arrays got if without matching types"; } // check types if(!base_type_eq(array_type, a.op2().type(), ns)) { std::cout << a.pretty() << std::endl; throw "collect_arrays got if without matching types"; } arrays.make_union(a, a.op1()); arrays.make_union(a, a.op2()); collect_arrays(a.op1()); collect_arrays(a.op2()); } else if(a.id()==ID_symbol) { } else if(a.id()==ID_nondet_symbol) { } else if(a.id()==ID_member) { if(to_member_expr(a).struct_op().id()!=ID_symbol) throw "unexpected array expression: member with `"+a.op0().id_string()+"'"; } else if(a.id()==ID_constant || a.id()==ID_array || a.id()==ID_string_constant) { } else if(a.id()==ID_array_of) { } else throw "unexpected array expression: `"+a.id_string()+"'"; }
bool remove_const_function_pointerst::is_const_expression( const exprt &expression) const { return is_const_type(expression.type()); }
void boolbvt::convert_with_array( const array_typet &type, const exprt &op1, const exprt &op2, const bvt &prev_bv, bvt &next_bv) { if(is_unbounded_array(type)) { // can't do this error().source_location=type.source_location(); error() << "convert_with_array called for unbounded array" << eom; throw 0; } const exprt &array_size=type.size(); mp_integer size; if(to_integer(array_size, size)) { error().source_location=type.source_location(); error() << "convert_with_array expects constant array size" << eom; throw 0; } const bvt &op2_bv=convert_bv(op2); if(size*op2_bv.size()!=prev_bv.size()) { error().source_location=type.source_location(); error() << "convert_with_array: unexpected operand 2 width" << eom; throw 0; } // Is the index a constant? mp_integer op1_value; if(!to_integer(op1, op1_value)) { // Yes, it is! next_bv=prev_bv; if(op1_value>=0 && op1_value<size) // bounds check { std::size_t offset=integer2unsigned(op1_value*op2_bv.size()); for(std::size_t j=0; j<op2_bv.size(); j++) next_bv[offset+j]=op2_bv[j]; } return; } typet counter_type=op1.type(); for(mp_integer i=0; i<size; i=i+1) { exprt counter=from_integer(i, counter_type); literalt eq_lit=convert(equal_exprt(op1, counter)); std::size_t offset=integer2unsigned(i*op2_bv.size()); for(std::size_t j=0; j<op2_bv.size(); j++) next_bv[offset+j]= prop.lselect(eq_lit, op2_bv[j], prev_bv[offset+j]); } }
exprt pointer_logict::object_rec( const mp_integer &offset, const typet &pointer_type, const exprt &src) const { if(src.type().id()==ID_array) { mp_integer size= pointer_offset_size(ns, src.type().subtype()); if(size==0) return src; mp_integer index=offset/size; mp_integer rest=offset%size; if(rest<0) rest=-rest; index_exprt tmp(src.type().subtype()); tmp.index()=from_integer(index, typet(ID_integer)); tmp.array()=src; return object_rec(rest, pointer_type, tmp); } else if(src.type().id()==ID_struct) { const struct_typet::componentst &components= to_struct_type(src.type()).components(); if(offset<0) return src; mp_integer current_offset=0; for(struct_typet::componentst::const_iterator it=components.begin(); it!=components.end(); it++) { assert(offset>=current_offset); const typet &subtype=it->type(); mp_integer sub_size=pointer_offset_size(ns, subtype); mp_integer new_offset=current_offset+sub_size; if(new_offset>offset) { // found it member_exprt tmp(subtype); tmp.set_component_name(it->get_name()); tmp.op0()=src; return object_rec( offset-current_offset, pointer_type, tmp); } assert(new_offset<=offset); current_offset=new_offset; assert(current_offset<=offset); } return src; } else if(src.type().id()==ID_union) return src; return src; }
void bv_cbmct::convert_waitfor(const exprt &expr, bvt &bv) { if(expr.operands().size()!=4) throw "waitfor expected to have four operands"; exprt new_cycle; const exprt &old_cycle=expr.op0(); const exprt &cycle_var=expr.op1(); const exprt &bound=expr.op2(); const exprt &predicate=expr.op3(); make_free_bv_expr(expr.type(), new_cycle); mp_integer bound_value; if(to_integer(bound, bound_value)) throw "waitfor bound must be a constant"; { // constraint: new_cycle>=old_cycle exprt rel_expr(ID_ge, bool_typet()); rel_expr.copy_to_operands(new_cycle, old_cycle); set_to_true(rel_expr); } { // constraint: new_cycle<=bound+1 exprt one=from_integer(1, bound.type()); exprt bound_plus1(ID_plus, bound.type()); bound_plus1.reserve_operands(2); bound_plus1.copy_to_operands(bound); bound_plus1.move_to_operands(one); exprt rel_expr(ID_le, bool_typet()); rel_expr.copy_to_operands(new_cycle, bound_plus1); set_to_true(rel_expr); } for(mp_integer i=0; i<=bound_value; i=i+1) { // replace cycle_var by old_cycle+i; exprt old_cycle_plus_i(ID_plus, old_cycle.type()); old_cycle_plus_i.operands().resize(2); old_cycle_plus_i.op0()=old_cycle; old_cycle_plus_i.op1()=from_integer(i, old_cycle.type()); exprt tmp_predicate=predicate; replace_expr(cycle_var, old_cycle_plus_i, tmp_predicate); // CONSTRAINT: // if((cycle)<=bound) { // if((cycle)<new_cycle) // assume(!property); // else if((cycle)==new_cycle) // assume(property); { exprt cycle_le_bound(ID_le, bool_typet()); cycle_le_bound.operands().resize(2); cycle_le_bound.op0()=old_cycle_plus_i; cycle_le_bound.op1()=bound; exprt cycle_lt_new_cycle(ID_lt, bool_typet()); cycle_lt_new_cycle.operands().resize(2); cycle_lt_new_cycle.op0()=old_cycle_plus_i; cycle_lt_new_cycle.op1()=new_cycle; exprt and_expr(ID_and, bool_typet()); and_expr.operands().resize(2); and_expr.op0().swap(cycle_le_bound); and_expr.op1().swap(cycle_lt_new_cycle); exprt top_impl(ID_implies, bool_typet()); top_impl.reserve_operands(2); top_impl.move_to_operands(and_expr); top_impl.copy_to_operands(tmp_predicate); top_impl.op1().make_not(); set_to_true(top_impl); } { exprt cycle_le_bound(ID_le, bool_typet()); cycle_le_bound.operands().resize(2); cycle_le_bound.op0()=old_cycle_plus_i; cycle_le_bound.op1()=bound; exprt cycle_eq_new_cycle(ID_equal, bool_typet()); cycle_eq_new_cycle.operands().resize(2); cycle_eq_new_cycle.op0()=old_cycle_plus_i; cycle_eq_new_cycle.op1()=new_cycle; exprt and_expr(ID_and, bool_typet()); and_expr.operands().resize(2); and_expr.op0().swap(cycle_le_bound); and_expr.op1().swap(cycle_eq_new_cycle); exprt top_impl(ID_implies, bool_typet()); top_impl.reserve_operands(2); top_impl.move_to_operands(and_expr); top_impl.copy_to_operands(tmp_predicate); set_to_true(top_impl); } } // result: new_cycle return convert_bitvector(new_cycle, bv); }
void bv_arithmetict::from_expr(const exprt &expr) { assert(expr.is_constant()); spec=expr.type(); value=binary2integer(expr.get_string(ID_value), spec.is_signed); }
bvt boolbvt::convert_floatbv_op(const exprt &expr) { const exprt::operandst &operands=expr.operands(); if(operands.size()!=3) throw "operator "+expr.id_string()+" takes three operands"; const exprt &op0=expr.op0(); // first operand const exprt &op1=expr.op1(); // second operand const exprt &op2=expr.op2(); // rounding mode bvt bv0=convert_bv(op0); bvt bv1=convert_bv(op1); bvt bv2=convert_bv(op2); const typet &type=ns.follow(expr.type()); if(op0.type()!=type || op1.type()!=type) { std::cerr << expr.pretty() << std::endl; throw "float op with mixed types"; } float_utilst float_utils(prop); float_utils.set_rounding_mode(bv2); if(type.id()==ID_floatbv) { float_utils.spec=to_floatbv_type(expr.type()); if(expr.id()==ID_floatbv_plus) return float_utils.add_sub(bv0, bv1, false); else if(expr.id()==ID_floatbv_minus) return float_utils.add_sub(bv0, bv1, true); else if(expr.id()==ID_floatbv_mult) return float_utils.mul(bv0, bv1); else if(expr.id()==ID_floatbv_div) return float_utils.div(bv0, bv1); else if(expr.id()==ID_floatbv_rem) return float_utils.rem(bv0, bv1); else assert(false); } else if(type.id()==ID_vector || type.id()==ID_complex) { const typet &subtype=ns.follow(type.subtype()); if(subtype.id()==ID_floatbv) { float_utils.spec=to_floatbv_type(subtype); std::size_t width=boolbv_width(type); std::size_t sub_width=boolbv_width(subtype); if(sub_width==0 || width%sub_width!=0) throw "convert_floatbv_op: unexpected vector operand width"; std::size_t size=width/sub_width; bvt bv; bv.resize(width); for(std::size_t i=0; i<size; i++) { bvt tmp_bv0, tmp_bv1, tmp_bv; tmp_bv0.assign(bv0.begin()+i*sub_width, bv0.begin()+(i+1)*sub_width); tmp_bv1.assign(bv1.begin()+i*sub_width, bv1.begin()+(i+1)*sub_width); if(expr.id()==ID_floatbv_plus) tmp_bv=float_utils.add_sub(tmp_bv0, tmp_bv1, false); else if(expr.id()==ID_floatbv_minus) tmp_bv=float_utils.add_sub(tmp_bv0, tmp_bv1, true); else if(expr.id()==ID_floatbv_mult) tmp_bv=float_utils.mul(tmp_bv0, tmp_bv1); else if(expr.id()==ID_floatbv_div) tmp_bv=float_utils.div(tmp_bv0, tmp_bv1); else assert(false); assert(tmp_bv.size()==sub_width); assert(i*sub_width+sub_width-1<bv.size()); std::copy(tmp_bv.begin(), tmp_bv.end(), bv.begin()+i*sub_width); } return bv; } else return conversion_failed(expr); } else return conversion_failed(expr); }
literalt equalityt::equality2(const exprt &e1, const exprt &e2) { const typet &type=e1.type(); if(e2.type()!=e1.type()) throw "equality got different types"; // check for syntactical equality if(e1==e2) return const_literal(true); // check for boolean equality if(type.id()==ID_bool) throw "equalityt got boolean equality"; // return lequal(convert(e1), convert(e2)); // look it up typestructt &typestruct=typemap[type]; elementst &elements=typestruct.elements; elements_revt &elements_rev=typestruct.elements_rev; equalitiest &equalities=typestruct.equalities; std::pair<unsigned, unsigned> u; { std::pair<elementst::iterator, bool> result= elements.insert(std::pair<exprt, unsigned>(e1, elements.size())); u.first=result.first->second; if(result.second) elements_rev[u.first]=e1; } { std::pair<elementst::iterator, bool> result= elements.insert(elementst::value_type(e2, elements.size())); u.second=result.first->second; if(result.second) elements_rev[u.second]=e2; } literalt l; { equalitiest::const_iterator result=equalities.find(u); if(result==equalities.end()) { l=prop.new_variable(); if(freeze_all && !l.is_constant()) prop.set_frozen(l); equalities.insert(equalitiest::value_type(u, l)); } else l=result->second; } #ifdef DEBUG std::cout << "EQUALITY " << l << "<=>" << e1 << "=" << e2 << std::endl; #endif return l; }
/// get a boolean value from counter example if not valid bool prop_conv_solvert::get_bool(const exprt &expr, tvt &value) const { // trivial cases if(expr.is_true()) { value=tvt(true); return false; } else if(expr.is_false()) { value=tvt(false); return false; } else if(expr.id()==ID_symbol) { symbolst::const_iterator result= symbols.find(to_symbol_expr(expr).get_identifier()); if(result==symbols.end()) return true; value=prop.l_get(result->second); return false; } // sub-expressions if(expr.id()==ID_not) { if(expr.type().id()==ID_bool && expr.operands().size()==1) { if(get_bool(expr.op0(), value)) return true; value=!value; return false; } } else if(expr.id()==ID_and || expr.id()==ID_or) { if(expr.type().id()==ID_bool && expr.operands().size()>=1) { value=tvt(expr.id()==ID_and); forall_operands(it, expr) { tvt tmp; if(get_bool(*it, tmp)) return true; if(expr.id()==ID_and) { if(tmp.is_false()) { value=tvt(false); return false; } value=value && tmp; } else // or { if(tmp.is_true()) { value=tvt(true); return false; } value=value || tmp; } } return false; }
void disjunctive_polynomial_accelerationt::assert_for_values( scratch_programt &program, std::map<exprt, exprt> &values, std::set<std::pair<expr_listt, exprt> > &coefficients, int num_unwindings, goto_programt &loop_body, exprt &target) { // First figure out what the appropriate type for this expression is. typet expr_type = nil_typet(); for (std::map<exprt, exprt>::iterator it = values.begin(); it != values.end(); ++it) { if (expr_type == nil_typet()) { expr_type = it->first.type(); } else { expr_type = join_types(expr_type, it->first.type()); } } // Now set the initial values of the all the variables... for (std::map<exprt, exprt>::iterator it = values.begin(); it != values.end(); ++it) { program.assign(it->first, it->second); } // Now unwind the loop as many times as we need to. for (int i = 0; i < num_unwindings; i++) { program.append(loop_body); } // Now build the polynomial for this point and assert it fits. exprt rhs = nil_exprt(); for (std::set<std::pair<expr_listt, exprt> >::iterator it = coefficients.begin(); it != coefficients.end(); ++it) { exprt concrete_value = from_integer(1, expr_type); for (expr_listt::const_iterator e_it = it->first.begin(); e_it != it->first.end(); ++e_it) { exprt e = *e_it; if (e == loop_counter) { mult_exprt mult(from_integer(num_unwindings, expr_type), concrete_value); mult.swap(concrete_value); } else { std::map<exprt, exprt>::iterator v_it = values.find(e); assert(v_it != values.end()); mult_exprt mult(concrete_value, v_it->second); mult.swap(concrete_value); } } // OK, concrete_value now contains the value of all the relevant variables // multiplied together. Create the term concrete_value*coefficient and add // it into the polynomial. typecast_exprt cast(it->second, expr_type); exprt term = mult_exprt(concrete_value, cast); if (rhs.is_nil()) { rhs = term; } else { rhs = plus_exprt(rhs, term); } } rhs = typecast_exprt(rhs, target.type()); // We now have the RHS of the polynomial. Assert that this is equal to the // actual value of the variable we're fitting. exprt polynomial_holds = equal_exprt(target, rhs); // Finally, assert that the polynomial equals the variable we're fitting. goto_programt::targett assumption = program.add_instruction(ASSUME); assumption->guard = polynomial_holds; }
void interpretert::evaluate( const exprt &expr, std::vector<mp_integer> &dest) const { if(expr.id()==ID_constant) { if(expr.type().id()==ID_struct) { } else if(expr.type().id()==ID_floatbv) { ieee_floatt f; f.from_expr(to_constant_expr(expr)); dest.push_back(f.pack()); return; } else if(expr.type().id()==ID_fixedbv) { fixedbvt f; f.from_expr(to_constant_expr(expr)); dest.push_back(f.get_value()); return; } else if(expr.type().id()==ID_bool) { dest.push_back(expr.is_true()); return; } else { mp_integer i; if(!to_integer(expr, i)) { dest.push_back(i); return; } } } else if(expr.id()==ID_struct) { dest.reserve(get_size(expr.type())); bool error=false; forall_operands(it, expr) { if(it->type().id()==ID_code) continue; unsigned sub_size=get_size(it->type()); if(sub_size==0) continue; std::vector<mp_integer> tmp; evaluate(*it, tmp); if(tmp.size()==sub_size) { for(unsigned i=0; i<sub_size; i++) dest.push_back(tmp[i]); } else error=true; } if(!error) return; dest.clear(); }
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)integer2long(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)integer2long(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)integer2long(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; }
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 c_typecheck_baset::do_designated_initializer( exprt &result, designatort &designator, const exprt &value, bool force_constant) { assert(!designator.empty()); if(value.id()==ID_designated_initializer) { assert(value.operands().size()==1); designator= make_designator( designator.front().type, static_cast<const exprt &>(value.find(ID_designator))); assert(!designator.empty()); return do_designated_initializer( result, designator, value.op0(), force_constant); } exprt *dest=&result; // first phase: follow given designator for(size_t i=0; i<designator.size(); i++) { size_t index=designator[i].index; const typet &type=designator[i].type; const typet &full_type=follow(type); if(full_type.id()==ID_array || full_type.id()==ID_vector) { if(index>=dest->operands().size()) { if(full_type.id()==ID_array && (to_array_type(full_type).size().is_zero() || to_array_type(full_type).size().is_nil())) { // we are willing to grow an incomplete or zero-sized array exprt zero=zero_initializer(full_type.subtype(), value.source_location(), *this, get_message_handler()); dest->operands().resize(integer2size_t(index)+1, zero); // todo: adjust type! } else { err_location(value); error() << "array index designator " << index << " out of bounds (" << dest->operands().size() << ")" << eom; throw 0; } } dest=&(dest->operands()[integer2size_t(index)]); } else if(full_type.id()==ID_struct) { const struct_typet::componentst &components= to_struct_type(full_type).components(); if(index>=dest->operands().size()) { err_location(value); error() << "structure member designator " << index << " out of bounds (" << dest->operands().size() << ")" << eom; throw 0; } assert(index<components.size()); assert(components[index].type().id()!=ID_code && !components[index].get_is_padding()); dest=&(dest->operands()[index]); } else if(full_type.id()==ID_union) { const union_typet &union_type=to_union_type(full_type); const union_typet::componentst &components= union_type.components(); assert(index<components.size()); const union_typet::componentt &component=union_type.components()[index]; if(dest->id()==ID_union && dest->get(ID_component_name)==component.get_name()) { // Already right union component. We can initialize multiple submembers, // so do not overwrite this. } else { // Note that gcc issues a warning if the union component is switched. // Build a union expression from given component. union_exprt union_expr(type); union_expr.op()=zero_initializer(component.type(), value.source_location(), *this, get_message_handler()); union_expr.add_source_location()=value.source_location(); union_expr.set_component_name(component.get_name()); *dest=union_expr; } dest=&(dest->op0()); } else assert(false); } // second phase: assign value // for this, we may need to go down, adding to the designator while(true) { // see what type we have to initialize const typet &type=designator.back().subtype; const typet &full_type=follow(type); assert(full_type.id()!=ID_symbol); // do we initialize a scalar? if(full_type.id()!=ID_struct && full_type.id()!=ID_union && full_type.id()!=ID_array && full_type.id()!=ID_vector) { // The initializer for a scalar shall be a single expression, // * optionally enclosed in braces. * if(value.id()==ID_initializer_list && value.operands().size()==1) *dest=do_initializer_rec(value.op0(), type, force_constant); else *dest=do_initializer_rec(value, type, force_constant); assert(full_type==follow(dest->type())); return; // done } // union? The component in the zero initializer might // not be the first one. if(full_type.id()==ID_union) { const union_typet &union_type=to_union_type(full_type); const union_typet::componentst &components= union_type.components(); if(!components.empty()) { const union_typet::componentt &component=union_type.components().front(); union_exprt union_expr(type); union_expr.op()=zero_initializer(component.type(), value.source_location(), *this, get_message_handler()); union_expr.add_source_location()=value.source_location(); union_expr.set_component_name(component.get_name()); *dest=union_expr; } } // see what initializer we are given if(value.id()==ID_initializer_list) { *dest=do_initializer_rec(value, type, force_constant); return; // done } else if(value.id()==ID_string_constant) { // We stop for initializers that are string-constants, // which are like arrays. We only do so if we are to // initialize an array of scalars. if(full_type.id()==ID_array && (follow(full_type.subtype()).id()==ID_signedbv || follow(full_type.subtype()).id()==ID_unsignedbv)) { *dest=do_initializer_rec(value, type, force_constant); return; // done } } else if(follow(value.type())==full_type) { // a struct/union/vector can be initialized directly with // an expression of the right type. This doesn't // work with arrays, unfortunately. if(full_type.id()==ID_struct || full_type.id()==ID_union || full_type.id()==ID_vector) { *dest=value; return; // done } } assert(full_type.id()==ID_struct || full_type.id()==ID_union || full_type.id()==ID_array || full_type.id()==ID_vector); // we are initializing a compound type, and enter it! // this may change the type, full_type might not be valid anymore const typet dest_type=full_type; designator_enter(type, designator); if(dest->operands().empty()) { err_location(value); error() << "cannot initialize type `" << to_string(dest_type) << "' using value `" << to_string(value) << "'" << eom; throw 0; } dest=&(dest->op0()); // we run into another loop iteration } }
void make_type(exprt &dest, const typet &type) { if(ns.follow(dest.type())!=ns.follow(type)) dest.make_typecast(type); }
void value_sett::get_value_set_rec( const exprt &expr, object_mapt &dest, const std::string &suffix, const typet &original_type, const namespacet &ns) const { #if 0 std::cout << "GET_VALUE_SET_REC EXPR: " << from_expr(ns, "", expr) << "\n"; std::cout << "GET_VALUE_SET_REC SUFFIX: " << suffix << '\n'; #endif const typet &expr_type=ns.follow(expr.type()); if(expr.id()==ID_unknown || expr.id()==ID_invalid) { insert(dest, exprt(ID_unknown, original_type)); } else if(expr.id()==ID_index) { assert(expr.operands().size()==2); const typet &type=ns.follow(expr.op0().type()); assert(type.id()==ID_array || type.id()==ID_incomplete_array); get_value_set_rec(expr.op0(), dest, "[]"+suffix, original_type, ns); } else if(expr.id()==ID_member) { assert(expr.operands().size()==1); const typet &type=ns.follow(expr.op0().type()); assert(type.id()==ID_struct || type.id()==ID_union || type.id()==ID_incomplete_struct || type.id()==ID_incomplete_union); const std::string &component_name= expr.get_string(ID_component_name); get_value_set_rec(expr.op0(), dest, "."+component_name+suffix, original_type, ns); } else if(expr.id()==ID_symbol) { irep_idt identifier=to_symbol_expr(expr).get_identifier(); // is it a pointer, integer, array or struct? if(expr_type.id()==ID_pointer || expr_type.id()==ID_signedbv || expr_type.id()==ID_unsignedbv || expr_type.id()==ID_struct || expr_type.id()==ID_union || expr_type.id()==ID_array) { // look it up valuest::const_iterator v_it= values.find(id2string(identifier)+suffix); // try first component name as suffix if not yet found if(v_it==values.end() && (expr_type.id()==ID_struct || expr_type.id()==ID_union)) { const struct_union_typet &struct_union_type= to_struct_union_type(expr_type); const std::string first_component_name= struct_union_type.components().front().get_string(ID_name); v_it=values.find( id2string(identifier)+"."+first_component_name+suffix); } // not found? try without suffix if(v_it==values.end()) v_it=values.find(identifier); if(v_it!=values.end()) make_union(dest, v_it->second.object_map); else insert(dest, exprt(ID_unknown, original_type)); } else insert(dest, exprt(ID_unknown, original_type)); } else if(expr.id()==ID_if) { if(expr.operands().size()!=3) throw "if takes three operands"; get_value_set_rec(expr.op1(), dest, suffix, original_type, ns); get_value_set_rec(expr.op2(), dest, suffix, original_type, ns); } else if(expr.id()==ID_address_of) { if(expr.operands().size()!=1) throw expr.id_string()+" expected to have one operand"; get_reference_set(expr.op0(), dest, ns); } else if(expr.id()==ID_dereference) { object_mapt reference_set; get_reference_set(expr, reference_set, ns); const object_map_dt &object_map=reference_set.read(); if(object_map.begin()==object_map.end()) insert(dest, exprt(ID_unknown, original_type)); else { for(object_map_dt::const_iterator it1=object_map.begin(); it1!=object_map.end(); it1++) { const exprt &object=object_numbering[it1->first]; get_value_set_rec(object, dest, suffix, original_type, ns); } } } else if(expr.id()=="reference_to") { // old stuff, will go away object_mapt reference_set; get_reference_set(expr, reference_set, ns); const object_map_dt &object_map=reference_set.read(); if(object_map.begin()==object_map.end()) insert(dest, exprt(ID_unknown, original_type)); else { for(object_map_dt::const_iterator it=object_map.begin(); it!=object_map.end(); it++) { const exprt &object=object_numbering[it->first]; get_value_set_rec(object, dest, suffix, original_type, ns); } } } else if(expr.is_constant()) { // check if NULL if(expr.get(ID_value)==ID_NULL && expr_type.id()==ID_pointer) { insert(dest, exprt("NULL-object", expr_type.subtype()), 0); } else if(expr_type.id()==ID_unsignedbv || expr_type.id()==ID_signedbv) { // an integer constant got turned into a pointer insert(dest, exprt(ID_integer_address, unsigned_char_type())); } else insert(dest, exprt(ID_unknown, original_type)); } else if(expr.id()==ID_typecast) { if(expr.operands().size()!=1) throw "typecast takes one operand"; // let's see what gets converted to what const typet &op_type=ns.follow(expr.op0().type()); if(op_type.id()==ID_pointer) { // pointer-to-pointer -- we just ignore these get_value_set_rec(expr.op0(), dest, suffix, original_type, ns); } else if(op_type.id()==ID_unsignedbv || op_type.id()==ID_signedbv) { // integer-to-pointer if(expr.op0().is_zero()) insert(dest, exprt("NULL-object", expr_type.subtype()), 0); else { // see if we have something for the integer object_mapt tmp; get_value_set_rec(expr.op0(), tmp, suffix, original_type, ns); if(tmp.read().empty()) { // if not, throw in integer insert(dest, exprt(ID_integer_address, unsigned_char_type())); } else if(tmp.read().size()==1 && object_numbering[tmp.read().begin()->first].id()==ID_unknown) { // if not, throw in integer insert(dest, exprt(ID_integer_address, unsigned_char_type())); } else { // use as is dest.write().insert(tmp.read().begin(), tmp.read().end()); } } } else insert(dest, exprt(ID_unknown, original_type)); } else if(expr.id()==ID_plus || expr.id()==ID_minus) { if(expr.operands().size()<2) throw expr.id_string()+" expected to have at least two operands"; object_mapt pointer_expr_set; mp_integer i; bool i_is_set=false; // special case for pointer+integer if(expr.operands().size()==2 && expr_type.id()==ID_pointer) { exprt ptr_operand; if(expr.op0().type().id()!=ID_pointer && expr.op0().is_constant()) { i_is_set=!to_integer(expr.op0(), i); ptr_operand=expr.op1(); } else { i_is_set=!to_integer(expr.op1(), i); ptr_operand=expr.op0(); } if(i_is_set) { typet pointer_sub_type=ptr_operand.type().subtype(); if(pointer_sub_type.id()==ID_empty) pointer_sub_type=char_type(); mp_integer size=pointer_offset_size(pointer_sub_type, ns); if(size<=0) { i_is_set=false; } else { i*=size; if(expr.id()==ID_minus) i.negate(); } } get_value_set_rec( ptr_operand, pointer_expr_set, "", ptr_operand.type(), ns); } else { // we get the points-to for all operands, even integers forall_operands(it, expr) { get_value_set_rec( *it, pointer_expr_set, "", it->type(), ns); } } for(object_map_dt::const_iterator it=pointer_expr_set.read().begin(); it!=pointer_expr_set.read().end(); it++) { objectt object=it->second; // adjust by offset if(object.offset_is_zero() && i_is_set) object.offset=i; else object.offset_is_set=false; insert(dest, it->first, object); } }
exprt address_canonizer( const exprt &address, const namespacet &ns) { assert(ns.follow(address.type()).id()==ID_pointer); if(address.id()==ID_address_of) { const address_of_exprt &address_of_expr= to_address_of_expr(address); const exprt &object=address_of_expr.object(); if(object.id()==ID_dereference) { // &*x ---> x return to_dereference_expr(object).pointer(); } else if(object.id()==ID_member) { // get offset exprt offset=member_offset_expr(to_member_expr(object), ns); // &x.m ---> (&x)+offset address_of_exprt address_of_expr(to_member_expr(object).struct_op()); exprt rec_result=address_canonizer(address_of_expr, ns); // rec. call pointer_typet byte_pointer(unsigned_char_type()); typecast_exprt typecast_expr(rec_result, byte_pointer); plus_exprt sum(typecast_expr, offset); if(sum.type()!=address.type()) sum.make_typecast(address.type()); return sum; } else if(object.id()==ID_index) { // &(x[i]) ---> (&x)+i address_of_exprt address_of_expr(to_index_expr(object).array()); exprt rec_result=address_canonizer(address_of_expr, ns); // rec. call pointer_typet pointer_type; pointer_type.subtype()=object.type(); typecast_exprt typecast_expr(rec_result, pointer_type); plus_exprt sum(typecast_expr, to_index_expr(object).index()); if(sum.type()!=address.type()) sum.make_typecast(address.type()); return sum; } else if(object.id()==ID_symbol && is_iterator(object)) { // address of iterator is dereferenced to a corresponding symbol - // will be bound to real address during analysis symbol_exprt iterator_addr( id2string(to_symbol_expr(object).get_identifier())+"'addr", address.type()); return iterator_addr; } else return address; } else if(address.id()==ID_plus || address.id()==ID_minus) { // one of the operands needs to be a pointer assert(address.operands().size()==2); exprt tmp=address; if(ns.follow(tmp.op0().type()).id()==ID_pointer) { tmp.op0()=address_canonizer(tmp.op0(), ns); return tmp; } else if(ns.follow(tmp.op1().type()).id()==ID_pointer) { tmp.op1()=address_canonizer(tmp.op1(), ns); return tmp; } else return tmp; } else if(address.id()==ID_if) { if_exprt tmp=to_if_expr(address); tmp.true_case()=address_canonizer(tmp.true_case(), ns); tmp.false_case()=address_canonizer(tmp.false_case(), ns); return tmp; } else if(address.id()==ID_typecast) { typecast_exprt tmp=to_typecast_expr(address); // cast from another pointer? if(tmp.op().type().id()==ID_pointer) { tmp.op()=address_canonizer(tmp.op(), ns); return tmp; } return address; } else return address; }
void boolbvt::convert_case(const exprt &expr, bvt &bv) { const std::vector<exprt> &operands=expr.operands(); unsigned width=boolbv_width(expr.type()); if(width==0) return conversion_failed(expr, bv); bv.resize(width); // make it free variables Forall_literals(it, bv) *it=prop.new_variable(); if(operands.size()<3) throw "case takes at least three operands"; if((operands.size()%2)!=1) throw "number of case operands must be odd"; enum { FIRST, COMPARE, VALUE } what=FIRST; bvt compare_bv; literalt previous_compare=const_literal(false); literalt compare_literal=const_literal(false); forall_operands(it, expr) { bvt op=convert_bv(*it); switch(what) { case FIRST: compare_bv.swap(op); what=COMPARE; break; case COMPARE: if(compare_bv.size()!=op.size()) { std::cerr << "compare operand: " << compare_bv.size() << std::endl << "operand: " << op.size() << std::endl << it->pretty() << std::endl; throw "size of compare operand does not match"; } compare_literal=bv_utils.equal(compare_bv, op); compare_literal=prop.land(prop.lnot(previous_compare), compare_literal); previous_compare=prop.lor(previous_compare, compare_literal); what=VALUE; break; case VALUE: if(bv.size()!=op.size()) { std::cerr << "result size: " << bv.size() << std::endl << "operand: " << op.size() << std::endl << it->pretty() << std::endl; throw "size of value operand does not match"; } { literalt value_literal=bv_utils.equal(bv, op); prop.l_set_to_true( prop.limplies(compare_literal, value_literal)); } what=COMPARE; break; default: assert(false); } }
void ieee_floatt::from_expr(const exprt &expr) { assert(expr.is_constant()); spec=to_floatbv_type(expr.type()); unpack(binary2integer(expr.get_string(ID_value), false)); }
exprt dereferencet::read_object( const exprt &object, const exprt &offset, const typet &type) { const typet &object_type=ns.follow(object.type()); const typet &dest_type=ns.follow(type); // is the object an array with matching subtype? exprt simplified_offset=simplify_expr(offset, ns); // check if offset is zero if(simplified_offset.is_zero()) { // check type if(base_type_eq(object_type, dest_type, ns)) { return object; // trivial case } else if(type_compatible(object_type, dest_type)) { // the type differs, but we can do this with a typecast return typecast_exprt(object, dest_type); } } if(object.id()==ID_index) { const index_exprt &index_expr=to_index_expr(object); exprt index=index_expr.index(); // multiply index by object size exprt size=size_of_expr(object_type, ns); if(size.is_nil()) throw "dereference failed to get object size for index"; index.make_typecast(simplified_offset.type()); size.make_typecast(index.type()); exprt new_offset=plus_exprt(simplified_offset, mult_exprt(index, size)); return read_object(index_expr.array(), new_offset, type); } else if(object.id()==ID_member) { const member_exprt &member_expr=to_member_expr(object); const typet &compound_type= ns.follow(member_expr.struct_op().type()); if(compound_type.id()==ID_struct) { const struct_typet &struct_type= to_struct_type(compound_type); exprt member_offset=member_offset_expr( struct_type, member_expr.get_component_name(), ns); if(member_offset.is_nil()) throw "dereference failed to get member offset"; member_offset.make_typecast(simplified_offset.type()); exprt new_offset=plus_exprt(simplified_offset, member_offset); return read_object(member_expr.struct_op(), new_offset, type); } else if(compound_type.id()==ID_union) { // Unions are easy: the offset is always zero, // so simply pass down. return read_object(member_expr.struct_op(), offset, type); } } // check if we have an array with the right subtype if(object_type.id()==ID_array && base_type_eq(object_type.subtype(), dest_type, ns)) { // check proper alignment exprt size=size_of_expr(dest_type, ns); if(size.is_not_nil()) { mp_integer size_constant, offset_constant; if(!to_integer(simplify_expr(size, ns), size_constant) && !to_integer(simplified_offset, offset_constant) && (offset_constant%size_constant)==0) { // Yes! Can use index expression! mp_integer index_constant=offset_constant/size_constant; exprt index_expr=from_integer(index_constant, size.type()); return index_exprt(object, index_expr, dest_type); } } } // give up and use byte_extract return binary_exprt(object, byte_extract_id(), simplified_offset, dest_type); }
json_objectt json( const exprt &expr, const namespacet &ns) { json_objectt result; const typet &type=ns.follow(expr.type()); if(expr.id()==ID_constant) { if(type.id()==ID_unsignedbv || type.id()==ID_signedbv || type.id()==ID_c_bit_field) { std::size_t width=to_bitvector_type(type).get_width(); result["name"]=json_stringt("integer"); result["binary"]=json_stringt(expr.get_string(ID_value)); result["width"]=json_numbert(i2string(width)); const typet &underlying_type= type.id()==ID_c_bit_field?type.subtype(): type; bool is_signed=underlying_type.id()==ID_signedbv; std::string sig=is_signed?"":"unsigned "; if(width==config.ansi_c.char_width) result["c_type"]=json_stringt(sig+"char"); else if(width==config.ansi_c.int_width) result["c_type"]=json_stringt(sig+"int"); else if(width==config.ansi_c.short_int_width) result["c_type"]=json_stringt(sig+"short int"); else if(width==config.ansi_c.long_int_width) result["c_type"]=json_stringt(sig+"long int"); else if(width==config.ansi_c.long_long_int_width) result["c_type"]=json_stringt(sig+"long long int"); mp_integer i; if(!to_integer(expr, i)) result["data"]=json_stringt(integer2string(i)); } else if(type.id()==ID_c_enum) { result["name"]=json_stringt("integer"); result["binary"]=json_stringt(expr.get_string(ID_value)); result["width"]=json_numbert(type.subtype().get_string(ID_width)); result["c_type"]=json_stringt("enum"); mp_integer i; if(!to_integer(expr, i)) result["data"]=json_stringt(integer2string(i)); } else if(type.id()==ID_c_enum_tag) { constant_exprt tmp; tmp.type()=ns.follow_tag(to_c_enum_tag_type(type)); tmp.set_value(to_constant_expr(expr).get_value()); return json(tmp, ns); } else if(type.id()==ID_bv) { result["name"]=json_stringt("bitvector"); result["binary"]=json_stringt(expr.get_string(ID_value)); } else if(type.id()==ID_fixedbv) { result["name"]=json_stringt("fixed"); result["width"]=json_numbert(type.get_string(ID_width)); result["binary"]=json_stringt(expr.get_string(ID_value)); result["data"]= json_stringt(fixedbvt(to_constant_expr(expr)).to_ansi_c_string()); } else if(type.id()==ID_floatbv) { result["name"]=json_stringt("float"); result["width"]=json_numbert(type.get_string(ID_width)); result["binary"]=json_stringt(expr.get_string(ID_value)); result["data"]= json_stringt(ieee_floatt(to_constant_expr(expr)).to_ansi_c_string()); } else if(type.id()==ID_pointer) { result["name"]=json_stringt("pointer"); result["binary"]=json_stringt(expr.get_string(ID_value)); if(expr.get(ID_value)==ID_NULL) result["data"]=json_stringt("NULL"); } else if(type.id()==ID_bool) { result["name"]=json_stringt("boolean"); result["binary"]=json_stringt(expr.is_true()?"1":"0"); result["data"]=jsont::json_boolean(expr.is_true()); } else { result["name"]=json_stringt("unknown"); } } else if(expr.id()==ID_array) { result["name"]=json_stringt("array"); json_arrayt &elements=result["elements"].make_array(); unsigned index=0; forall_operands(it, expr) { json_objectt &e=elements.push_back().make_object(); e["index"]=json_numbert(i2string(index)); e["value"]=json(*it, ns); index++; }