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); }
literalt boolbvt::convert_ieee_float_rel(const exprt &expr) { const exprt::operandst &operands=expr.operands(); const irep_idt &rel=expr.id(); if(operands.size()==2) { const exprt &op0=expr.op0(); const exprt &op1=expr.op1(); bvtypet bvtype0=get_bvtype(op0.type()); bvtypet bvtype1=get_bvtype(op1.type()); const bvt &bv0=convert_bv(op0); const bvt &bv1=convert_bv(op1); if(bv0.size()==bv1.size() && !bv0.empty() && bvtype0==IS_FLOAT && bvtype1==IS_FLOAT) { float_utilst float_utils(prop); float_utils.spec=to_floatbv_type(op0.type()); if(rel==ID_ieee_float_equal) return float_utils.relation(bv0, float_utilst::EQ, bv1); else if(rel==ID_ieee_float_notequal) return !float_utils.relation(bv0, float_utilst::EQ, bv1); else return SUB::convert_rest(expr); } } return SUB::convert_rest(expr); }
literalt boolbvt::convert_verilog_case_equality( const binary_relation_exprt &expr) { // This is 4-valued comparison, i.e., z===z, x===x etc. // The result is always Boolean. if(!base_type_eq(expr.lhs().type(), expr.rhs().type(), ns)) { std::cout << "######### lhs: " << expr.lhs().pretty() << '\n'; std::cout << "######### rhs: " << expr.rhs().pretty() << '\n'; throw "verilog_case_equality without matching types"; } const bvt &bv0=convert_bv(expr.lhs()); const bvt &bv1=convert_bv(expr.rhs()); if(bv0.size()!=bv1.size()) { std::cerr << "lhs: " << expr.lhs().pretty() << '\n'; std::cerr << "lhs size: " << bv0.size() << '\n'; std::cerr << "rhs: " << expr.rhs().pretty() << '\n'; std::cerr << "rhs size: " << bv1.size() << '\n'; throw "unexpected size mismatch on verilog_case_equality"; } if(expr.id()==ID_verilog_case_inequality) return !bv_utils.equal(bv0, bv1); else return bv_utils.equal(bv0, bv1); }
void boolbvt::convert_floatbv_typecast( const floatbv_typecast_exprt &expr, bvt &bv) { const exprt &op0=expr.op(); // number to convert const exprt &op1=expr.rounding_mode(); // rounding mode bvt bv0=convert_bv(op0); bvt bv1=convert_bv(op1); const typet &src_type=ns.follow(expr.op0().type()); const typet &dest_type=ns.follow(expr.type()); if(src_type==dest_type) // redundant type cast? { bv=bv0; return; } float_utilst float_utils(prop); float_utils.set_rounding_mode(convert_bv(op1)); if(src_type.id()==ID_floatbv && dest_type.id()==ID_floatbv) { float_utils.spec=to_floatbv_type(src_type); bv=float_utils.conversion(bv0, to_floatbv_type(dest_type)); } else if(src_type.id()==ID_signedbv && dest_type.id()==ID_floatbv) { float_utils.spec=to_floatbv_type(dest_type); bv=float_utils.from_signed_integer(bv0); } else if(src_type.id()==ID_unsignedbv && dest_type.id()==ID_floatbv) { float_utils.spec=to_floatbv_type(dest_type); bv=float_utils.from_unsigned_integer(bv0); } else if(src_type.id()==ID_floatbv && dest_type.id()==ID_signedbv) { std::size_t dest_width=to_signedbv_type(dest_type).get_width(); float_utils.spec=to_floatbv_type(src_type); bv=float_utils.to_signed_integer(bv0, dest_width); } else if(src_type.id()==ID_floatbv && dest_type.id()==ID_unsignedbv) { std::size_t dest_width=to_unsignedbv_type(dest_type).get_width(); float_utils.spec=to_floatbv_type(src_type); bv=float_utils.to_unsigned_integer(bv0, dest_width); } else return conversion_failed(expr, bv); }
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; }
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; }
void boolbvt::convert_with_union( const union_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); if(next_bv.size()<op2_bv.size()) { error().source_location=type.source_location(); error() << "convert_with_union: unexpected operand op2 width" << eom; throw 0; } if(config.ansi_c.endianness==configt::ansi_ct::endiannesst::IS_LITTLE_ENDIAN) { for(std::size_t i=0; i<op2_bv.size(); i++) next_bv[i]=op2_bv[i]; } else { assert(config.ansi_c.endianness==configt::ansi_ct::endiannesst::IS_BIG_ENDIAN); endianness_mapt map_u(type, false, ns); endianness_mapt map_op2(op2.type(), false, ns); for(std::size_t i=0; i<op2_bv.size(); i++) next_bv[map_u.map_bit(i)]=op2_bv[map_op2.map_bit(i)]; } }
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"; }
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; }
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; }
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_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; } }
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); }
literalt boolbvt::convert_equality(const equal_exprt &expr) { if(!base_type_eq(expr.lhs().type(), expr.rhs().type(), ns)) { std::cout << "######### lhs: " << expr.lhs().pretty() << '\n'; std::cout << "######### rhs: " << expr.rhs().pretty() << '\n'; throw "equality without matching types"; } // see if it is an unbounded array if(is_unbounded_array(expr.lhs().type())) { // flatten byte_update/byte_extract operators if needed if(has_byte_operator(expr)) { exprt tmp=flatten_byte_operators(expr, ns); return record_array_equality(to_equal_expr(tmp)); } return record_array_equality(expr); } const bvt &bv0=convert_bv(expr.lhs()); const bvt &bv1=convert_bv(expr.rhs()); if(bv0.size()!=bv1.size()) { std::cerr << "lhs: " << expr.lhs().pretty() << '\n'; std::cerr << "lhs size: " << bv0.size() << '\n'; std::cerr << "rhs: " << expr.rhs().pretty() << '\n'; std::cerr << "rhs size: " << bv1.size() << '\n'; throw "unexpected size mismatch on equality"; } if(bv0.empty()) { // An empty bit-vector comparison. It's not clear // what this is meant to say. return prop.new_variable(); } return bv_utils.equal(bv0, bv1); }
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_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_bv_typecast(const typecast_exprt &expr) { const typet &expr_type=ns.follow(expr.type()); const exprt &op=expr.op(); const typet &op_type=ns.follow(op.type()); const bvt &op_bv=convert_bv(op); bvt bv; if(type_conversion(op_type, op_bv, expr_type, bv)) return conversion_failed(expr); 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_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_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; }
void bv_refinementt::freeze_lazy_constraints() { if(!lazy_arrays) return; for(std::list<lazy_constraintt>::iterator l_it = lazy_array_constraints.begin(); l_it != lazy_array_constraints.end(); ++l_it) { std::set<symbol_exprt> symbols; find_symbols(l_it->lazy,symbols); for(std::set<symbol_exprt>::const_iterator it = symbols.begin(); it != symbols.end(); ++it) { bvt bv = convert_bv(l_it->lazy); forall_literals(b_it, bv) if(!b_it->is_constant()) prop.set_frozen(*b_it); } } }
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); }
literalt boolbvt::convert_onehot(const unary_exprt &expr) { bvt op=convert_bv(expr.op()); literalt one_seen=const_literal(false); literalt more_than_one_seen=const_literal(false); for(bvt::const_iterator it=op.begin(); it!=op.end(); it++) { more_than_one_seen= prop.lor(more_than_one_seen, prop.land(*it, one_seen)); one_seen=prop.lor(*it, one_seen); } if(expr.id()==ID_onehot) return prop.land(one_seen, !more_than_one_seen); else if(expr.id()==ID_onehot0) return !more_than_one_seen; else throw "unexpected onehot expression"; }
literalt boolbvt::convert_typecast(const typecast_exprt &expr) { assert(expr.operands().size()==1); if(expr.op0().type().id()==ID_range) { mp_integer from=string2integer(expr.op0().type().get_string(ID_from)); mp_integer to=string2integer(expr.op0().type().get_string(ID_to)); if(from==1 && to==1) return const_literal(true); else if(from==0 && to==0) return const_literal(false); } const bvt &bv=convert_bv(expr.op0()); if(!bv.empty()) return prop.lor(bv); return SUB::convert_rest(expr); }
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_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(); }
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); }