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_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(ieee_not_equal(f0, f1)); else if(expr.id()==ID_ieee_float_equal) expr.make_bool(ieee_equal(f0, 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 jsil_typecheckt::typecheck_expr_proto_field(exprt &expr) { if(expr.operands().size()!=2) { err_location(expr); error() << "operator `" << expr.id() << "' expects two operands" << eom; throw 0; } make_type_compatible(expr.op0(), jsil_object_type(), true); make_type_compatible(expr.op1(), string_typet(), true); expr.type()=jsil_value_or_empty_type(); }
void jsil_typecheckt::typecheck_expr_binary_arith(exprt &expr) { if(expr.operands().size()!=2) { err_location(expr); error() << "operator `" << expr.id() << "' expects two operands" << eom; throw 0; } make_type_compatible(expr.op0(), floatbv_typet(), true); make_type_compatible(expr.op1(), floatbv_typet(), true); expr.type()=floatbv_typet(); }
std::string inv_object_storet::build_string(const exprt &expr) const { // we ignore some casts if(expr.id()==ID_typecast) { assert(expr.operands().size()==1); if(expr.type().id()==ID_signedbv || expr.type().id()==ID_unsignedbv) { if(expr.op0().type().id()==ID_signedbv || expr.op0().type().id()==ID_unsignedbv) { if(to_bitvector_type(expr.type()).get_width()>= to_bitvector_type(expr.op0().type()).get_width()) return build_string(expr.op0()); } else if(expr.op0().type().id()==ID_bool) { return build_string(expr.op0()); } } } // we always track constants, but make sure they are uniquely // represented if(expr.is_constant()) { // NULL? if(expr.type().id()==ID_pointer) if(expr.get(ID_value)==ID_NULL) return "0"; mp_integer i; if(!to_integer(expr, i)) return integer2string(i); } // we also like "address_of" and "reference_to" // if the object is constant if(is_constant_address(expr)) return from_expr(ns, "", expr); if(expr.id()==ID_member) { assert(expr.operands().size()==1); return build_string(expr.op0())+"."+expr.get_string(ID_component_name); } if(expr.id()==ID_symbol) return expr.get_string(ID_identifier); return ""; }
void bv_cbmct::convert_waitfor_symbol(const exprt &expr, bvt &bv) { if(expr.operands().size()!=1) throw "waitfor_symbol expected to have one operand"; exprt result; const exprt &bound=expr.op0(); make_free_bv_expr(expr.type(), result); // constraint: result<=bound exprt rel_expr(ID_le, bool_typet()); rel_expr.copy_to_operands(result, bound); set_to_true(rel_expr); return convert_bitvector(result, bv); }
std::string expr2javat::convert_code_java_delete( const exprt &src, unsigned indent) { std::string dest=indent_str(indent)+"delete "; if(src.operands().size()!=1) { unsigned precedence; return convert_norep(src, precedence); } std::string tmp=convert(src.op0()); dest+=tmp+";\n"; return dest; }
exprt concatenate_array_id( const exprt &array, const exprt &index, const typet &type) { std::string a, idx, identifier; a = array.get_string(ID_identifier); if (index.id()==ID_typecast) idx = index.op0().get_string(ID_value); else idx = index.get_string(ID_value); mp_integer i=string2integer(idx); identifier=a+"["+integer2string(i)+"]"; symbol_exprt new_expr(identifier, type); return new_expr; }
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 jsil_typecheckt::typecheck_expr_index(exprt &expr) { if(expr.operands().size()!=2) { err_location(expr); error() << "operator `" << expr.id() << "' expects two operands" << eom; throw 0; } make_type_compatible(expr.op0(), jsil_object_type(), true); make_type_compatible(expr.op1(), string_typet(), true); // special case for function identifiers if (expr.op1().id()=="fid" || expr.op1().id()=="constructid") expr.type()=code_typet(); else expr.type()=jsil_value_type(); }
void interval_domaint::assume_rec( const exprt &cond, bool negation) { if(cond.id()==ID_lt || cond.id()==ID_le || cond.id()==ID_gt || cond.id()==ID_ge || cond.id()==ID_equal || cond.id()==ID_notequal) { assert(cond.operands().size()==2); if(negation) // !x<y ---> x>=y { if(cond.id()==ID_lt) assume_rec(cond.op0(), ID_ge, cond.op1()); else if(cond.id()==ID_le) assume_rec(cond.op0(), ID_gt, cond.op1()); else if(cond.id()==ID_gt) assume_rec(cond.op0(), ID_le, cond.op1()); else if(cond.id()==ID_ge) assume_rec(cond.op0(), ID_lt, cond.op1()); else if(cond.id()==ID_equal) assume_rec(cond.op0(), ID_notequal, cond.op1()); else if(cond.id()==ID_notequal) assume_rec(cond.op0(), ID_equal, cond.op1()); } else assume_rec(cond.op0(), cond.id(), cond.op1()); } else if(cond.id()==ID_not) { assume_rec(to_not_expr(cond).op(), !negation); } else if(cond.id()==ID_and) { if(!negation) forall_operands(it, cond) assume_rec(*it, false); } else if(cond.id()==ID_or) { if(negation) forall_operands(it, cond) assume_rec(*it, true); } }
literalt dplib_convt::convert_rest(const exprt &expr) { //dplib_prop.out << "%% E: " << expr << std::endl; literalt l=prop.new_variable(); find_symbols(expr); if(expr.id()==ID_equal || expr.id()==ID_notequal) { assert(expr.operands().size()==2); dplib_prop.out << "ASSERT " << dplib_prop.dplib_literal(l) << " <=> ("; convert_dplib_expr(expr.op0()); dplib_prop.out << ((expr.id()==ID_equal)?"=":"/="); convert_dplib_expr(expr.op1()); dplib_prop.out << ");" << std::endl; } return l; }
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"); } }
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 boolbvt::convert_shift(const exprt &expr, bvt &bv) { if(expr.type().id()!=ID_unsignedbv && expr.type().id()!=ID_signedbv) return conversion_failed(expr, bv); unsigned width=boolbv_width(expr.type()); if(width==0) return conversion_failed(expr, bv); if(width==0) throw "zero length bit vector type: "+expr.type().to_string(); if(expr.operands().size()!=2) throw "shifting takes two operands"; bvt op, dist; convert_bv(expr.op0(), op); convert_bv(expr.op1(), dist); if(op.size()!=width) throw "convert_shift: unexpected operand width"; bv_utilst::shiftt shift; if(expr.id()==ID_shl) shift=bv_utilst::LEFT; else if(expr.id()==ID_ashr) shift=bv_utilst::ARIGHT; else if(expr.id()==ID_lshr) shift=bv_utilst::LRIGHT; else throw "unexpected operand"; bv=bv_utils.shift(op, shift, dist); }
void goto_checkt::overflow_check(const exprt &expr, const guardt &guard) { if (!options.get_bool_option("overflow-check")) return; // first, check type if (expr.type().id() != "signedbv") return; // add overflow subgoal exprt overflow("overflow-" + expr.id_string(), bool_typet()); overflow.operands() = expr.operands(); if (expr.id() == "typecast") { if (expr.operands().size() != 1) throw "typecast takes one operand"; const typet &old_type = expr.op0().type(); unsigned new_width = atoi(expr.type().width().c_str()); unsigned old_width = atoi(old_type.width().c_str()); if (old_type.id() == "unsignedbv") new_width--; if (new_width >= old_width) return; overflow.id(overflow.id_string() + "-" + i2string(new_width)); } overflow.make_not(); add_guarded_claim(overflow, "arithmetic overflow on " + expr.id_string(), "overflow", expr.find_location(), guard); }
void boolbvt::convert_shift(const exprt &expr, bvt &bv) { if(expr.type().id()!=ID_unsignedbv && expr.type().id()!=ID_signedbv && expr.type().id()!=ID_floatbv && expr.type().id()!=ID_pointer && expr.type().id()!=ID_bv) return conversion_failed(expr, bv); unsigned width=boolbv_width(expr.type()); if(width==0) return conversion_failed(expr, bv); if(expr.operands().size()!=2) throw "shifting takes two operands"; const bvt &op=convert_bv(expr.op0()); const bvt &dist=convert_bv(expr.op1()); if(op.size()!=width) throw "convert_shift: unexpected operand width"; bv_utilst::shiftt shift; if(expr.id()==ID_shl) shift=bv_utilst::LEFT; else if(expr.id()==ID_ashr) shift=bv_utilst::ARIGHT; else if(expr.id()==ID_lshr) shift=bv_utilst::LRIGHT; else throw "unexpected operand"; bv=bv_utils.shift(op, shift, dist); }
bvt boolbvt::convert_abs(const exprt &expr) { std::size_t width=boolbv_width(expr.type()); if(width==0) return conversion_failed(expr); const exprt::operandst &operands=expr.operands(); if(operands.size()!=1) throw "abs takes one operand"; const exprt &op0=expr.op0(); const bvt &op_bv=convert_bv(op0); if(op0.type()!=expr.type()) return conversion_failed(expr); bvtypet bvtype=get_bvtype(expr.type()); if(bvtype==IS_FIXED || bvtype==IS_SIGNED || bvtype==IS_UNSIGNED) { return bv_utils.absolute_value(op_bv); } else if(bvtype==IS_FLOAT) { float_utilst float_utils(prop); float_utils.spec=to_floatbv_type(expr.type()); return float_utils.abs(op_bv); } return conversion_failed(expr); }
void boolbvt::convert_union(const exprt &expr, bvt &bv) { unsigned width=boolbv_width(expr.type()); if(width==0) return conversion_failed(expr, bv); if(expr.operands().size()!=1) throw "union expects one argument"; const bvt &op_bv=convert_bv(expr.op0()); if(width<op_bv.size()) throw "union: unexpected operand op width"; bv.resize(width); for(unsigned i=0; i<op_bv.size(); i++) bv[i]=op_bv[i]; // pad with nondets for(unsigned i=op_bv.size(); i<bv.size(); i++) bv[i]=prop.new_variable(); }
exprt flatten_byte_extract( const exprt &src, const namespacet &ns) { assert(src.id()==ID_byte_extract_little_endian || src.id()==ID_byte_extract_big_endian); assert(src.operands().size()==2); bool little_endian; if(src.id()==ID_byte_extract_little_endian) little_endian=true; else if(src.id()==ID_byte_extract_big_endian) little_endian=false; else assert(false); if(src.id()==ID_byte_extract_big_endian) throw "byte_extract flattening of big endian not done yet"; unsigned width= integer2long(pointer_offset_size(ns, src.type())); const typet &t=src.op0().type(); if(t.id()==ID_array) { const array_typet &array_type=to_array_type(t); const typet &subtype=array_type.subtype(); // byte-array? if((subtype.id()==ID_unsignedbv || subtype.id()==ID_signedbv) && subtype.get_int(ID_width)==8) { // get 'width'-many bytes, and concatenate exprt::operandst op; op.resize(width); for(unsigned i=0; i<width; i++) { // the most significant byte comes first in the concatenation! unsigned offset_i= little_endian?(width-i-1):i; plus_exprt offset(from_integer(offset_i, src.op1().type()), src.op1()); index_exprt index_expr(subtype); index_expr.array()=src.op0(); index_expr.index()=offset; op[i]=index_expr; } if(width==1) return op[0]; else // width>=2 { concatenation_exprt concatenation(src.type()); concatenation.operands().swap(op); return concatenation; } } else // non-byte array { const exprt &root=src.op0(); const exprt &offset=src.op1(); const typet &array_type=ns.follow(root.type()); const typet &offset_type=ns.follow(offset.type()); const typet &element_type=ns.follow(array_type.subtype()); mp_integer element_width=pointer_offset_size(ns, element_type); if(element_width==-1) // failed throw "failed to flatten non-byte array with unknown element width"; mp_integer result_width=pointer_offset_size(ns, src.type()); mp_integer num_elements=(element_width+result_width-2)/element_width+1; // compute new root and offset concatenation_exprt concat( unsignedbv_typet(integer2long(element_width*8*num_elements))); exprt first_index= (element_width==1)?offset : div_exprt(offset, from_integer(element_width, offset_type)); // 8*offset/el_w for(mp_integer i=num_elements; i>0; --i) { plus_exprt index(first_index, from_integer(i-1, offset_type)); concat.copy_to_operands(index_exprt(root, index)); } // the new offset is width%offset exprt new_offset= (element_width==1)?from_integer(0, offset_type): mod_exprt(offset, from_integer(element_width, offset_type)); // build new byte-extract expression exprt tmp(src.id(), src.type()); tmp.copy_to_operands(concat, new_offset); return tmp; } } else // non-array { // We turn that into logical right shift and extractbits const exprt &offset=src.op1(); const typet &offset_type=ns.follow(offset.type()); mult_exprt times_eight(offset, from_integer(8, offset_type)); lshr_exprt left_shift(src.op0(), times_eight); extractbits_exprt extractbits; extractbits.src()=left_shift; extractbits.type()=src.type(); extractbits.upper()=from_integer(width*8-1, offset_type); extractbits.lower()=from_integer(0, offset_type); return extractbits; } }
exprt flatten_byte_update( const exprt &src, const namespacet &ns) { assert(src.id()==ID_byte_update_little_endian || src.id()==ID_byte_update_big_endian); assert(src.operands().size()==3); mp_integer element_size= pointer_offset_size(ns, src.op2().type()); const typet &t=ns.follow(src.op0().type()); if(t.id()==ID_array) { const array_typet &array_type=to_array_type(t); const typet &subtype=array_type.subtype(); // array of bitvectors? if(subtype.id()==ID_unsignedbv || subtype.id()==ID_signedbv || subtype.id()==ID_floatbv) { mp_integer sub_size=pointer_offset_size(ns, subtype); if(sub_size==-1) throw "can't flatten byte_update for sub-type without size"; // byte array? if(sub_size==1) { // apply 'array-update-with' element_size times exprt result=src.op0(); for(mp_integer i=0; i<element_size; ++i) { exprt i_expr=from_integer(i, ns.follow(src.op1().type())); exprt new_value; if(i==0 && element_size==1) // bytes? { new_value=src.op2(); if(new_value.type()!=subtype) new_value.make_typecast(subtype); } else { exprt byte_extract_expr( src.id()==ID_byte_update_little_endian?ID_byte_extract_little_endian: src.id()==ID_byte_update_big_endian?ID_byte_extract_big_endian: throw "unexpected src.id()", subtype); byte_extract_expr.copy_to_operands(src.op2(), i_expr); new_value=flatten_byte_extract(byte_extract_expr, ns); } exprt where=plus_exprt(src.op1(), i_expr); with_exprt with_expr; with_expr.type()=src.type(); with_expr.old()=result; with_expr.where()=where; with_expr.new_value()=new_value; result.swap(with_expr); } return result; } else // sub_size!=1 { if(element_size==1) // byte-granularity update { div_exprt div_offset(src.op1(), from_integer(sub_size, src.op1().type())); mod_exprt mod_offset(src.op1(), from_integer(sub_size, src.op1().type())); index_exprt index_expr(src.op0(), div_offset, array_type.subtype()); exprt byte_update_expr(src.id(), array_type.subtype()); byte_update_expr.copy_to_operands(index_expr, mod_offset, src.op2()); // Call recurisvely, the array is gone! exprt flattened_byte_update_expr= flatten_byte_update(byte_update_expr, ns); with_exprt with_expr( src.op0(), div_offset, flattened_byte_update_expr); return with_expr; } else throw "flatten_byte_update can only do byte updates of non-byte arrays right now"; } } else { throw "flatten_byte_update can only do arrays of scalars right now"; } } else if(t.id()==ID_signedbv || t.id()==ID_unsignedbv || t.id()==ID_floatbv) { // do a shift, mask and OR unsigned width=to_bitvector_type(t).get_width(); if(element_size*8>width) throw "flatten_byte_update to update element that is too large"; // build mask exprt mask= bitnot_exprt( from_integer(power(2, element_size*8)-1, unsignedbv_typet(width))); const typet &offset_type=ns.follow(src.op1().type()); mult_exprt offset_times_eight(src.op1(), from_integer(8, offset_type)); // shift the mask shl_exprt shl_expr(mask, offset_times_eight); // do the 'AND' bitand_exprt bitand_expr(src.op0(), mask); // zero-extend the value concatenation_exprt value_extended( from_integer(0, unsignedbv_typet(width-integer2long(element_size)*8)), src.op2(), t); // shift the value shl_exprt value_shifted(value_extended, offset_times_eight); // do the 'OR' bitor_exprt bitor_expr(bitand_expr, value_shifted); return bitor_expr; } else { throw "flatten_byte_update can only do array and scalars right now"; } }
literalt boolbvt::convert_overflow(const exprt &expr) { const exprt::operandst &operands=expr.operands(); if(expr.id()==ID_overflow_plus || expr.id()==ID_overflow_minus) { if(operands.size()!=2) throw "operator "+expr.id_string()+" takes two operands"; const bvt &bv0=convert_bv(operands[0]); const bvt &bv1=convert_bv(operands[1]); if(bv0.size()!=bv1.size()) return SUB::convert_rest(expr); bv_utilst::representationt rep= expr.op0().type().id()==ID_signedbv?bv_utilst::SIGNED: bv_utilst::UNSIGNED; return expr.id()==ID_overflow_minus? bv_utils.overflow_sub(bv0, bv1, rep): bv_utils.overflow_add(bv0, bv1, rep); } else if(expr.id()==ID_overflow_mult) { if(operands.size()!=2) throw "operator "+expr.id_string()+" takes two operands"; if(operands[0].type().id()!=ID_unsignedbv && operands[0].type().id()!=ID_signedbv) return SUB::convert_rest(expr); bvt bv0=convert_bv(operands[0]); bvt bv1=convert_bv(operands[1]); if(bv0.size()!=bv1.size()) throw "operand size mismatch on overflow-*"; bv_utilst::representationt rep= operands[0].type().id()==ID_signedbv?bv_utilst::SIGNED: bv_utilst::UNSIGNED; if(operands[0].type()!=operands[1].type()) throw "operand type mismatch on overflow-*"; assert(bv0.size()==bv1.size()); unsigned old_size=bv0.size(); unsigned new_size=old_size*2; // sign/zero extension bv0=bv_utils.extension(bv0, new_size, rep); bv1=bv_utils.extension(bv1, new_size, rep); bvt result=bv_utils.multiplier(bv0, bv1, rep); if(rep==bv_utilst::UNSIGNED) { bvt bv_overflow; bv_overflow.reserve(old_size); // get top result bits for(unsigned i=old_size; i<result.size(); i++) bv_overflow.push_back(result[i]); return prop.lor(bv_overflow); } else { bvt bv_overflow; bv_overflow.reserve(old_size); // get top result bits, plus one more assert(old_size!=0); for(unsigned i=old_size-1; i<result.size(); i++) bv_overflow.push_back(result[i]); // these need to be either all 1's or all 0's literalt all_one=prop.land(bv_overflow); literalt all_zero=prop.lnot(prop.lor(bv_overflow)); return prop.lnot(prop.lor(all_one, all_zero)); } } else if(expr.id()==ID_overflow_unary_minus) { if(operands.size()!=1) throw "operator "+expr.id_string()+" takes one operand"; const bvt &bv=convert_bv(operands[0]); return bv_utils.overflow_negate(bv); } else if(has_prefix(expr.id_string(), "overflow-typecast-")) { unsigned bits=atoi(expr.id().c_str()+18); const exprt::operandst &operands=expr.operands(); if(operands.size()!=1) throw "operator "+expr.id_string()+" takes one operand"; const exprt &op=operands[0]; const bvt &bv=convert_bv(op); if(bits>=bv.size() || bits==0) throw "overflow-typecast got wrong number of bits"; // signed or unsigned? if(op.type().id()==ID_signedbv) { bvt tmp_bv; for(unsigned i=bits; i<bv.size(); i++) tmp_bv.push_back(prop.lxor(bv[bits-1], bv[i])); return prop.lor(tmp_bv); } else { bvt tmp_bv; for(unsigned i=bits; i<bv.size(); i++) tmp_bv.push_back(bv[i]); return prop.lor(tmp_bv); } } return SUB::convert_rest(expr); }
void cvc_convt::convert_address_of_rec(const exprt &expr) { if(expr.id()==ID_symbol || expr.id()==ID_constant || expr.id()==ID_string_constant) { out << "(# object:=" << pointer_logic.add_object(expr) << ", offset:=" << bin_zero(config.ansi_c.pointer_width) << " #)"; } else if(expr.id()==ID_index) { if(expr.operands().size()!=2) throw "index takes two operands"; const exprt &array=expr.op0(); const exprt &index=expr.op1(); if(index.is_zero()) { if(array.type().id()==ID_pointer) convert_expr(array); else if(array.type().id()==ID_array) convert_address_of_rec(array); else assert(false); } else { out << "(LET P: "; out << cvc_pointer_type(); out << " = "; if(array.type().id()==ID_pointer) convert_expr(array); else if(array.type().id()==ID_array) convert_address_of_rec(array); else assert(false); out << " IN P WITH .offset:=BVPLUS(" << config.ansi_c.pointer_width << ", P.offset, "; convert_expr(index); out << "))"; } } else if(expr.id()==ID_member) { if(expr.operands().size()!=1) throw "member takes one operand"; const exprt &struct_op=expr.op0(); out << "(LET P: "; out << cvc_pointer_type(); out << " = "; convert_address_of_rec(struct_op); const irep_idt &component_name= to_member_expr(expr).get_component_name(); mp_integer offset=member_offset( to_struct_type(struct_op.type()), component_name, ns); typet index_type(ID_unsignedbv); index_type.set(ID_width, config.ansi_c.pointer_width); exprt index=from_integer(offset, index_type); out << " IN P WITH .offset:=BVPLUS(" << config.ansi_c.pointer_width << ", P.offset, "; convert_expr(index); out << "))"; } else throw "don't know how to take address of: "+expr.id_string(); }
void boolbvt::convert_mult(const exprt &expr, bvt &bv) { unsigned width=boolbv_width(expr.type()); if(width==0) return conversion_failed(expr, bv); bv.resize(width); const exprt::operandst &operands=expr.operands(); if(operands.size()==0) throw "mult without operands"; const exprt &op0=expr.op0(); bool no_overflow=expr.id()=="no-overflow-mult"; if(expr.type().id()==ID_fixedbv) { if(op0.type()!=expr.type()) throw "multiplication with mixed types"; bv=convert_bv(op0); if(bv.size()!=width) throw "convert_mult: unexpected operand width"; unsigned fraction_bits= to_fixedbv_type(expr.type()).get_fraction_bits(); // do a sign extension by fraction_bits bits bv=bv_utils.sign_extension(bv, bv.size()+fraction_bits); for(exprt::operandst::const_iterator it=operands.begin()+1; it!=operands.end(); it++) { if(it->type()!=expr.type()) throw "multiplication with mixed types"; bvt op=convert_bv(*it); if(op.size()!=width) throw "convert_mult: unexpected operand width"; op=bv_utils.sign_extension(op, bv.size()); bv=bv_utils.signed_multiplier(bv, op); } // cut it down again bv.erase(bv.begin(), bv.begin()+fraction_bits); return; } else if(expr.type().id()==ID_floatbv) { if(op0.type()!=expr.type()) throw "multiplication with mixed types"; bv=convert_bv(op0); if(bv.size()!=width) throw "convert_mult: unexpected operand width"; float_utilst float_utils(prop); float_utils.spec=to_floatbv_type(expr.type()); for(exprt::operandst::const_iterator it=operands.begin()+1; it!=operands.end(); it++) { if(it->type()!=expr.type()) throw "multiplication with mixed types"; const bvt &op=convert_bv(*it); if(op.size()!=width) throw "convert_mult: unexpected operand width"; bv=float_utils.mul(bv, op); } return; } else if(expr.type().id()==ID_unsignedbv || expr.type().id()==ID_signedbv) { if(op0.type()!=expr.type()) throw "multiplication with mixed types"; bv_utilst::representationt rep= expr.type().id()==ID_signedbv?bv_utilst::SIGNED: bv_utilst::UNSIGNED; bv=convert_bv(op0); if(bv.size()!=width) throw "convert_mult: unexpected operand width"; for(exprt::operandst::const_iterator it=operands.begin()+1; it!=operands.end(); it++) { if(it->type()!=expr.type()) throw "multiplication with mixed types"; const bvt &op=convert_bv(*it); if(op.size()!=width) throw "convert_mult: unexpected operand width"; if(no_overflow) bv=bv_utils.multiplier_no_overflow(bv, op, rep); else bv=bv_utils.multiplier(bv, op, rep); } return; } conversion_failed(expr, bv); }
std::string as_vcd_binary( const exprt &expr, const namespacet &ns) { const typet &type=ns.follow(expr.type()); if(expr.id()==ID_constant) { if(type.id()==ID_unsignedbv || type.id()==ID_signedbv || type.id()==ID_bv || type.id()==ID_fixedbv || type.id()==ID_floatbv || type.id()==ID_pointer) return expr.get_string(ID_value); } else if(expr.id()==ID_array) { std::string result; forall_operands(it, expr) result+=as_vcd_binary(*it, ns); return result; } else if(expr.id()==ID_struct) { std::string result; forall_operands(it, expr) result+=as_vcd_binary(*it, ns); return result; } else if(expr.id()==ID_union) { assert(expr.operands().size()==1); return as_vcd_binary(expr.op0(), ns); } // build "xxx" mp_integer width; if(type.id()==ID_unsignedbv || type.id()==ID_signedbv || type.id()==ID_floatbv || type.id()==ID_fixedbv || type.id()==ID_pointer || type.id()==ID_bv) width=string2integer(type.get_string(ID_width)); else width=pointer_offset_size(type, ns)*8; if(width>=0) { std::string result; for(; width!=0; --width) result+='x'; return result; } return ""; }
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; }
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; }
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 } }
exprt build_full_lhs_rec( const prop_convt &prop_conv, const namespacet &ns, const exprt &src_original, // original identifiers const exprt &src_ssa) // renamed identifiers { if(src_ssa.id()!=src_original.id()) return src_original; const irep_idt id=src_original.id(); if(id==ID_index) { // get index value from src_ssa exprt index_value=prop_conv.get(to_index_expr(src_ssa).index()); if(index_value.is_not_nil()) { simplify(index_value, ns); index_exprt tmp=to_index_expr(src_original); tmp.index()=index_value; tmp.array()= build_full_lhs_rec(prop_conv, ns, to_index_expr(src_original).array(), to_index_expr(src_ssa).array()); return tmp; } return src_original; } else if(id==ID_member) { member_exprt tmp=to_member_expr(src_original); tmp.struct_op()=build_full_lhs_rec( prop_conv, ns, to_member_expr(src_original).struct_op(), to_member_expr(src_ssa).struct_op()); } else if(id==ID_if) { if_exprt tmp2=to_if_expr(src_original); tmp2.false_case()=build_full_lhs_rec(prop_conv, ns, tmp2.false_case(), to_if_expr(src_ssa).false_case()); tmp2.true_case()=build_full_lhs_rec(prop_conv, ns, tmp2.true_case(), to_if_expr(src_ssa).true_case()); exprt tmp=prop_conv.get(to_if_expr(src_ssa).cond()); if(tmp.is_true()) return tmp2.true_case(); else if(tmp.is_false()) return tmp2.false_case(); else return tmp2; } else if(id==ID_typecast) { typecast_exprt tmp=to_typecast_expr(src_original); tmp.op()=build_full_lhs_rec(prop_conv, ns, to_typecast_expr(src_original).op(), to_typecast_expr(src_ssa).op()); return tmp; } else if(id==ID_byte_extract_little_endian || id==ID_byte_extract_big_endian) { exprt tmp=src_original; assert(tmp.operands().size()==2); tmp.op0()=build_full_lhs_rec(prop_conv, ns, tmp.op0(), src_ssa.op0()); // re-write into big case-split } return src_original; }
exprt c_typecheck_baset::do_initializer_list( const exprt &value, const typet &type, bool force_constant) { assert(value.id()==ID_initializer_list); const typet &full_type=follow(type); exprt result; if(full_type.id()==ID_struct || full_type.id()==ID_union || full_type.id()==ID_vector) { // start with zero everywhere result= zero_initializer( type, value.source_location(), *this, get_message_handler()); } else if(full_type.id()==ID_array) { if(to_array_type(full_type).size().is_nil()) { // start with empty array result=exprt(ID_array, full_type); result.add_source_location()=value.source_location(); } else { // start with zero everywhere result= zero_initializer( type, value.source_location(), *this, get_message_handler()); } // 6.7.9, 14: An array of character type may be initialized by a character // string literal or UTF-8 string literal, optionally enclosed in braces. if(value.operands().size()>=1 && value.op0().id()==ID_string_constant && (full_type.subtype().id()==ID_signedbv || full_type.subtype().id()==ID_unsignedbv) && full_type.subtype().get(ID_width)==char_type().get(ID_width)) { if(value.operands().size()>1) { warning().source_location=value.find_source_location(); warning() << "ignoring excess initializers" << eom; } return do_initializer_rec(value.op0(), type, force_constant); } } else { // The initializer for a scalar shall be a single expression, // * optionally enclosed in braces. * if(value.operands().size()==1) return do_initializer_rec(value.op0(), type, force_constant); err_location(value); error() << "cannot initialize `" << to_string(full_type) << "' with an initializer list" << eom; throw 0; } designatort current_designator; designator_enter(type, current_designator); forall_operands(it, value) { do_designated_initializer( result, current_designator, *it, force_constant); // increase designator -- might go up increment_designator(current_designator); }