literalt smt1_propt::lxor(const bvt &bv) { if(bv.size()==0) return const_literal(false); if(bv.size()==1) return bv[0]; out << std::endl; literalt l=new_variable(); out << ":assumption ; lxor" << std::endl; out << " (iff " << smt1_literal(l) << " (xor"; forall_literals(it, bv) out << " " << smt1_literal(*it); out << "))" << std::endl; return l; }
bvt bv_utilst::extension( const bvt &bv, std::size_t new_size, representationt rep) { std::size_t old_size=bv.size(); bvt result=bv; result.resize(new_size); assert(old_size!=0); literalt extend_with= (rep==SIGNED && !bv.empty())?bv[old_size-1]: const_literal(false); for(std::size_t i=old_size; i<new_size; i++) result[i]=extend_with; return result; }
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); }
bool z3_propt::process_clause(const bvt &bv, bvt &dest) { dest.clear(); // empty clause! this is UNSAT if(bv.empty()) return false; std::set<literalt> s; dest.reserve(bv.size()); for(bvt::const_iterator it=bv.begin(); it!=bv.end(); it++) { literalt l=*it; // we never use index 0 assert(l.var_no()!=0); if(l.is_true()) return true; // clause satisfied if(l.is_false()) continue; if(l.var_no()>=_no_variables) std::cout << "l.var_no()=" << l.var_no() << " _no_variables=" << _no_variables << std::endl; assert(l.var_no()<_no_variables); // prevent duplicate literals if(s.insert(l).second) dest.push_back(l); if(s.find(lnot(l))!=s.end()) return true; // clause satisfied } return false; }
void smt1_propt::lcnf(const bvt &bv) { out << std::endl; out << ":assumption ; lcnf" << std::endl; out << " "; if(bv.empty()) out << "false ; the empty clause"; else if(bv.size()==1) out << smt1_literal(bv.front()); else { out << "(or"; for(bvt::const_iterator it=bv.begin(); it!=bv.end(); it++) out << " " << smt1_literal(*it); out << ")"; } out << std::endl; }
static void write_dimacs_clause( const bvt &clause, std::ostream &out, bool break_lines) { // The DIMACS CNF format allows line breaks in clauses: // "Each clauses is terminated by the value 0. Unlike many formats // that represent the end of a clause by a new-line character, // this format allows clauses to be on multiple lines." // Some historic solvers (zchaff e.g.) have silently swallowed // literals in clauses that exceed some fixed buffer size. // However, the SAT competition format does not allow line // breaks in clauses, so we offer both options. for(size_t j=0; j<clause.size(); j++) { out << clause[j].dimacs() << " "; // newline to avoid overflow in sat checkers if((j&15)==0 && j!=0 && break_lines) out << "\n"; } out << "0" << "\n"; }
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 bv_utilst::overflow_sub( const bvt &op0, const bvt &op1, representationt rep) { if(rep==SIGNED) { // We special-case x-INT_MIN, which is >=0 if // x is negative, always representable, and // thus not an overflow. literalt op1_is_int_min=is_int_min(op1); literalt op0_is_negative=op0[op0.size()-1]; return prop.lselect(op1_is_int_min, !op0_is_negative, overflow_add(op0, negate(op1), SIGNED)); } else if(rep==UNSIGNED) { // overflow is simply _negated_ carry-out return !carry_out(op0, inverted(op1), const_literal(true)); } else assert(false); }
mp_integer boolbvt::get_value( const bvt &bv, unsigned offset, unsigned width) { mp_integer value=0; mp_integer weight=1; for(unsigned bit_nr=offset; bit_nr<offset+width; bit_nr++) { assert(bit_nr<bv.size()); switch(prop.l_get(bv[bit_nr]).get_value()) { case tvt::TV_FALSE: break; case tvt::TV_TRUE: value+=weight; break; case tvt::TV_UNKNOWN: break; default: assert(false); } weight*=2; } return value; }
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); } }
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; }
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); }
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_case(const exprt &expr, bvt &bv) { const std::vector<exprt> &operands=expr.operands(); unsigned width=boolbv_width(expr.type()); if(width==0) return conversion_failed(expr, bv); bv.resize(width); // make it free variables Forall_literals(it, bv) *it=prop.new_variable(); if(operands.size()<3) throw "case takes at least three operands"; if((operands.size()%2)!=1) throw "number of case operands must be odd"; enum { FIRST, COMPARE, VALUE } what=FIRST; bvt compare_bv; literalt previous_compare=const_literal(false); literalt compare_literal=const_literal(false); forall_operands(it, expr) { bvt op=convert_bv(*it); switch(what) { case FIRST: compare_bv.swap(op); what=COMPARE; break; case COMPARE: if(compare_bv.size()!=op.size()) { std::cerr << "compare operand: " << compare_bv.size() << std::endl << "operand: " << op.size() << std::endl << it->pretty() << std::endl; throw "size of compare operand does not match"; } compare_literal=bv_utils.equal(compare_bv, op); compare_literal=prop.land(prop.lnot(previous_compare), compare_literal); previous_compare=prop.lor(previous_compare, compare_literal); what=VALUE; break; case VALUE: if(bv.size()!=op.size()) { std::cerr << "result size: " << bv.size() << std::endl << "operand: " << op.size() << std::endl << it->pretty() << std::endl; throw "size of value operand does not match"; } { literalt value_literal=bv_utils.equal(bv, op); prop.l_set_to_true( prop.limplies(compare_literal, value_literal)); } what=COMPARE; break; default: assert(false); } }
void 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); }
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 prop_convt::set_frozen(const bvt &bv) { for(unsigned i=0; i<bv.size(); i++) if(!bv[i].is_constant()) set_frozen(bv[i]); }
void boolbvt::convert_with_array( const array_typet &type, const exprt &op1, const exprt &op2, const bvt &prev_bv, bvt &next_bv) { if(is_unbounded_array(type)) { // can't do this error().source_location=type.source_location(); error() << "convert_with_array called for unbounded array" << eom; throw 0; } const exprt &array_size=type.size(); mp_integer size; if(to_integer(array_size, size)) { error().source_location=type.source_location(); error() << "convert_with_array expects constant array size" << eom; throw 0; } const bvt &op2_bv=convert_bv(op2); if(size*op2_bv.size()!=prev_bv.size()) { error().source_location=type.source_location(); error() << "convert_with_array: unexpected operand 2 width" << eom; throw 0; } // Is the index a constant? mp_integer op1_value; if(!to_integer(op1, op1_value)) { // Yes, it is! next_bv=prev_bv; if(op1_value>=0 && op1_value<size) // bounds check { std::size_t offset=integer2unsigned(op1_value*op2_bv.size()); for(std::size_t j=0; j<op2_bv.size(); j++) next_bv[offset+j]=op2_bv[j]; } return; } typet counter_type=op1.type(); for(mp_integer i=0; i<size; i=i+1) { exprt counter=from_integer(i, counter_type); literalt eq_lit=convert(equal_exprt(op1, counter)); std::size_t offset=integer2unsigned(i*op2_bv.size()); for(std::size_t j=0; j<op2_bv.size(); j++) next_bv[offset+j]= prop.lselect(eq_lit, op2_bv[j], prev_bv[offset+j]); } }
void float_utilst::normalization_shift(bvt &fraction, bvt &exponent) { #if 0 // this thing is quadratic! bvt new_fraction=prop.new_variables(fraction.size()); bvt new_exponent=prop.new_variables(exponent.size()); // i is the shift distance for(std::size_t i=0; i<fraction.size(); i++) { bvt equal; // the bits above need to be zero for(std::size_t j=0; j<i; j++) equal.push_back( !fraction[fraction.size()-1-j]); // this one needs to be one equal.push_back(fraction[fraction.size()-1-i]); // iff all of that holds, we shift here! literalt shift=prop.land(equal); // build shifted value bvt shifted_fraction=bv_utils.shift(fraction, bv_utilst::LEFT, i); bv_utils.cond_implies_equal(shift, shifted_fraction, new_fraction); // build new exponent bvt adjustment=bv_utils.build_constant(-i, exponent.size()); bvt added_exponent=bv_utils.add(exponent, adjustment); bv_utils.cond_implies_equal(shift, added_exponent, new_exponent); } // Fraction all zero? It stays zero. // The exponent is undefined in that case. literalt fraction_all_zero=bv_utils.is_zero(fraction); bvt zero_fraction; zero_fraction.resize(fraction.size(), const_literal(false)); bv_utils.cond_implies_equal(fraction_all_zero, zero_fraction, new_fraction); fraction=new_fraction; exponent=new_exponent; #else // n-log-n alignment shifter. // The worst-case shift is the number of fraction // bits minus one, in case the faction is one exactly. assert(!fraction.empty()); unsigned depth=integer2unsigned(address_bits(fraction.size()-1)); if(exponent.size()<depth) exponent=bv_utils.sign_extension(exponent, depth); bvt exponent_delta=bv_utils.zeros(exponent.size()); for(int d=depth-1; d>=0; d--) { std::size_t distance=(1<<d); assert(fraction.size()>distance); // check if first 'distance'-many bits are zeros const bvt prefix=bv_utils.extract_msb(fraction, distance); literalt prefix_is_zero=bv_utils.is_zero(prefix); // If so, shift the zeros out left by 'distance'. // Otherwise, leave as is. const bvt shifted= bv_utils.shift(fraction, bv_utilst::LEFT, distance); fraction= bv_utils.select(prefix_is_zero, shifted, fraction); // add corresponding weight to exponent assert(d<(signed)exponent_delta.size()); exponent_delta[d]=prefix_is_zero; } exponent=bv_utils.sub(exponent, exponent_delta); #endif }
bvt float_utilst::add_sub( const bvt &src1, const bvt &src2, bool subtract) { unbiased_floatt unpacked1=unpack(src1); unbiased_floatt unpacked2=unpack(src2); // subtract? if(subtract) unpacked2.sign=!unpacked2.sign; // figure out which operand has the bigger exponent const bvt exponent_difference=subtract_exponents(unpacked1, unpacked2); literalt src2_bigger=exponent_difference.back(); const bvt bigger_exponent= bv_utils.select(src2_bigger, unpacked2.exponent, unpacked1.exponent); // swap fractions as needed const bvt new_fraction1= bv_utils.select(src2_bigger, unpacked2.fraction, unpacked1.fraction); const bvt new_fraction2= bv_utils.select(src2_bigger, unpacked1.fraction, unpacked2.fraction); // compute distance const bvt distance=bv_utils.absolute_value(exponent_difference); // limit the distance: shifting more than f+3 bits is unnecessary const bvt limited_dist=limit_distance(distance, spec.f+3); // pad fractions with 2 zeros from below const bvt fraction1_padded=bv_utils.concatenate(bv_utils.zeros(3), new_fraction1); const bvt fraction2_padded=bv_utils.concatenate(bv_utils.zeros(3), new_fraction2); // shift new_fraction2 literalt sticky_bit; const bvt fraction1_shifted=fraction1_padded; const bvt fraction2_shifted=sticky_right_shift( fraction2_padded, limited_dist, sticky_bit); // sticky bit: or of the bits lost by the right-shift bvt fraction2_stickied=fraction2_shifted; fraction2_stickied[0]=prop.lor(fraction2_shifted[0], sticky_bit); // need to have two extra fraction bits for addition and rounding const bvt fraction1_ext=bv_utils.zero_extension(fraction1_shifted, fraction1_shifted.size()+2); const bvt fraction2_ext=bv_utils.zero_extension(fraction2_stickied, fraction2_stickied.size()+2); unbiased_floatt result; // now add/sub them literalt subtract_lit=prop.lxor(unpacked1.sign, unpacked2.sign); result.fraction= bv_utils.add_sub(fraction1_ext, fraction2_ext, subtract_lit); // sign of result literalt fraction_sign=result.fraction.back(); result.fraction=bv_utils.absolute_value(result.fraction); result.exponent=bigger_exponent; // adjust the exponent for the fact that we added two bits to the fraction result.exponent= bv_utils.add(bv_utils.sign_extension(result.exponent, result.exponent.size()+1), bv_utils.build_constant(2, result.exponent.size()+1)); // NaN? result.NaN=prop.lor( prop.land(prop.land(unpacked1.infinity, unpacked2.infinity), prop.lxor(unpacked1.sign, unpacked2.sign)), prop.lor(unpacked1.NaN, unpacked2.NaN)); // infinity? result.infinity=prop.land( !result.NaN, prop.lor(unpacked1.infinity, unpacked2.infinity)); // zero? // Note that: // 1. The zero flag isn't used apart from in divide and // is only set on unpack // 2. Subnormals mean that addition or subtraction can't round to 0, // thus we can perform this test now // 3. The rules for sign are different for zero result.zero = prop.land( !prop.lor(result.infinity, result.NaN), !prop.lor(result.fraction)); // sign literalt add_sub_sign= prop.lxor(prop.lselect(src2_bigger, unpacked2.sign, unpacked1.sign), fraction_sign); literalt infinity_sign= prop.lselect(unpacked1.infinity, unpacked1.sign, unpacked2.sign); #if 1 literalt zero_sign= prop.lselect(rounding_mode_bits.round_to_minus_inf, prop.lor(unpacked1.sign, unpacked2.sign), prop.land(unpacked1.sign, unpacked2.sign)); result.sign=prop.lselect( result.infinity, infinity_sign, prop.lselect(result.zero, zero_sign, add_sub_sign)); #else result.sign=prop.lselect( result.infinity, infinity_sign, add_sub_sign); #endif #if 0 result.sign=const_literal(false); result.fraction.resize(spec.f+1, const_literal(true)); result.exponent.resize(spec.e, const_literal(false)); result.NaN=const_literal(false); result.infinity=const_literal(false); //for(std::size_t i=0; i<result.fraction.size(); i++) // result.fraction[i]=const_literal(true); for(std::size_t i=0; i<result.fraction.size(); i++) result.fraction[i]=new_fraction2[i]; return pack(bias(result)); #endif return rounder(result); }
bvt float_utilst::conversion( const bvt &src, const ieee_float_spect &dest_spec) { assert(src.size()==spec.width()); #if 1 // Catch the special case in which we extend, // e.g. single to double. // In this case, rounding can be avoided, // but a denormal number may be come normal. // Be careful to exclude the difficult case // when denormalised numbers in the old format // can be converted to denormalised numbers in the // new format. Note that this is rare and will only // happen with very non-standard formats. int sourceSmallestNormalExponent = -((1 << (spec.e - 1)) - 1); int sourceSmallestDenormalExponent = sourceSmallestNormalExponent - spec.f; // Using the fact that f doesn't include the hidden bit int destSmallestNormalExponent = -((1 << (dest_spec.e - 1)) - 1); if(dest_spec.e>=spec.e && dest_spec.f>=spec.f && !(sourceSmallestDenormalExponent < destSmallestNormalExponent)) { unbiased_floatt unpacked_src=unpack(src); unbiased_floatt result; // the fraction gets zero-padded std::size_t padding=dest_spec.f-spec.f; result.fraction= bv_utils.concatenate(bv_utils.zeros(padding), unpacked_src.fraction); // the exponent gets sign-extended result.exponent= bv_utils.sign_extension(unpacked_src.exponent, dest_spec.e); // if the number was denormal and is normal in the new format, // normalise it! if(dest_spec.e > spec.e) { normalization_shift(result.fraction,result.exponent); } // the flags get copied result.sign=unpacked_src.sign; result.NaN=unpacked_src.NaN; result.infinity=unpacked_src.infinity; // no rounding needed! spec=dest_spec; return pack(bias(result)); } else #endif { // we actually need to round unbiased_floatt result=unpack(src); spec=dest_spec; return rounder(result); } }
void float_utilst::denormalization_shift(bvt &fraction, bvt &exponent) { mp_integer bias=spec.bias(); // Is the exponent strictly less than -bias+1, i.e., exponent<-bias+1? // This is transformed to distance=(-bias+1)-exponent // i.e., distance>0 // Note that 1-bias is the exponent represented by 0...01, // i.e. the exponent of the smallest normal number and thus the 'base' // exponent for subnormal numbers. assert(exponent.size()>=spec.e); #if 1 // Need to sign extend to avoid overflow. Note that this is a // relatively rare problem as the value needs to be close to the top // of the exponent range and then range must not have been // previously extended as add, multiply, etc. do. This is primarily // to handle casting down from larger ranges. exponent = bv_utils.sign_extension(exponent, exponent.size() + 1); #endif bvt distance=bv_utils.sub( bv_utils.build_constant(-bias+1, exponent.size()), exponent); // use sign bit literalt denormal=prop.land( !distance.back(), !bv_utils.is_zero(distance)); #if 1 // Care must be taken to not loose information required for the // guard and sticky bits. +3 is for the hidden, guard and sticky bits. if (fraction.size() < (spec.f + 3)) { // Add zeros at the LSB end for the guard bit to shift into fraction= bv_utils.concatenate(bv_utils.zeros((spec.f + 3) - fraction.size()), fraction); } bvt denormalisedFraction = fraction; literalt sticky_bit = const_literal(false); denormalisedFraction = sticky_right_shift(fraction, distance, sticky_bit); denormalisedFraction[0] = prop.lor(denormalisedFraction[0], sticky_bit); fraction= bv_utils.select( denormal, denormalisedFraction, fraction); #else fraction= bv_utils.select( denormal, bv_utils.shift(fraction, bv_utilst::LRIGHT, distance), fraction); #endif exponent= bv_utils.select(denormal, bv_utils.build_constant(-bias, exponent.size()), exponent); }
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 bv_utilst::set_equal(const bvt &a, const bvt &b) { assert(a.size()==b.size()); for(std::size_t i=0; i<a.size(); i++) prop.set_equal(a[i], b[i]); }
exprt boolbvt::bv_get(const bvt &bv, const typet &type) const { std::vector<bool> unknown; unknown.resize(bv.size(), false); return bv_get_rec(bv, unknown, 0, type); }
void boolbvt::convert_byte_update( const byte_update_exprt &expr, bvt &bv) { if(expr.operands().size()!=3) throw "byte_update takes three operands"; const exprt &op=expr.op0(); const exprt &offset_expr=expr.offset(); const exprt &value=expr.value(); bool little_endian; if(expr.id()==ID_byte_update_little_endian) little_endian=true; else if(expr.id()==ID_byte_update_big_endian) little_endian=false; else assert(false); bv=convert_bv(op); const bvt &value_bv=convert_bv(value); std::size_t update_width=value_bv.size(); std::size_t byte_width=8; if(update_width>bv.size()) update_width=bv.size(); // see if the byte number is constant mp_integer index; if(!to_integer(offset_expr, index)) { // yes! mp_integer offset=index*8; if(offset+update_width>mp_integer(bv.size()) || offset<0) { // out of bounds } else { if(little_endian) { for(std::size_t i=0; i<update_width; i++) bv[integer2long(offset+i)]=value_bv[i]; } else { endianness_mapt map_op(op.type(), false, ns); endianness_mapt map_value(value.type(), false, ns); std::size_t offset_i=integer2unsigned(offset); for(std::size_t i=0; i<update_width; i++) bv[map_op.map_bit(offset_i+i)]=value_bv[map_value.map_bit(i)]; } } return; } // byte_update with variable index for(std::size_t offset=0; offset<bv.size(); offset+=byte_width) { // index condition equal_exprt equality; equality.lhs()=offset_expr; equality.rhs()=from_integer(offset/byte_width, offset_expr.type()); literalt equal=convert(equality); endianness_mapt map_op(op.type(), little_endian, ns); endianness_mapt map_value(value.type(), little_endian, ns); for(std::size_t bit=0; bit<update_width; bit++) if(offset+bit<bv.size()) { std::size_t bv_o=map_op.map_bit(offset+bit); std::size_t value_bv_o=map_value.map_bit(bit); bv[bv_o]=prop.lselect(equal, value_bv[value_bv_o], bv[bv_o]); } } }
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 bv_refinementt::check_UNSAT(approximationt &a) { // part of the conflict? if(!is_in_conflict(a)) return; status() << "Found assumption for `" << a.as_string() << "' in proof (state " << a.under_state << ")" << eom; assert(!a.under_assumptions.empty()); a.under_assumptions.clear(); if(a.expr.type().id()==ID_floatbv) { const floatbv_typet &floatbv_type=to_floatbv_type(a.expr.type()); ieee_float_spect spec=floatbv_type; a.under_assumptions.reserve(a.op0_bv.size()+a.op1_bv.size()); float_utilst float_utils(prop); float_utils.spec=spec; // the fraction without hidden bit const bvt fraction0=float_utils.get_fraction(a.op0_bv); const bvt fraction1=float_utils.get_fraction(a.op1_bv); if(a.under_state==0) { // we first set sign and exponent free, // but keep the fraction zero for(unsigned i=0; i<fraction0.size(); i++) a.add_under_assumption(prop.lnot(fraction0[i])); for(unsigned i=0; i<fraction1.size(); i++) a.add_under_assumption(prop.lnot(fraction1[i])); } else { // now fraction: make this grow quadratically unsigned x=a.under_state*a.under_state; if(x>=MAX_FLOAT_UNDERAPPROX && x>=a.result_bv.size()) { // make it free altogether, this guarantees progress } else { // set x bits of both exponent and mantissa free // need to start with most-significant bits #if 0 for(unsigned i=x; i<fraction0.size(); i++) a.add_under_assumption(prop.lnot( fraction0[fraction0.size()-i-1])); for(unsigned i=x; i<fraction1.size(); i++) a.add_under_assumption(prop.lnot( fraction1[fraction1.size()-i-1])); #endif } } } else { unsigned x=a.under_state+1; if(x>=MAX_INTEGER_UNDERAPPROX && x>=a.result_bv.size()) { // make it free altogether, this guarantees progress } else { // set x least-significant bits free a.under_assumptions.reserve(a.op0_bv.size()+a.op1_bv.size()); for(unsigned i=x; i<a.op0_bv.size(); i++) a.add_under_assumption(prop.lnot(a.op0_bv[i])); for(unsigned i=x; i<a.op1_bv.size(); i++) a.add_under_assumption(prop.lnot(a.op1_bv[i])); } } a.under_state++; progress=true; }