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_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_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; }
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; }
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_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_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; }
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); }
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_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_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_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); }
void boolbvt::convert_index(const index_exprt &expr, bvt &bv) { if(expr.id()!=ID_index) throw "expected index expression"; if(expr.operands().size()!=2) throw "index takes two operands"; const exprt &array=expr.array(); const exprt &index=expr.index(); const array_typet &array_type= to_array_type(ns.follow(array.type())); // see if the array size is constant if(is_unbounded_array(array_type)) { // use array decision procedure unsigned width=boolbv_width(expr.type()); if(width==0) return conversion_failed(expr, bv); // free variables bv.resize(width); for(unsigned i=0; i<width; i++) bv[i]=prop.new_variable(); record_array_index(expr); // record type if array is a symbol if(array.id()==ID_symbol) map.get_map_entry( to_symbol_expr(array).get_identifier(), array_type); // make sure we have the index in the cache convert_bv(index); return; } // see if the index address is constant mp_integer index_value; if(!to_integer(index, index_value)) return convert_index(array, index_value, bv); unsigned width=boolbv_width(expr.type()); if(width==0) return conversion_failed(expr, bv); mp_integer array_size; if(to_integer(array_type.size(), array_size)) { std::cout << to_array_type(array.type()).size().pretty() << std::endl; throw "failed to convert array size"; } // get literals for the whole array const bvt &array_bv=convert_bv(array); if(array_size*width!=array_bv.size()) throw "unexpected array size"; // TODO: maybe a shifter-like construction would be better if(prop.has_set_to()) { // free variables bv.resize(width); for(unsigned i=0; i<width; i++) bv[i]=prop.new_variable(); // add implications equal_exprt index_equality; index_equality.lhs()=index; // index operand bvt equal_bv; equal_bv.resize(width); for(mp_integer i=0; i<array_size; i=i+1) { index_equality.rhs()=from_integer(i, index_equality.lhs().type()); if(index_equality.rhs().is_nil()) throw "number conversion failed (1)"; mp_integer offset=i*width; for(unsigned j=0; j<width; j++) equal_bv[j]=prop.lequal(bv[j], array_bv[integer2long(offset+j)]); prop.l_set_to_true( prop.limplies(convert(index_equality), prop.land(equal_bv))); } } else { bv.resize(width); equal_exprt equality; equality.lhs()=index; // index operand typet constant_type=index.type(); // type of index operand assert(array_size>0); for(mp_integer i=0; i<array_size; i=i+1) { equality.op1()=from_integer(i, constant_type); literalt e=convert(equality); mp_integer offset=i*width; for(unsigned j=0; j<width; j++) { literalt l=array_bv[integer2long(offset+j)]; if(i==0) // this initializes bv bv[j]=l; else bv[j]=prop.lselect(e, l, bv[j]); } } } }
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); } }
void boolbvt::convert_constraint_select_one(const exprt &expr, bvt &bv) { const exprt::operandst &operands=expr.operands(); if(expr.id()!="constraint_select_one") throw "expected constraint_select_one expression"; if(operands.size()<2) throw "constraint_select_one takes at least two operands"; if(expr.type()!=expr.op0().type()) throw "constraint_select_one expects matching types"; if(prop.has_set_to()) { std::vector<bvt> op_bv; op_bv.reserve(expr.operands().size()); forall_operands(it, expr) op_bv.push_back(convert_bv(*it)); bv=op_bv[0]; // add constraints bvt equal_bv; equal_bv.resize(bv.size()); bvt b; b.reserve(op_bv.size()-1); for(unsigned i=1; i<op_bv.size(); i++) { if(op_bv[i].size()!=bv.size()) throw "constraint_select_one expects matching width"; for(unsigned j=0; j<bv.size(); j++) equal_bv[j]=prop.lequal(bv[j], op_bv[i][j]); b.push_back(prop.land(equal_bv)); } prop.l_set_to_true(prop.lor(b)); } else { unsigned op_nr=0; forall_operands(it, expr) { const bvt &op_bv=convert_bv(*it); if(op_nr==0) bv=op_bv; else { if(op_bv.size()!=bv.size()) return conversion_failed(expr, bv); for(unsigned i=0; i<op_bv.size(); i++) bv[i]=prop.lselect(prop.new_variable(), bv[i], op_bv[i]); } op_nr++; } } }
void 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); }
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_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); }
void boolbvt::convert_bitwise(const exprt &expr, bvt &bv) { unsigned width=boolbv_width(expr.type()); if(width==0) return conversion_failed(expr, bv); if(expr.id()==ID_bitnot) { if(expr.operands().size()!=1) throw "bitnot takes one operand"; const exprt &op0=expr.op0(); const bvt &op_bv=convert_bv(op0); if(op_bv.size()!=width) throw "convert_bitwise: unexpected operand width"; bv=bv_utils.inverted(op_bv); return; } else if(expr.id()==ID_bitand || expr.id()==ID_bitor || expr.id()==ID_bitxor || expr.id()==ID_bitnand || expr.id()==ID_bitnor || expr.id()==ID_bitxnor) { bv.resize(width); forall_operands(it, expr) { const bvt &op=convert_bv(*it); if(op.size()!=width) throw "convert_bitwise: unexpected operand width"; if(it==expr.operands().begin()) bv=op; else { for(unsigned i=0; i<width; i++) { if(expr.id()==ID_bitand) bv[i]=prop.land(bv[i], op[i]); else if(expr.id()==ID_bitor) bv[i]=prop.lor(bv[i], op[i]); else if(expr.id()==ID_bitxor) bv[i]=prop.lxor(bv[i], op[i]); else if(expr.id()==ID_bitnand) bv[i]=prop.lnand(bv[i], op[i]); else if(expr.id()==ID_bitnor) bv[i]=prop.lnor(bv[i], op[i]); else if(expr.id()==ID_bitxnor) bv[i]=prop.lequal(bv[i], op[i]); else throw "unexpected operand"; } } } return; }
void boolbvt::convert_case(const exprt &expr, bvt &bv) { const std::vector<exprt> &operands=expr.operands(); unsigned width=boolbv_width(expr.type()); if(width==0) return conversion_failed(expr, bv); bv.resize(width); // make it free variables Forall_literals(it, bv) *it=prop.new_variable(); if(operands.size()<3) throw "case takes at least three operands"; if((operands.size()%2)!=1) throw "number of case operands must be odd"; enum { FIRST, COMPARE, VALUE } what=FIRST; bvt compare_bv; literalt previous_compare=const_literal(false); literalt compare_literal=const_literal(false); forall_operands(it, expr) { bvt op=convert_bv(*it); switch(what) { case FIRST: compare_bv.swap(op); what=COMPARE; break; case COMPARE: if(compare_bv.size()!=op.size()) { std::cerr << "compare operand: " << compare_bv.size() << std::endl << "operand: " << op.size() << std::endl << it->pretty() << std::endl; throw "size of compare operand does not match"; } compare_literal=bv_utils.equal(compare_bv, op); compare_literal=prop.land(prop.lnot(previous_compare), compare_literal); previous_compare=prop.lor(previous_compare, compare_literal); what=VALUE; break; case VALUE: if(bv.size()!=op.size()) { std::cerr << "result size: " << bv.size() << std::endl << "operand: " << op.size() << std::endl << it->pretty() << std::endl; throw "size of value operand does not match"; } { literalt value_literal=bv_utils.equal(bv, op); prop.l_set_to_true( prop.limplies(compare_literal, value_literal)); } what=COMPARE; break; default: assert(false); } }
bvt boolbvt::convert_shift(const binary_exprt &expr) { const irep_idt &type_id=expr.type().id(); if(type_id!=ID_unsignedbv && type_id!=ID_signedbv && type_id!=ID_floatbv && type_id!=ID_pointer && type_id!=ID_bv && type_id!=ID_verilog_signedbv && type_id!=ID_verilog_unsignedbv) return conversion_failed(expr); std::size_t width=boolbv_width(expr.type()); if(width==0) return conversion_failed(expr); if(expr.operands().size()!=2) throw "shifting takes two operands"; const bvt &op=convert_bv(expr.op0()); if(op.size()!=width) throw "convert_shift: unexpected operand 0 width"; bv_utilst::shiftt shift; if(expr.id()==ID_shl) shift=bv_utilst::shiftt::LEFT; else if(expr.id()==ID_ashr) shift=bv_utilst::shiftt::ARIGHT; else if(expr.id()==ID_lshr) shift=bv_utilst::shiftt::LRIGHT; else throw "unexpected shift operator"; // we allow a constant as shift distance if(expr.op1().is_constant()) { mp_integer i; if(to_integer(expr.op1(), i)) throw "convert_shift: failed to convert constant"; std::size_t distance; if(i<0 || i>std::numeric_limits<signed>::max()) distance=0; else distance=integer2size_t(i); if(type_id==ID_verilog_signedbv || type_id==ID_verilog_unsignedbv) distance*=2; return bv_utils.shift(op, shift, distance); } else { const bvt &distance=convert_bv(expr.op1()); return bv_utils.shift(op, shift, distance); } }