bvt boolbvt::convert_struct(const struct_exprt &expr) { const struct_typet &struct_type=to_struct_type(ns.follow(expr.type())); std::size_t width=boolbv_width(struct_type); const struct_typet::componentst &components=struct_type.components(); if(expr.operands().size()!=components.size()) { error().source_location=expr.find_source_location(); error() << "struct: wrong number of arguments" << eom; throw 0; } bvt bv; bv.resize(width); std::size_t offset=0, i=0; for(struct_typet::componentst::const_iterator it=components.begin(); it!=components.end(); it++) { const typet &subtype=it->type(); const exprt &op=expr.operands()[i]; if(!base_type_eq(subtype, op.type(), ns)) { error().source_location=expr.find_source_location(); error() << "struct: component type does not match: " << subtype.pretty() << " vs. " << op.type().pretty() << eom; throw 0; } std::size_t subtype_width=boolbv_width(subtype); if(subtype_width!=0) { const bvt &op_bv=convert_bv(op); assert(offset<width); assert(op_bv.size()==subtype_width); assert(offset+op_bv.size()<=width); for(std::size_t j=0; j<op_bv.size(); j++) bv[offset+j]=op_bv[j]; offset+=op_bv.size(); } i++; } assert(offset==width); return bv; }
bvt boolbvt::convert_array_of(const array_of_exprt &expr) { if(expr.type().id()!=ID_array) throw "array_of must be array-typed"; const array_typet &array_type=to_array_type(expr.type()); if(is_unbounded_array(array_type)) return conversion_failed(expr); std::size_t width=boolbv_width(array_type); if(width==0) { // A zero-length array is acceptable; // an element with unknown size is not. if(boolbv_width(array_type.subtype())==0) return conversion_failed(expr); else return bvt(); } const exprt &array_size=array_type.size(); mp_integer size; if(to_integer(array_size, size)) return conversion_failed(expr); const bvt &tmp=convert_bv(expr.op0()); bvt bv; bv.resize(width); if(size*tmp.size()!=width) throw "convert_array_of: unexpected operand width"; std::size_t offset=0; for(mp_integer i=0; i<size; i=i+1) { for(std::size_t j=0; j<tmp.size(); j++, offset++) bv[offset]=tmp[j]; } assert(offset==bv.size()); return bv; }
void boolbvt::convert_index( const exprt &array, const mp_integer &index, bvt &bv) { const array_typet &array_type= to_array_type(ns.follow(array.type())); unsigned width=boolbv_width(array_type.subtype()); if(width==0) return conversion_failed(array, bv); bv.resize(width); const bvt &tmp=convert_bv(array); // recursive call mp_integer offset=index*width; if(offset>=0 && offset+width<=mp_integer(tmp.size())) { // in bounds for(unsigned i=0; i<width; i++) bv[i]=tmp[integer2long(offset+i)]; } else { // out of bounds for(unsigned i=0; i<width; i++) bv[i]=prop.new_variable(); } }
void boolbvt::convert_concatenation(const exprt &expr, bvt &bv) { unsigned width=boolbv_width(expr.type()); if(width==0) return conversion_failed(expr, bv); const exprt::operandst &operands=expr.operands(); if(operands.size()==0) throw "concatenation takes at least one operand"; unsigned offset=width; bv.resize(width); forall_expr(it, operands) { const bvt &op=convert_bv(*it); if(op.size()>offset) throw "concatenation operand width too big"; offset-=op.size(); for(unsigned i=0; i<op.size(); i++) bv[offset+i]=op[i]; } if(offset!=0) throw "concatenation operand width too small"; }
bvt boolbvt::convert_array(const exprt &expr) { std::size_t width=boolbv_width(expr.type()); if(width==0) return conversion_failed(expr); if(expr.type().id()==ID_array) { assert(expr.has_operands()); const exprt::operandst &operands=expr.operands(); assert(!operands.empty()); std::size_t op_width=width/operands.size(); bvt bv; bv.reserve(width); forall_expr(it, operands) { const bvt &tmp=convert_bv(*it); if(tmp.size()!=op_width) throw "convert_array: unexpected operand width"; forall_literals(it2, tmp) bv.push_back(*it2); } return bv; }
bvt boolbvt::convert_power(const binary_exprt &expr) { const typet &type=ns.follow(expr.type()); std::size_t width=boolbv_width(type); if(width==0) return conversion_failed(expr); if(type.id()==ID_unsignedbv || type.id()==ID_signedbv) { // Let's do the special case 2**x bvt op0=convert_bv(expr.op0()); bvt op1=convert_bv(expr.op1()); literalt eq_2= bv_utils.equal(op0, bv_utils.build_constant(2, op0.size())); bvt one=bv_utils.build_constant(1, width); bvt shift=bv_utils.shift(one, bv_utilst::LEFT, op1); bvt nondet=prop.new_variables(width); return bv_utils.select(eq_2, shift, nondet); } return conversion_failed(expr); }
void boolbvt::convert_replication(const exprt &expr, bvt &bv) { unsigned width=boolbv_width(expr.type()); if(width==0) return conversion_failed(expr, bv); if(expr.operands().size()!=2) throw "replication takes two operands"; mp_integer times; if(to_integer(expr.op0(), times)) throw "replication takes constant as first parameter"; const unsigned u_times=integer2unsigned(times); const bvt &op=convert_bv(expr.op1()); unsigned offset=0; bv.resize(width); for(unsigned i=0; i<u_times; i++) { if(op.size()+offset>width) throw "replication operand width too big"; for(unsigned i=0; i<op.size(); i++) bv[i+offset]=op[i]; offset+=op.size(); } if(offset!=bv.size()) throw "replication operand width too small"; }
boolbv_mapt::map_entryt &boolbv_mapt::get_map_entry( const irep_idt &identifier, const typet &type) { if(type.id()==ID_symbol) return get_map_entry(identifier, ns.follow(type)); std::pair<mappingt::iterator, bool> result= mapping.insert(std::pair<irep_idt, map_entryt>( identifier, map_entryt())); map_entryt &map_entry=result.first->second; if(result.second) { // actually inserted map_entry.type=type; map_entry.width=boolbv_width(type); map_entry.bvtype=get_bvtype(type); map_entry.literal_map.resize(map_entry.width); } assert(map_entry.literal_map.size()==map_entry.width); return map_entry; }
void boolbvt::convert_constant(const constant_exprt &expr, bvt &bv) { unsigned width=boolbv_width(expr.type()); if(width==0) return conversion_failed(expr, bv); bv.resize(width); const typet &expr_type=expr.type(); if(expr_type.id()==ID_array) { unsigned op_width=width/expr.operands().size(); unsigned offset=0; forall_operands(it, expr) { const bvt &tmp=convert_bv(*it); if(tmp.size()!=op_width) throw "convert_constant: unexpected operand width"; for(unsigned j=0; j<op_width; j++) bv[offset+j]=tmp[j]; offset+=op_width; } return; }
void boolbvt::convert_cond(const exprt &expr, bvt &bv) { const exprt::operandst &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()<2) throw "cond takes at least two operands"; if((operands.size()%2)!=0) throw "number of cond operands must be even"; if(prop.has_set_to()) { bool condition=true; literalt previous_cond=const_literal(false); literalt cond_literal=const_literal(false); forall_operands(it, expr) { if(condition) { cond_literal=convert(*it); cond_literal=prop.land(prop.lnot(previous_cond), cond_literal); previous_cond=prop.lor(previous_cond, cond_literal); } else { const bvt &op=convert_bv(*it); 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(cond_literal, value_literal)); } condition=!condition; } }
void boolbvt::convert_with_struct( const struct_typet &type, const exprt &op1, const exprt &op2, const bvt &prev_bv, bvt &next_bv) { next_bv=prev_bv; const bvt &op2_bv=convert_bv(op2); const irep_idt &component_name=op1.get(ID_component_name); const struct_typet::componentst &components= type.components(); std::size_t offset=0; for(struct_typet::componentst::const_iterator it=components.begin(); it!=components.end(); it++) { const typet &subtype=it->type(); std::size_t sub_width=boolbv_width(subtype); if(it->get_name()==component_name) { if(!base_type_eq(subtype, op2.type(), ns)) { error().source_location=type.source_location(); error() << "with/struct: component `" << component_name << "' type does not match: " << subtype.pretty() << " vs. " << op2.type().pretty() << eom; throw 0; } if(sub_width!=op2_bv.size()) { error().source_location=type.source_location(); error() << "convert_with_struct: unexpected operand op2 width" << eom; throw 0; } for(std::size_t i=0; i<sub_width; i++) next_bv[offset+i]=op2_bv[i]; break; // done } offset+=sub_width; } }
void boolbvt::convert_div(const exprt &expr, bvt &bv) { if(expr.type().id()!=ID_unsignedbv && expr.type().id()!=ID_signedbv && expr.type().id()!=ID_fixedbv) 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 "division takes two operands"; if(expr.op0().type().id()!=expr.type().id() || expr.op1().type().id()!=expr.type().id()) return conversion_failed(expr, bv); bvt op0=convert_bv(expr.op0()); bvt op1=convert_bv(expr.op1()); if(op0.size()!=width || op1.size()!=width) throw "convert_div: unexpected operand width"; bvt res, rem; if(expr.type().id()==ID_fixedbv) { unsigned fraction_bits= to_fixedbv_type(expr.type()).get_fraction_bits(); bvt zeros; zeros.resize(fraction_bits, const_literal(false)); // add fraction_bits least-significant bits op0.insert(op0.begin(), zeros.begin(), zeros.end()); op1=bv_utils.sign_extension(op1, op1.size()+fraction_bits); bv_utils.divider(op0, op1, res, rem, bv_utilst::SIGNED); // cut it down again res.resize(width); } else { bv_utilst::representationt rep= expr.type().id()==ID_signedbv?bv_utilst::SIGNED: bv_utilst::UNSIGNED; bv_utils.divider(op0, op1, res, rem, rep); } bv=res; }
bvt boolbvt::convert_with(const exprt &expr) { if(expr.operands().size()<3) { error().source_location=expr.find_source_location(); error() << "with takes at least three operands" << eom; throw 0; } if((expr.operands().size()%2)!=1) { error().source_location=expr.find_source_location(); error() << "with takes an odd number of operands" << eom; throw 0; } bvt bv=convert_bv(expr.op0()); std::size_t width=boolbv_width(expr.type()); if(width==0) return conversion_failed(expr); if(bv.size()!=width) { error().source_location=expr.find_source_location(); error() << "unexpected operand 0 width" << eom; throw 0; } bvt prev_bv; prev_bv.resize(width); const exprt::operandst &ops=expr.operands(); for(std::size_t op_no=1; op_no<ops.size(); op_no+=2) { bv.swap(prev_bv); convert_with(expr.op0().type(), ops[op_no], ops[op_no+1], prev_bv, bv); } return bv; }
bvt boolbvt::convert_if(const if_exprt &expr) { std::size_t width=boolbv_width(expr.type()); if(width==0) return bvt(); // An empty bit-vector if. literalt cond=convert(expr.cond()); const bvt &op1_bv=convert_bv(expr.true_case()); const bvt &op2_bv=convert_bv(expr.false_case()); if(op1_bv.size()!=width || op2_bv.size()!=width) throw "operand size mismatch for if "+expr.pretty(); return bv_utils.select(cond, op1_bv, op2_bv); }
bv_refinementt::approximationt & bv_refinementt::add_approximation( const exprt &expr, bvt &bv) { approximations.push_back(approximationt(approximations.size())); approximationt &a=approximations.back(); // stable! unsigned width=boolbv_width(expr.type()); assert(width!=0); a.expr=expr; a.result_bv=prop.new_variables(width); a.no_operands=expr.operands().size(); set_frozen(a.result_bv); if(a.no_operands==1) { a.op0_bv=convert_bv(expr.op0()); set_frozen(a.op0_bv); } else if(a.no_operands==2) { a.op0_bv=convert_bv(expr.op0()); a.op1_bv=convert_bv(expr.op1()); set_frozen(a.op0_bv); set_frozen(a.op1_bv); } else if(a.no_operands==3) { a.op0_bv=convert_bv(expr.op0()); a.op1_bv=convert_bv(expr.op1()); a.op2_bv=convert_bv(expr.op2()); set_frozen(a.op0_bv); set_frozen(a.op1_bv); set_frozen(a.op2_bv); } else assert(false); bv=a.result_bv; initialize(a); return a; }
bvt boolbvt::convert_union(const union_exprt &expr) { std::size_t width=boolbv_width(expr.type()); if(width==0) return conversion_failed(expr); const bvt &op_bv=convert_bv(expr.op()); if(width<op_bv.size()) throw "union: unexpected operand op width"; bvt bv; bv.resize(width); if(config.ansi_c.endianness==configt::ansi_ct::endiannesst::IS_LITTLE_ENDIAN) { for(std::size_t i=0; i<op_bv.size(); i++) bv[i]=op_bv[i]; // pad with nondets for(std::size_t i=op_bv.size(); i<bv.size(); i++) bv[i]=prop.new_variable(); } else { assert( config.ansi_c.endianness==configt::ansi_ct::endiannesst::IS_BIG_ENDIAN); endianness_mapt map_u(expr.type(), false, ns); endianness_mapt map_op(expr.op0().type(), false, ns); for(std::size_t i=0; i<op_bv.size(); i++) bv[map_u.map_bit(i)]=op_bv[map_op.map_bit(i)]; // pad with nondets for(std::size_t i=op_bv.size(); i<bv.size(); i++) bv[map_u.map_bit(i)]=prop.new_variable(); } return bv; }
void boolbvt::convert_update(const exprt &expr, bvt &bv) { const exprt::operandst &ops=expr.operands(); if(ops.size()!=3) throw "update takes at three operands"; std::size_t width=boolbv_width(expr.type()); if(width==0) return conversion_failed(expr, bv); bv=convert_bv(ops[0]); if(bv.size()!=width) throw "update: unexpected operand 0 width"; // start the recursion convert_update_rec( expr.op1().operands(), 0, expr.type(), 0, expr.op2(), bv); }
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); }
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_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); }
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(); }
void boolbvt::convert_floatbv_op(const exprt &expr, bvt &bv) { 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) bv=float_utils.add_sub(bv0, bv1, false); else if(expr.id()==ID_floatbv_minus) bv=float_utils.add_sub(bv0, bv1, true); else if(expr.id()==ID_floatbv_mult) bv=float_utils.mul(bv0, bv1); else if(expr.id()==ID_floatbv_div) bv=float_utils.div(bv0, bv1); else if(expr.id()==ID_floatbv_rem) bv=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; 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); } } else return conversion_failed(expr, bv); } else return conversion_failed(expr, bv); }
bool bv_minimizing_dect::minimize(const minimization_listt &symbols) { // unfortunately, only MiniSat supports this #if defined(SATCHECK_MINISAT) || defined(SATCHECK_MINISAT2) bvt constraints; for(minimization_listt::const_iterator l_it=symbols.begin(); l_it!=symbols.end(); l_it++) { unsigned result=0; const exprt &symbol = *l_it; status("Minimizing... "); // FIXME: be more gener[ous|al] here! assert(symbol.type().id()==ID_unsignedbv); unsigned width=boolbv_width(symbol.type()); for(unsigned i = width; i > 0; i--) { literalt lit; #if 0 std::cout << "SYMBOL: " << symbol << std::endl; #endif if(literal(symbol, i-1, lit)) continue; // there's no corresponding literal if(lit.is_constant()) continue; literalt nlit=satcheck.lnot(lit); constraints.push_back(nlit); if(satcheck.l_get(lit)==tvt(false)) continue; // call Minisat with constraints satcheck.set_assumptions(constraints); if(satcheck.prop_solve() == propt::P_UNSATISFIABLE) { // change constraint to 1 constraints.back().swap(lit); result |= 1 << (i-1); // make sure the model is reconstructed satcheck.set_assumptions(constraints); if(satcheck.prop_solve()==propt::P_UNSATISFIABLE) assert (false); // do not remove call to prop_solve!! } } status(symbol.get_string(ID_identifier)+" = "+i2string(result)); } return true; #else // we don't have it... return false; #endif }
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); }
bvt boolbvt::convert_extractbits(const extractbits_exprt &expr) { std::size_t width=boolbv_width(expr.type()); if(width==0) return conversion_failed(expr); const irep_idt &type_id=expr.type().id(); if(type_id!=ID_signedbv && type_id!=ID_unsignedbv && type_id!=ID_c_enum && type_id!=ID_c_enum_tag && type_id!=ID_bv) return conversion_failed(expr); if(expr.operands().size()!=3) { error().source_location=expr.find_source_location(); error() << "extractbits takes three operands" << eom; throw 0; } mp_integer o1, o2; const bvt &bv0=convert_bv(expr.op0()); // We only do constants for now. // Should implement a shift here. if(to_integer(expr.op1(), o1) || to_integer(expr.op2(), o2)) return conversion_failed(expr); if(o1<0 || o1>=bv0.size()) { error().source_location=expr.find_source_location(); error() << "extractbits: second operand out of range: " << expr.pretty() << eom; } if(o2<0 || o2>=bv0.size()) { error().source_location=expr.find_source_location(); error() << "extractbits: third operand out of range: " << expr.pretty() << eom; throw 0; } if(o2>o1) std::swap(o1, o2); // now o2<=o1 if((o1-o2+1)!=width) { error().source_location=expr.find_source_location(); error() << "extractbits: wrong width (expected " << (o1-o2+1) << " but got " << width << "): " << expr.pretty() << eom; throw 0; } std::size_t offset=integer2unsigned(o2); bvt bv; bv.resize(width); for(std::size_t i=0; i<width; i++) bv[i]=bv0[offset+i]; return bv; }
void boolbvt::convert_unary_minus(const exprt &expr, bvt &bv) { const typet &type=ns.follow(expr.type()); unsigned width=boolbv_width(type); if(width==0) return conversion_failed(expr, bv); const exprt::operandst &operands=expr.operands(); if(operands.size()!=1) throw "unary minus takes one operand"; const exprt &op0=expr.op0(); const bvt &op_bv=convert_bv(op0); bvtypet bvtype=get_bvtype(type); bvtypet op_bvtype=get_bvtype(op0.type()); unsigned op_width=op_bv.size(); bool no_overflow=(expr.id()=="no-overflow-unary-minus"); if(op_width==0 || op_width!=width) return conversion_failed(expr, bv); if(bvtype==IS_UNKNOWN && (type.id()==ID_vector || type.id()==ID_complex)) { const typet &subtype=ns.follow(type.subtype()); unsigned sub_width=boolbv_width(subtype); if(sub_width==0 || width%sub_width!=0) throw "unary-: unexpected vector operand width"; unsigned size=width/sub_width; bv.resize(width); for(unsigned i=0; i<size; i++) { bvt tmp_op; tmp_op.resize(sub_width); for(unsigned j=0; j<tmp_op.size(); j++) { assert(i*sub_width+j<op_bv.size()); tmp_op[j]=op_bv[i*sub_width+j]; } bvt tmp_result; if(type.subtype().id()==ID_floatbv) { float_utilst float_utils(prop); float_utils.spec=to_floatbv_type(subtype); tmp_result=float_utils.negate(tmp_op); } else tmp_result=bv_utils.negate(tmp_op); assert(tmp_result.size()==sub_width); for(unsigned j=0; j<tmp_result.size(); j++) { assert(i*sub_width+j<bv.size()); bv[i*sub_width+j]=tmp_result[j]; } } return; } else if(bvtype==IS_FIXED && op_bvtype==IS_FIXED) { if(no_overflow) bv=bv_utils.negate_no_overflow(op_bv); else bv=bv_utils.negate(op_bv); return; } else if(bvtype==IS_FLOAT && op_bvtype==IS_FLOAT) { assert(!no_overflow); float_utilst float_utils(prop); float_utils.spec=to_floatbv_type(expr.type()); bv=float_utils.negate(op_bv); return; } else if((op_bvtype==IS_SIGNED || op_bvtype==IS_UNSIGNED) && (bvtype==IS_SIGNED || bvtype==IS_UNSIGNED)) { if(no_overflow) prop.l_set_to(bv_utils.overflow_negate(op_bv), false); if(no_overflow) bv=bv_utils.negate_no_overflow(op_bv); else bv=bv_utils.negate(op_bv); return; } conversion_failed(expr, bv); }
bool boolbvt::type_conversion( const typet &src_type, const bvt &src, const typet &dest_type, bvt &dest) { bvtypet dest_bvtype=get_bvtype(dest_type); bvtypet src_bvtype=get_bvtype(src_type); if(src_bvtype==IS_C_BIT_FIELD) return type_conversion( c_bit_field_replacement_type(to_c_bit_field_type(src_type), ns), src, dest_type, dest); if(dest_bvtype==IS_C_BIT_FIELD) return type_conversion( src_type, src, c_bit_field_replacement_type(to_c_bit_field_type(dest_type), ns), dest); std::size_t src_width=src.size(); std::size_t dest_width=boolbv_width(dest_type); if(dest_width==0 || src_width==0) return true; dest.clear(); dest.reserve(dest_width); if(dest_type.id()==ID_complex) { if(src_type==dest_type.subtype()) { forall_literals(it, src) dest.push_back(*it); // pad with zeros for(std::size_t i=src.size(); i<dest_width; i++) dest.push_back(const_literal(false)); return false; } else if(src_type.id()==ID_complex) { // recursively do both halfs bvt lower, upper, lower_res, upper_res; lower.assign(src.begin(), src.begin()+src.size()/2); upper.assign(src.begin()+src.size()/2, src.end()); type_conversion(ns.follow(src_type.subtype()), lower, ns.follow(dest_type.subtype()), lower_res); type_conversion(ns.follow(src_type.subtype()), upper, ns.follow(dest_type.subtype()), upper_res); assert(lower_res.size()+upper_res.size()==dest_width); dest=lower_res; dest.insert(dest.end(), upper_res.begin(), upper_res.end()); return false; } } if(src_type.id()==ID_complex) { assert(dest_type.id()!=ID_complex); if(dest_type.id()==ID_signedbv || dest_type.id()==ID_unsignedbv || dest_type.id()==ID_floatbv || dest_type.id()==ID_fixedbv || dest_type.id()==ID_c_enum || dest_type.id()==ID_c_enum_tag || dest_type.id()==ID_bool) { // A cast from complex x to real T // is (T) __real__ x. bvt tmp_src(src); tmp_src.resize(src.size()/2); // cut off imag part return type_conversion(src_type.subtype(), tmp_src, dest_type, dest); } } switch(dest_bvtype) { case IS_RANGE: if(src_bvtype==IS_UNSIGNED || src_bvtype==IS_SIGNED || src_bvtype==IS_C_BOOL) { mp_integer dest_from=to_range_type(dest_type).get_from(); if(dest_from==0) { // do zero extension dest.resize(dest_width); for(std::size_t i=0; i<dest.size(); i++) dest[i]=(i<src.size()?src[i]:const_literal(false)); return false; } } else if(src_bvtype==IS_RANGE) // range to range { mp_integer src_from=to_range_type(src_type).get_from(); mp_integer dest_from=to_range_type(dest_type).get_from(); if(dest_from==src_from) { // do zero extension, if needed dest=bv_utils.zero_extension(src, dest_width); return false; } else { // need to do arithmetic: add src_from-dest_from mp_integer offset=src_from-dest_from; dest= bv_utils.add( bv_utils.zero_extension(src, dest_width), bv_utils.build_constant(offset, dest_width)); } return false; } break; case IS_FLOAT: // to float { float_utilst float_utils(prop); switch(src_bvtype) { case IS_FLOAT: // float to float // we don't have a rounding mode here, // which is why we refuse. break; case IS_SIGNED: // signed to float case IS_C_ENUM: float_utils.spec=to_floatbv_type(dest_type); dest=float_utils.from_signed_integer(src); return false; case IS_UNSIGNED: // unsigned to float case IS_C_BOOL: // _Bool to float float_utils.spec=to_floatbv_type(dest_type); dest=float_utils.from_unsigned_integer(src); return false; case IS_BV: assert(src_width==dest_width); dest=src; return false; default: if(src_type.id()==ID_bool) { // bool to float // build a one ieee_floatt f; f.spec=to_floatbv_type(dest_type); f.from_integer(1); dest=convert_bv(f.to_expr()); assert(src_width==1); Forall_literals(it, dest) *it=prop.land(*it, src[0]); return false; } } } break; case IS_FIXED: if(src_bvtype==IS_FIXED) { // fixed to fixed std::size_t dest_fraction_bits=to_fixedbv_type(dest_type).get_fraction_bits(), dest_int_bits=dest_width-dest_fraction_bits; std::size_t op_fraction_bits=to_fixedbv_type(src_type).get_fraction_bits(), op_int_bits=src_width-op_fraction_bits; dest.resize(dest_width); // i == position after dot // i == 0: first position after dot for(std::size_t i=0; i<dest_fraction_bits; i++) { // position in bv std::size_t p=dest_fraction_bits-i-1; if(i<op_fraction_bits) dest[p]=src[op_fraction_bits-i-1]; else dest[p]=const_literal(false); // zero padding } for(std::size_t i=0; i<dest_int_bits; i++) { // position in bv std::size_t p=dest_fraction_bits+i; assert(p<dest_width); if(i<op_int_bits) dest[p]=src[i+op_fraction_bits]; else dest[p]=src[src_width-1]; // sign extension } return false; } else if(src_bvtype==IS_BV) { assert(src_width==dest_width); dest=src; return false; } else if(src_bvtype==IS_UNSIGNED || src_bvtype==IS_SIGNED || src_bvtype==IS_C_BOOL || src_bvtype==IS_C_ENUM) { // integer to fixed std::size_t dest_fraction_bits= to_fixedbv_type(dest_type).get_fraction_bits(); for(std::size_t i=0; i<dest_fraction_bits; i++) dest.push_back(const_literal(false)); // zero padding for(std::size_t i=0; i<dest_width-dest_fraction_bits; i++) { literalt l; if(i<src_width) l=src[i]; else { if(src_bvtype==IS_SIGNED || src_bvtype==IS_C_ENUM) l=src[src_width-1]; // sign extension else l=const_literal(false); // zero extension } dest.push_back(l); } return false; } else if(src_type.id()==ID_bool) { // bool to fixed std::size_t fraction_bits= to_fixedbv_type(dest_type).get_fraction_bits(); assert(src_width==1); for(std::size_t i=0; i<dest_width; i++) { if(i==fraction_bits) dest.push_back(src[0]); else dest.push_back(const_literal(false)); } return false; } break; case IS_UNSIGNED: case IS_SIGNED: case IS_C_ENUM: switch(src_bvtype) { case IS_FLOAT: // float to integer // we don't have a rounding mode here, // which is why we refuse. break; case IS_FIXED: // fixed to integer { std::size_t op_fraction_bits= to_fixedbv_type(src_type).get_fraction_bits(); for(std::size_t i=0; i<dest_width; i++) { if(i<src_width-op_fraction_bits) dest.push_back(src[i+op_fraction_bits]); else { if(dest_bvtype==IS_SIGNED) dest.push_back(src[src_width-1]); // sign extension else dest.push_back(const_literal(false)); // zero extension } } // we might need to round up in case of negative numbers // e.g., (int)(-1.00001)==1 bvt fraction_bits_bv=src; fraction_bits_bv.resize(op_fraction_bits); literalt round_up= prop.land(prop.lor(fraction_bits_bv), src.back()); dest=bv_utils.incrementer(dest, round_up); return false; } case IS_UNSIGNED: // integer to integer case IS_SIGNED: case IS_C_ENUM: case IS_C_BOOL: { // We do sign extension for any source type // that is signed, independently of the // destination type. // E.g., ((short)(ulong)(short)-1)==-1 bool sign_extension= src_bvtype==IS_SIGNED || src_bvtype==IS_C_ENUM; for(std::size_t i=0; i<dest_width; i++) { if(i<src_width) dest.push_back(src[i]); else if(sign_extension) dest.push_back(src[src_width-1]); // sign extension else dest.push_back(const_literal(false)); } return false; } case IS_VERILOG_UNSIGNED: // verilog_unsignedbv to signed/unsigned/enum { for(std::size_t i=0; i<dest_width; i++) { std::size_t src_index=i*2; // we take every second bit if(src_index<src_width) dest.push_back(src[src_index]); else // always zero-extend dest.push_back(const_literal(false)); } return false; } break; case IS_VERILOG_SIGNED: // verilog_signedbv to signed/unsigned/enum { for(std::size_t i=0; i<dest_width; i++) { std::size_t src_index=i*2; // we take every second bit if(src_index<src_width) dest.push_back(src[src_index]); else // always sign-extend dest.push_back(src.back()); } return false; } break; default: if(src_type.id()==ID_bool) { // bool to integer assert(src_width==1); for(std::size_t i=0; i<dest_width; i++) { if(i==0) dest.push_back(src[0]); else dest.push_back(const_literal(false)); } return false; } } break; case IS_VERILOG_UNSIGNED: if(src_bvtype==IS_UNSIGNED || src_bvtype==IS_C_BOOL || src_type.id()==ID_bool) { for(std::size_t i=0, j=0; i<dest_width; i+=2, j++) { if(j<src_width) dest.push_back(src[j]); else dest.push_back(const_literal(false)); dest.push_back(const_literal(false)); } return false; } else if(src_bvtype==IS_SIGNED) { for(std::size_t i=0, j=0; i<dest_width; i+=2, j++) { if(j<src_width) dest.push_back(src[j]); else dest.push_back(src.back()); dest.push_back(const_literal(false)); } return false; } else if(src_bvtype==IS_VERILOG_UNSIGNED) { // verilog_unsignedbv to verilog_unsignedbv dest=src; if(dest_width<src_width) dest.resize(dest_width); else { dest=src; while(dest.size()<dest_width) { dest.push_back(const_literal(false)); dest.push_back(const_literal(false)); } } return false; } break; case IS_BV: assert(src_width==dest_width); dest=src; return false; case IS_C_BOOL: dest.resize(dest_width, const_literal(false)); if(src_bvtype==IS_FLOAT) { float_utilst float_utils(prop); float_utils.spec=to_floatbv_type(src_type); dest[0]=!float_utils.is_zero(src); } else if(src_bvtype==IS_C_BOOL) dest[0]=src[0]; else dest[0]=!bv_utils.is_zero(src); return false; default: if(dest_type.id()==ID_array) { if(src_width==dest_width) { dest=src; return false; } } else if(dest_type.id()==ID_struct) { const struct_typet &dest_struct = to_struct_type(dest_type); if(src_type.id()==ID_struct) { // we do subsets dest.resize(dest_width, const_literal(false)); const struct_typet &op_struct = to_struct_type(src_type); const struct_typet::componentst &dest_comp= dest_struct.components(); const struct_typet::componentst &op_comp= op_struct.components(); // build offset maps offset_mapt op_offsets, dest_offsets; build_offset_map(op_struct, op_offsets); build_offset_map(dest_struct, dest_offsets); // build name map typedef std::map<irep_idt, unsigned> op_mapt; op_mapt op_map; for(std::size_t i=0; i<op_comp.size(); i++) op_map[op_comp[i].get_name()]=i; // now gather required fields for(std::size_t i=0; i<dest_comp.size(); i++) { std::size_t offset=dest_offsets[i]; std::size_t comp_width=boolbv_width(dest_comp[i].type()); if(comp_width==0) continue; op_mapt::const_iterator it= op_map.find(dest_comp[i].get_name()); if(it==op_map.end()) { // not found // filling with free variables for(std::size_t j=0; j<comp_width; j++) dest[offset+j]=prop.new_variable(); } else { // found if(dest_comp[i].type()!=dest_comp[it->second].type()) { // filling with free variables for(std::size_t j=0; j<comp_width; j++) dest[offset+j]=prop.new_variable(); } else { std::size_t op_offset=op_offsets[it->second]; for(std::size_t j=0; j<comp_width; j++) dest[offset+j]=src[op_offset+j]; } } } return false; } } } return true; }
exprt boolbvt::bv_get_rec( const bvt &bv, const std::vector<bool> &unknown, std::size_t offset, const typet &type) const { if(type.id()==ID_symbol) return bv_get_rec(bv, unknown, offset, ns.follow(type)); std::size_t width=boolbv_width(type); assert(bv.size()==unknown.size()); assert(bv.size()>=offset+width); if(type.id()==ID_bool) { if(!unknown[offset]) { switch(prop.l_get(bv[offset]).get_value()) { case tvt::tv_enumt::TV_FALSE: return false_exprt(); case tvt::tv_enumt::TV_TRUE: return true_exprt(); default: return false_exprt(); // default } } return nil_exprt(); } bvtypet bvtype=get_bvtype(type); if(bvtype==IS_UNKNOWN) { if(type.id()==ID_array) { const typet &subtype=type.subtype(); std::size_t sub_width=boolbv_width(subtype); if(sub_width!=0) { exprt::operandst op; op.reserve(width/sub_width); for(std::size_t new_offset=0; new_offset<width; new_offset+=sub_width) { op.push_back( bv_get_rec(bv, unknown, offset+new_offset, subtype)); } exprt dest=exprt(ID_array, type); dest.operands().swap(op); return dest; } } else if(type.id()==ID_struct_tag) { return bv_get_rec(bv, unknown, offset, ns.follow_tag(to_struct_tag_type(type))); } else if(type.id()==ID_union_tag) { return bv_get_rec(bv, unknown, offset, ns.follow_tag(to_union_tag_type(type))); } else if(type.id()==ID_struct) { const struct_typet &struct_type=to_struct_type(type); const struct_typet::componentst &components=struct_type.components(); std::size_t new_offset=0; exprt::operandst op; op.reserve(components.size()); for(struct_typet::componentst::const_iterator it=components.begin(); it!=components.end(); it++) { const typet &subtype=ns.follow(it->type()); op.push_back(nil_exprt()); std::size_t sub_width=boolbv_width(subtype); if(sub_width!=0) { op.back()=bv_get_rec(bv, unknown, offset+new_offset, subtype); new_offset+=sub_width; } } struct_exprt dest(type); dest.operands().swap(op); return dest; } else if(type.id()==ID_union) { const union_typet &union_type=to_union_type(type); const union_typet::componentst &components=union_type.components(); assert(!components.empty()); // Any idea that's better than just returning the first component? std::size_t component_nr=0; union_exprt value(union_type); value.set_component_name( components[component_nr].get_name()); const typet &subtype=components[component_nr].type(); value.op()=bv_get_rec(bv, unknown, offset, subtype); return value; } else if(type.id()==ID_vector) { const typet &subtype=ns.follow(type.subtype()); std::size_t sub_width=boolbv_width(subtype); if(sub_width!=0 && width%sub_width==0) { std::size_t size=width/sub_width; exprt value(ID_vector, type); value.operands().resize(size); for(std::size_t i=0; i<size; i++) value.operands()[i]= bv_get_rec(bv, unknown, i*sub_width, subtype); return value; } } else if(type.id()==ID_complex) { const typet &subtype=ns.follow(type.subtype()); std::size_t sub_width=boolbv_width(subtype); if(sub_width!=0 && width==sub_width*2) { exprt value(ID_complex, type); value.operands().resize(2); value.op0()=bv_get_rec(bv, unknown, 0*sub_width, subtype); value.op1()=bv_get_rec(bv, unknown, 1*sub_width, subtype); return value; } } } std::string value; for(std::size_t bit_nr=offset; bit_nr<offset+width; bit_nr++) { char ch; if(unknown[bit_nr]) ch='0'; else switch(prop.l_get(bv[bit_nr]).get_value()) { case tvt::tv_enumt::TV_FALSE: ch='0'; break; case tvt::tv_enumt::TV_TRUE: ch='1'; break; case tvt::tv_enumt::TV_UNKNOWN: ch='0'; break; default: assert(false); } value=ch+value; } switch(bvtype) { case IS_UNKNOWN: if(type.id()==ID_string) { mp_integer int_value=binary2integer(value, false); irep_idt s; if(int_value>=string_numbering.size()) s=irep_idt(); else s=string_numbering[int_value.to_long()]; return constant_exprt(s, type); } break; case IS_RANGE: { mp_integer int_value=binary2integer(value, false); mp_integer from=string2integer(type.get_string(ID_from)); constant_exprt value_expr(type); value_expr.set_value(integer2string(int_value+from)); return value_expr; } break; default: case IS_C_ENUM: constant_exprt value_expr(type); value_expr.set_value(value); return value_expr; } return nil_exprt(); }
void boolbvt::convert_update_rec( const exprt::operandst &designators, std::size_t d, const typet &type, std::size_t offset, const exprt &new_value, bvt &bv) { if(type.id()==ID_symbol) convert_update_rec( designators, d, ns.follow(type), offset, new_value, bv); if(d>=designators.size()) { // done bvt new_value_bv=convert_bv(new_value); std::size_t new_value_width=boolbv_width(type); if(new_value_width!=new_value_bv.size()) throw "convert_update_rec: unexpected new_value size"; // update for(std::size_t i=0; i<new_value_width; i++) { assert(offset+i<bv.size()); bv[offset+i]=new_value_bv[i]; } return; } const exprt &designator=designators[d]; if(designator.id()==ID_index_designator) { if(type.id()!=ID_array) throw "update: index designator needs array"; if(designator.operands().size()!=1) throw "update: index designator takes one operand"; bvt index_bv=convert_bv(designator.op0()); const array_typet &array_type=to_array_type(type); const typet &subtype=ns.follow(array_type.subtype()); std::size_t element_size=boolbv_width(subtype); // iterate over array mp_integer size; if(to_integer(array_type.size(), size)) throw "update: failed to get array size"; bvt tmp_bv=bv; for(std::size_t i=0; i!=integer2long(size); ++i) { std::size_t new_offset=offset+i*element_size; convert_update_rec( designators, d+1, subtype, new_offset, new_value, tmp_bv); bvt const_bv=bv_utils.build_constant(i, index_bv.size()); literalt equal=bv_utils.equal(const_bv, index_bv); for(std::size_t j=0; j<element_size; j++) { std::size_t idx=new_offset+j; assert(idx<bv.size()); bv[idx]=prop.lselect(equal, tmp_bv[idx], bv[idx]); } } } else if(designator.id()==ID_member_designator) { const irep_idt &component_name=designator.get(ID_component_name); if(type.id()==ID_struct) { const struct_typet &struct_type= to_struct_type(type); std::size_t struct_offset=0; struct_typet::componentt component; component.make_nil(); const struct_typet::componentst &components= struct_type.components(); for(struct_typet::componentst::const_iterator it=components.begin(); it!=components.end(); it++) { const typet &subtype=it->type(); std::size_t sub_width=boolbv_width(subtype); if(it->get_name()==component_name) { component=*it; break; // done } struct_offset+=sub_width; } if(component.is_nil()) throw "update: failed to find struct component"; const typet &new_type=ns.follow(component.type()); std::size_t new_offset=offset+struct_offset; // recursive call convert_update_rec( designators, d+1, new_type, new_offset, new_value, bv); } else if(type.id()==ID_union) { const union_typet &union_type= to_union_type(type); const union_typet::componentt &component= union_type.get_component(component_name); if(component.is_nil()) throw "update: failed to find union component"; // this only adjusts the type, the offset stays as-is const typet &new_type=ns.follow(component.type()); // recursive call convert_update_rec( designators, d+1, new_type, offset, new_value, bv); } else throw "update: member designator needs struct or union"; } else throw "update: unexpected designator"; }
void boolbvt::convert_add_sub(const exprt &expr, bvt &bv) { const typet &type=ns.follow(expr.type()); if(type.id()!=ID_unsignedbv && type.id()!=ID_signedbv && type.id()!=ID_fixedbv && type.id()!=ID_floatbv && type.id()!=ID_range && type.id()!=ID_vector) return conversion_failed(expr, bv); unsigned width=boolbv_width(type); if(width==0) return conversion_failed(expr, bv); const exprt::operandst &operands=expr.operands(); if(operands.size()==0) throw "operand "+expr.id_string()+" takes at least one operand"; const exprt &op0=expr.op0(); if(op0.type()!=type) { std::cerr << expr.pretty() << std::endl; throw "add/sub with mixed types"; } convert_bv(op0, bv); if(bv.size()!=width) throw "convert_add_sub: unexpected operand 0 width"; bool subtract=(expr.id()==ID_minus || expr.id()=="no-overflow-minus"); bool no_overflow=(expr.id()=="no-overflow-plus" || expr.id()=="no-overflow-minus"); typet arithmetic_type= (type.id()==ID_vector)?ns.follow(type.subtype()):type; bv_utilst::representationt rep= (arithmetic_type.id()==ID_signedbv || arithmetic_type.id()==ID_fixedbv)?bv_utilst::SIGNED: bv_utilst::UNSIGNED; for(exprt::operandst::const_iterator it=operands.begin()+1; it!=operands.end(); it++) { if(it->type()!=type) { std::cerr << expr.pretty() << std::endl; throw "add/sub with mixed types"; } bvt op; convert_bv(*it, op); if(op.size()!=width) throw "convert_add_sub: unexpected operand width"; if(type.id()==ID_vector) { const typet &subtype=ns.follow(type.subtype()); unsigned sub_width=boolbv_width(subtype); if(sub_width==0 || width%sub_width!=0) throw "convert_add_sub: unexpected vector operand width"; unsigned size=width/sub_width; bv.resize(width); for(unsigned i=0; i<size; i++) { bvt tmp_op; tmp_op.resize(sub_width); for(unsigned j=0; j<tmp_op.size(); j++) { assert(i*sub_width+j<op.size()); tmp_op[j]=op[i*sub_width+j]; } bvt tmp_result; tmp_result.resize(sub_width); for(unsigned j=0; j<tmp_result.size(); j++) { assert(i*sub_width+j<bv.size()); tmp_result[j]=bv[i*sub_width+j]; } if(type.subtype().id()==ID_floatbv) { #ifdef HAVE_FLOATBV float_utilst float_utils(prop); float_utils.spec=to_floatbv_type(subtype); tmp_result=float_utils.add_sub(tmp_result, tmp_op, subtract); #else return conversion_failed(expr, bv); #endif } else tmp_result=bv_utils.add_sub(tmp_result, tmp_op, subtract); assert(tmp_result.size()==sub_width); for(unsigned j=0; j<tmp_result.size(); j++) { assert(i*sub_width+j<bv.size()); bv[i*sub_width+j]=tmp_result[j]; } } } else if(type.id()==ID_floatbv) { #ifdef HAVE_FLOATBV float_utilst float_utils(prop); float_utils.spec=to_floatbv_type(arithmetic_type); bv=float_utils.add_sub(bv, op, subtract); #else return conversion_failed(expr, bv); #endif } else if(no_overflow) bv=bv_utils.add_sub_no_overflow(bv, op, subtract, rep); else bv=bv_utils.add_sub(bv, op, subtract); } }