exprt boolbvt::get(const exprt &expr) const { if(expr.id()==ID_symbol || expr.id()==ID_nondet_symbol) { const irep_idt &identifier=expr.get(ID_identifier); boolbv_mapt::mappingt::const_iterator it= map.mapping.find(identifier); if(it!=map.mapping.end()) { const boolbv_mapt::map_entryt &map_entry=it->second; if(is_unbounded_array(map_entry.type)) return bv_get_unbounded_array(identifier, to_array_type(map_entry.type)); std::vector<bool> unknown; bvt bv; unsigned width=map_entry.width; bv.resize(width); unknown.resize(width); for(unsigned bit_nr=0; bit_nr<width; bit_nr++) { assert(bit_nr<map_entry.literal_map.size()); if(map_entry.literal_map[bit_nr].is_set) { unknown[bit_nr]=false; bv[bit_nr]=map_entry.literal_map[bit_nr].l; } else { unknown[bit_nr]=true; bv[bit_nr].clear(); } } return bv_get_rec(bv, unknown, 0, map_entry.type); } } else if(expr.id()==ID_constant) return expr; else if(expr.id()==ID_infinity) return expr; return SUB::get(expr); }
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; }
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_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 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]); } } } }