void c_typecheck_baset::typecheck_c_bit_field_type(typet &type) { typecheck_type(type.subtype()); exprt &width_expr=static_cast<exprt &>(type.add(ID_size)); typecheck_expr(width_expr); make_constant_index(width_expr); mp_integer i; if(to_integer(width_expr, i)) { err_location(type); throw "failed to convert bit field width"; } if(i<0) { err_location(type); throw "bit field width is negative"; } const typet &base_type=follow(type.subtype()); if(base_type.id()==ID_bool) { if(i>1) { err_location(type); throw "bit field width too large"; } // We don't use bool, as it's really a byte long. type.id(ID_unsignedbv); type.set(ID_width, integer2long(i)); } else if(base_type.id()==ID_signedbv || base_type.id()==ID_unsignedbv || base_type.id()==ID_c_enum) { unsigned width=base_type.get_int(ID_width); if(i>width) { err_location(type); throw "bit field width too large"; } typet tmp(base_type); type.swap(tmp); type.set(ID_width, integer2string(i)); } else { err_location(type); str << "bit field with non-integer type: " << to_string(base_type); throw 0; } }
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 c_typecheck_baset::designator_enter( const typet &type, designatort &designator) { designatort::entryt entry; entry.type=type; assert(entry.type.id()!=ID_symbol); if(entry.type.id()==ID_struct) { entry.size=to_struct_type(entry.type).components().size(); if(entry.size!=0) entry.subtype=to_struct_type(entry.type).components().front().type(); else entry.subtype.make_nil(); } else if(entry.type.id()==ID_union) { if(to_union_type(entry.type).components().empty()) { entry.size=0; entry.subtype.make_nil(); } else { entry.size=1; entry.subtype=to_union_type(entry.type).components().front().type(); } } else if(entry.type.id()==ID_array) { mp_integer array_size; if(to_integer(to_array_type(entry.type).size(), array_size)) { err_location(to_array_type(entry.type).size()); str << "array has non-constant size `" << to_string(to_array_type(entry.type).size()) << "'"; throw 0; } entry.size=integer2long(array_size); entry.subtype=entry.type.subtype(); } else if(entry.type.id()==ID_incomplete_array) { entry.size=0; entry.subtype=entry.type.subtype(); } else assert(false); designator.push_entry(entry); }
int configt::ansi_ct::from_ns(const namespacet &ns, const std::string &what) { const irep_idt id="c::__CPROVER_architecture_"+what; const symbolt *symbol; if(ns.lookup(id, symbol)) throw "failed to find "+id2string(id); exprt tmp=symbol->value; simplify(tmp, ns); mp_integer int_value; if(to_integer(tmp, int_value)) throw "failed to convert "+id2string(id); return integer2long(int_value); }
bool string_constantt::from_array_expr(const array_exprt &src) { id(ID_string_constant); type()=src.type(); const typet &subtype=type().subtype(); // check subtype if(subtype!=signed_char_type() && subtype!=unsigned_char_type()) return true; std::string value; forall_operands(it, src) { mp_integer int_value=0; if(to_integer(*it, int_value)) return true; long long_value=integer2long(int_value); value+=(char)long_value; }
void rd_range_domaint::assign_byte_extract( const namespacet &ns, locationt from, const byte_extract_exprt &be, const mp_integer &size) { assert(size==1); mp_integer op_offset=compute_pointer_offset(ns, be.op()); mp_integer index; if(op_offset==-1 || to_integer(be.offset(), index)) assign(ns, from, be.op(), -1, 1); else { endianness_mapt map( be.op().type(), be.id()==ID_byte_extract_little_endian, ns); assert(index<std::numeric_limits<unsigned>::max()); op_offset+=map.map_byte(integer2long(index)); assign(ns, from, be.op(), op_offset, 1); } }
void add_padding(struct_typet &type, const namespacet &ns) { struct_typet::componentst &components=type.components(); // first do padding for bit-fields { unsigned padding_counter=0; unsigned bit_field_bits=0; for(struct_typet::componentst::iterator it=components.begin(); it!=components.end(); it++) { if(it->get_is_bit_field()) { // count the bits bit_field_bits+=it->type().get_int(ID_width); } else if(bit_field_bits!=0) { // not on a byte-boundary? if((bit_field_bits%8)!=0) { unsigned pad=8-bit_field_bits%8; unsignedbv_typet padding_type; padding_type.set_width(pad); struct_typet::componentt component; component.type()=padding_type; component.set_name("$bit_field_pad"+i2string(padding_counter++)); component.set_is_padding(true); component.set_is_bit_field(true); it=components.insert(it, component); it++; // skip over bit_field_bits+=pad; } bit_field_bits=0; } } // Add padding at the end? if((bit_field_bits%8)!=0) { unsigned pad=8-bit_field_bits%8; unsignedbv_typet padding_type; padding_type.set_width(pad); struct_typet::componentt component; component.type()=padding_type; component.set_name("$bit_field_pad"+i2string(padding_counter++)); component.set_is_padding(true); component.set_is_bit_field(true); components.push_back(component); } } // packed? if(type.get_bool(ID_packed)) return; // done mp_integer offset=0; unsigned padding_counter=0; unsigned max_alignment=0; unsigned bit_field_bits=0; for(struct_typet::componentst::iterator it=components.begin(); it!=components.end(); it++) { // ANSI-C says that bit-fields do not get padded! if(it->get_is_bit_field()) { // count the bits bit_field_bits+=it->type().get_int(ID_width); // we consider the type for max_alignment, however unsigned a=alignment(it->get_bit_field_type(), ns); if(max_alignment<a) max_alignment=a; continue; } else if(bit_field_bits!=0) { // these are now assumed to be multiples of 8 offset+=bit_field_bits/8; bit_field_bits=0; } const typet &it_type=it->type(); unsigned a=alignment(it_type, ns); // check minimum alignment if(a<config.ansi_c.alignment) a=config.ansi_c.alignment; if(max_alignment<a) max_alignment=a; if(a!=1) { // we may need to align it unsigned displacement=integer2long(offset%a); if(displacement!=0) { unsigned pad=a-displacement; unsignedbv_typet padding_type; padding_type.set_width(pad*8); struct_typet::componentt component; component.type()=padding_type; component.set_name("$pad"+i2string(padding_counter++)); component.set_is_padding(true); it=components.insert(it, component); it++; // skip over offset+=pad; } } mp_integer size=pointer_offset_size(ns, it_type); if(size!=-1) offset+=size; } if(bit_field_bits!=0) { // these are now assumed to be multiples of 8 offset+=bit_field_bits/8; } // There may be a need for 'end of struct' padding. // We use 'max_alignment'. if(max_alignment>1) { // we may need to align it unsigned displacement=integer2long(offset%max_alignment); if(displacement!=0) { unsigned pad=max_alignment-displacement; unsignedbv_typet padding_type; padding_type.set_width(pad*8); struct_typet::componentst::iterator it; // we need to insert before any 'flexible member' if(!components.empty() && components.back().type().id()==ID_array && to_array_type(components.back().type()).size().is_zero()) { it=components.end(); it--; } else it=components.end(); struct_typet::componentt component; component.type()=padding_type; component.set_name("$pad"+i2string(padding_counter++)); component.set_is_padding(true); components.insert(it, component); } } }
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"; }
exprt boolbvt::bv_get_unbounded_array( const irep_idt &identifier, const array_typet &type) const { // first, try to get size const exprt &size_expr=type.size(); exprt size=get(size_expr); // no size, give up if(size.is_nil()) return nil_exprt(); // get the numeric value, unless it's infinity mp_integer size_mpint; if(size.id()!=ID_infinity) { if(to_integer(size, size_mpint)) return nil_exprt(); // simple sanity check if(size_mpint<0) return nil_exprt(); } else size_mpint=0; // search array indices typedef std::map<mp_integer, exprt> valuest; valuest values; { unsigned number; symbol_exprt array_expr; array_expr.type()=type; array_expr.set_identifier(identifier); if(arrays.get_number(array_expr, number)) return nil_exprt(); // get root number=arrays.find_number(number); assert(number<index_map.size()); const index_sett &index_set=index_map[number]; for(index_sett::const_iterator it1= index_set.begin(); it1!=index_set.end(); it1++) { index_exprt index; index.type()=type.subtype(); index.array()=array_expr; index.index()=*it1; exprt value=bv_get_cache(index); exprt index_value=bv_get_cache(*it1); if(!index_value.is_nil()) { mp_integer index_mpint; if(!to_integer(index_value, index_mpint)) { if(value.is_nil()) values[index_mpint]=exprt(ID_unknown, type.subtype()); else values[index_mpint]=value; } } } } exprt result; if(size_mpint>100 || size.id()==ID_infinity) { result=exprt("array-list", type); result.type().set(ID_size, integer2string(size_mpint)); result.operands().reserve(values.size()*2); for(valuest::const_iterator it=values.begin(); it!=values.end(); it++) { exprt index=from_integer(it->first, size.type()); result.copy_to_operands(index, it->second); } } else { // set the size result=exprt(ID_array, type); result.type().set(ID_size, size); unsigned long size_int=integer2long(size_mpint); // allocate operands result.operands().resize(size_int); for(unsigned i=0; i<size_int; i++) result.operands()[i]=exprt(ID_unknown); // search uninterpreted functions for(valuest::iterator it=values.begin(); it!=values.end(); it++) if(it->first>=0 && it->first<size_mpint) result.operands()[integer2long(it->first)].swap(it->second); } return result; }
void interpretert::execute_function_call() { const code_function_callt &function_call= to_code_function_call(PC->code); // function to be called mp_integer a=evaluate_address(function_call.function()); if(a==0) throw "function call to NULL"; else if(a>=memory.size()) throw "out-of-range function call"; const memory_cellt &cell=memory[integer2long(a)]; const irep_idt &identifier=cell.identifier; const goto_functionst::function_mapt::const_iterator f_it= goto_functions.function_map.find(identifier); if(f_it==goto_functions.function_map.end()) throw "failed to find function "+id2string(identifier); // return value mp_integer return_value_address; if(function_call.lhs().is_not_nil()) return_value_address= evaluate_address(function_call.lhs()); else return_value_address=0; // values of the arguments std::vector<std::vector<mp_integer> > argument_values; argument_values.resize(function_call.arguments().size()); for(std::size_t i=0; i<function_call.arguments().size(); i++) evaluate(function_call.arguments()[i], argument_values[i]); // do the call if(f_it->second.body_available) { call_stack.push(stack_framet()); stack_framet &frame=call_stack.top(); frame.return_PC=next_PC; frame.return_function=function; frame.old_stack_pointer=stack_pointer; frame.return_value_address=return_value_address; // local variables std::set<irep_idt> locals; get_local_identifiers(f_it->second, locals); for(std::set<irep_idt>::const_iterator it=locals.begin(); it!=locals.end(); it++) { const irep_idt &id=*it; const symbolt &symbol=ns.lookup(id); unsigned size=get_size(symbol.type); if(size!=0) { frame.local_map[id]=stack_pointer; for(unsigned i=0; i<stack_pointer; i++) { unsigned address=stack_pointer+i; if(address>=memory.size()) memory.resize(address+1); memory[address].value=0; memory[address].identifier=id; memory[address].offset=i; } stack_pointer+=size; } } // assign the arguments const code_typet::parameterst ¶meters= to_code_type(f_it->second.type).parameters(); if(argument_values.size()<parameters.size()) throw "not enough arguments"; for(unsigned i=0; i<parameters.size(); i++) { const code_typet::parametert &a=parameters[i]; exprt symbol_expr(ID_symbol, a.type()); symbol_expr.set(ID_identifier, a.get_identifier()); assert(i<argument_values.size()); assign(evaluate_address(symbol_expr), argument_values[i]); } // set up new PC function=f_it; next_PC=f_it->second.body.instructions.begin(); } else throw "no body for "+id2string(identifier); }
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]); } } }
designatort c_typecheck_baset::make_designator( const typet &src_type, const exprt &src) { assert(!src.operands().empty()); typet type=follow(src_type); designatort designator; forall_operands(it, src) { const exprt &d_op=*it; designatort::entryt entry; entry.type=type; assert(type.id()!=ID_symbol); if(type.id()==ID_array || type.id()==ID_incomplete_array) { if(d_op.id()!=ID_index) { err_location(d_op); throw "expected array index designator"; } assert(d_op.operands().size()==1); exprt tmp_index=d_op.op0(); make_constant_index(tmp_index); mp_integer index, size; if(to_integer(tmp_index, index)) { err_location(d_op.op0()); throw "expected constant array index designator"; } if(type.id()==ID_incomplete_array) size=0; else if(to_integer(to_array_type(type).size(), size)) { err_location(d_op.op0()); throw "expected constant array size"; } entry.index=integer2long(index); entry.size=integer2long(size); entry.subtype=follow(type.subtype()); } else if(type.id()==ID_struct || type.id()==ID_union) { const struct_union_typet &struct_union_type=to_struct_union_type(type); if(d_op.id()!=ID_member) { err_location(d_op); throw "expected member designator"; } const irep_idt &component_name=d_op.get(ID_component_name); if(struct_union_type.has_component(component_name)) { // a direct member entry.index=struct_union_type.component_number(component_name); entry.size=struct_union_type.components().size(); entry.subtype=follow(struct_union_type.components()[entry.index].type()); } else { // We will search for anonymous members, // in a loop. This isn't supported by gcc, but icc does allow it. bool found=false, repeat; struct_union_typet tmp_type=struct_union_type; do { repeat=false; unsigned number=0; const struct_union_typet::componentst &components= tmp_type.components(); for(struct_union_typet::componentst::const_iterator c_it=components.begin(); c_it!=components.end(); c_it++, number++) { if(c_it->get_name()==component_name) { // done! entry.index=number; entry.size=components.size(); entry.subtype=follow(components[entry.index].type()); entry.type=tmp_type; } else if(c_it->get_anonymous() && has_component_rec( c_it->type(), component_name, *this)) { entry.index=number; entry.size=components.size(); entry.subtype=follow(c_it->type()); entry.type=tmp_type; tmp_type=to_struct_union_type(entry.subtype); designator.push_entry(entry); found=repeat=true; break; } } } while(repeat); if(!found) { err_location(d_op); str << "failed to find struct component `" << component_name << "' in initialization of `" << to_string(struct_union_type) << "'"; throw 0; } } } else { err_location(d_op); str << "designated initializers cannot initialize `" << to_string(type) << "'"; throw 0; } type=entry.subtype; designator.push_entry(entry); } assert(!designator.empty()); return designator; }
void ansi_c_convert_typet::read_rec(const typet &type) { if(type.id()==ID_merged_type) { forall_subtypes(it, type) read_rec(*it); } else if(type.id()==ID_signed) signed_cnt++; else if(type.id()==ID_unsigned) unsigned_cnt++; else if(type.id()==ID_ptr32) c_qualifiers.is_ptr32=true; else if(type.id()==ID_ptr64) c_qualifiers.is_ptr64=true; else if(type.id()==ID_volatile) c_qualifiers.is_volatile=true; else if(type.id()==ID_asm) { // ignore for now } else if(type.id()==ID_const) c_qualifiers.is_constant=true; else if(type.id()==ID_restricted) c_qualifiers.is_restricted=true; else if(type.id()==ID_char) char_cnt++; else if(type.id()==ID_int) int_cnt++; else if(type.id()==ID_int8) int8_cnt++; else if(type.id()==ID_int16) int16_cnt++; else if(type.id()==ID_int32) int32_cnt++; else if(type.id()==ID_int64) int64_cnt++; else if(type.id()==ID_gcc_float128) gcc_float128_cnt++; else if(type.id()==ID_gcc_int128) gcc_int128_cnt++; else if(type.id()==ID_gcc_attribute_mode) { const exprt &size_expr= static_cast<const exprt &>(type.find(ID_size)); if(size_expr.id()=="__QI__") gcc_mode_QI=true; else if(size_expr.id()=="__HI__") gcc_mode_HI=true; else if(size_expr.id()=="__SI__") gcc_mode_SI=true; else if(size_expr.id()=="__DI__") gcc_mode_DI=true; else { // we ignore without whining } } else if(type.id()==ID_bv) { bv_cnt++; const exprt &size_expr= static_cast<const exprt &>(type.find(ID_size)); mp_integer size_int; if(to_integer(size_expr, size_int)) { err_location(location); error("bit vector width has to be constant"); throw 0; } if(size_int<1 || size_int>1024) { err_location(location); error("bit vector width invalid"); throw 0; } bv_width=integer2long(size_int); } else if(type.id()==ID_short) short_cnt++; else if(type.id()==ID_long) long_cnt++; else if(type.id()==ID_double) double_cnt++; else if(type.id()==ID_float) float_cnt++; else if(type.id()==ID_bool) c_bool_cnt++; else if(type.id()==ID_proper_bool) proper_bool_cnt++; else if(type.id()==ID_complex) complex_cnt++; else if(type.id()==ID_static) c_storage_spec.is_static=true; else if(type.id()==ID_thread_local) c_storage_spec.is_thread_local=true; else if(type.id()==ID_inline) c_storage_spec.is_inline=true; else if(type.id()==ID_extern) c_storage_spec.is_extern=true; else if(type.id()==ID_typedef) c_storage_spec.is_typedef=true; else if(type.id()==ID_register) c_storage_spec.is_register=true; else if(type.id()==ID_auto) { // ignore } else if(type.id()==ID_packed) packed=true; else if(type.id()==ID_aligned) { aligned=true; // may come with size or not if(type.find(ID_size).is_nil()) alignment=exprt(ID_default); else alignment=static_cast<const exprt &>(type.find(ID_size)); } else if(type.id()==ID_transparent_union) { c_qualifiers.is_transparent_union=true; } else if(type.id()==ID_vector) vector_size=to_vector_type(type).size(); else if(type.id()==ID_void) { // we store 'void' as 'empty' typet tmp=type; tmp.id(ID_empty); other.push_back(tmp); } else other.push_back(type); }
exprt flatten_byte_update( const exprt &src, const namespacet &ns) { assert(src.id()==ID_byte_update_little_endian || src.id()==ID_byte_update_big_endian); assert(src.operands().size()==3); mp_integer element_size= pointer_offset_size(ns, src.op2().type()); const typet &t=ns.follow(src.op0().type()); if(t.id()==ID_array) { const array_typet &array_type=to_array_type(t); const typet &subtype=array_type.subtype(); // array of bitvectors? if(subtype.id()==ID_unsignedbv || subtype.id()==ID_signedbv || subtype.id()==ID_floatbv) { mp_integer sub_size=pointer_offset_size(ns, subtype); if(sub_size==-1) throw "can't flatten byte_update for sub-type without size"; // byte array? if(sub_size==1) { // apply 'array-update-with' element_size times exprt result=src.op0(); for(mp_integer i=0; i<element_size; ++i) { exprt i_expr=from_integer(i, ns.follow(src.op1().type())); exprt new_value; if(i==0 && element_size==1) // bytes? { new_value=src.op2(); if(new_value.type()!=subtype) new_value.make_typecast(subtype); } else { exprt byte_extract_expr( src.id()==ID_byte_update_little_endian?ID_byte_extract_little_endian: src.id()==ID_byte_update_big_endian?ID_byte_extract_big_endian: throw "unexpected src.id()", subtype); byte_extract_expr.copy_to_operands(src.op2(), i_expr); new_value=flatten_byte_extract(byte_extract_expr, ns); } exprt where=plus_exprt(src.op1(), i_expr); with_exprt with_expr; with_expr.type()=src.type(); with_expr.old()=result; with_expr.where()=where; with_expr.new_value()=new_value; result.swap(with_expr); } return result; } else // sub_size!=1 { if(element_size==1) // byte-granularity update { div_exprt div_offset(src.op1(), from_integer(sub_size, src.op1().type())); mod_exprt mod_offset(src.op1(), from_integer(sub_size, src.op1().type())); index_exprt index_expr(src.op0(), div_offset, array_type.subtype()); exprt byte_update_expr(src.id(), array_type.subtype()); byte_update_expr.copy_to_operands(index_expr, mod_offset, src.op2()); // Call recurisvely, the array is gone! exprt flattened_byte_update_expr= flatten_byte_update(byte_update_expr, ns); with_exprt with_expr( src.op0(), div_offset, flattened_byte_update_expr); return with_expr; } else throw "flatten_byte_update can only do byte updates of non-byte arrays right now"; } } else { throw "flatten_byte_update can only do arrays of scalars right now"; } } else if(t.id()==ID_signedbv || t.id()==ID_unsignedbv || t.id()==ID_floatbv) { // do a shift, mask and OR unsigned width=to_bitvector_type(t).get_width(); if(element_size*8>width) throw "flatten_byte_update to update element that is too large"; // build mask exprt mask= bitnot_exprt( from_integer(power(2, element_size*8)-1, unsignedbv_typet(width))); const typet &offset_type=ns.follow(src.op1().type()); mult_exprt offset_times_eight(src.op1(), from_integer(8, offset_type)); // shift the mask shl_exprt shl_expr(mask, offset_times_eight); // do the 'AND' bitand_exprt bitand_expr(src.op0(), mask); // zero-extend the value concatenation_exprt value_extended( from_integer(0, unsignedbv_typet(width-integer2long(element_size)*8)), src.op2(), t); // shift the value shl_exprt value_shifted(value_extended, offset_times_eight); // do the 'OR' bitor_exprt bitor_expr(bitand_expr, value_shifted); return bitor_expr; } else { throw "flatten_byte_update can only do array and scalars right now"; } }
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]); } } } }
exprt c_typecheck_baset::zero_initializer( const typet &type, const locationt &location) { const irep_idt &type_id=type.id(); if(type_id==ID_bool) { exprt result=false_exprt(); result.location()=location; return result; } else if(type_id==ID_unsignedbv || type_id==ID_signedbv || type_id==ID_floatbv || type_id==ID_fixedbv || type_id==ID_pointer) { exprt result=gen_zero(type); result.location()=location; return result; } else if(type_id==ID_code) { err_location(location); throw "cannot zero-initialize code-type"; } else if(type_id==ID_c_enum || type_id==ID_incomplete_c_enum) { constant_exprt value(type); value.set_value(ID_0); value.location()=location; return value; } else if(type_id==ID_array) { const array_typet &array_type=to_array_type(type); exprt tmpval=zero_initializer(array_type.subtype(), location); mp_integer array_size; if(array_type.size().id()==ID_infinity) { exprt value(ID_array_of, type); value.copy_to_operands(tmpval); value.location()=location; return value; } else if(to_integer(array_type.size(), array_size)) { err_location(location); str << "failed to zero-initialize array of non-fixed size `" << to_string(array_type.size()) << "'"; throw 0; } if(array_size<0) { err_location(location); throw "failed to zero-initialize array of with negative size"; } exprt value(ID_array, type); value.operands().resize(integer2long(array_size), tmpval); value.location()=location; return value; } else if(type_id==ID_incomplete_array) { // we initialize this with an empty array exprt value(ID_array, type); value.type().id(ID_array); value.type().set(ID_size, gen_zero(size_type())); value.location()=location; return value; } else if(type_id==ID_struct) { const struct_typet::componentst &components= to_struct_type(type).components(); exprt value(ID_struct, type); value.operands().reserve(components.size()); for(struct_typet::componentst::const_iterator it=components.begin(); it!=components.end(); it++) value.copy_to_operands(zero_initializer(it->type(), location)); value.location()=location; return value; } else if(type_id==ID_union) { const union_typet::componentst &components= to_union_type(type).components(); exprt value(ID_union, type); if(components.empty()) return value; // stupid empty union value.set(ID_component_name, components.front().get(ID_name)); value.copy_to_operands( zero_initializer(components.front().type(), location)); value.location()=location; return value; } else if(type_id==ID_symbol) return zero_initializer(follow(type), location); else { err_location(location); str << "Failed to zero-initialize `" << to_string(type) << "'"; throw 0; } }
exprt c_typecheck_baset::do_initializer_rec( const exprt &value, const typet &type, bool force_constant) { const typet &full_type=follow(type); if(full_type.id()==ID_incomplete_struct) { err_location(value); str << "type `" << to_string(full_type) << "' is still incomplete -- cannot initialize"; throw 0; } if(value.id()==ID_initializer_list) return do_initializer_list(value, full_type, force_constant); if(value.id()==ID_array && value.get_bool(ID_C_string_constant) && (full_type.id()==ID_array || full_type.id()==ID_incomplete_array) && (full_type.subtype().id()==ID_signedbv || full_type.subtype().id()==ID_unsignedbv) && full_type.subtype().get(ID_width)==value.type().subtype().get(ID_width)) { exprt tmp=value; // adjust char type tmp.type().subtype()=full_type.subtype(); Forall_operands(it, tmp) it->type()=full_type.subtype(); if(full_type.id()==ID_array) { // check size mp_integer array_size; if(to_integer(to_array_type(full_type).size(), array_size)) { err_location(value); throw "array size needs to be constant"; } if(array_size<0) { err_location(value); throw "array size must not be negative"; } if(mp_integer(tmp.operands().size())>array_size) { // cut off long strings. gcc does a warning for this tmp.operands().resize(integer2long(array_size)); tmp.type()=full_type; } else if(mp_integer(tmp.operands().size())<array_size) { // fill up tmp.type()=full_type; tmp.operands().resize(integer2long(array_size), gen_zero(full_type.subtype())); } } return tmp; } if(value.id()==ID_string_constant && (full_type.id()==ID_array || full_type.id()==ID_incomplete_array) && (full_type.subtype().id()==ID_signedbv || full_type.subtype().id()==ID_unsignedbv) && full_type.subtype().get(ID_width)==char_type().get(ID_width)) { // will go away, to be replaced by the above block string_constantt tmp1=to_string_constant(value); // adjust char type tmp1.type().subtype()=full_type.subtype(); exprt tmp2=tmp1.to_array_expr(); if(full_type.id()==ID_array) { // check size mp_integer array_size; if(to_integer(to_array_type(full_type).size(), array_size)) { err_location(value); throw "array size needs to be constant"; } if(array_size<0) { err_location(value); throw "array size must not be negative"; } if(mp_integer(tmp2.operands().size())>array_size) { // cut off long strings. gcc does a warning for this tmp2.operands().resize(integer2long(array_size)); tmp2.type()=full_type; } else if(mp_integer(tmp2.operands().size())<array_size) { // fill up tmp2.type()=full_type; tmp2.operands().resize(integer2long(array_size), gen_zero(full_type.subtype())); } } return tmp2; } if(full_type.id()==ID_incomplete_array) { err_location(value); str << "type `" << to_string(full_type) << "' cannot be initialized with `" << to_string(value) << "'"; throw 0; } if(value.id()==ID_designated_initializer) { err_location(value); str << "type `" << to_string(full_type) << "' cannot be initialized with designated initializer"; throw 0; } exprt result=value; implicit_typecast(result, type); return result; }
std::string ieee_floatt::format(const format_spect &format_spec) const { std::string result; if(sign) result+="-"; if((NaN || infinity) && !sign) result+="+"; // special cases if(NaN) result+="NaN"; else if(infinity) result+="inf"; else if(is_zero()) { result+="0"; // add zeros, if needed if(format_spec.precision>0) { result+='.'; for(unsigned i=0; i<format_spec.precision; i++) result+='0'; } } else { mp_integer _exponent, _fraction; extract(_fraction, _exponent); // convert to base 10 if(_exponent>=0) { result+=integer2string(_fraction*power(2, _exponent)); // add zeros, if needed if(format_spec.precision>0) { result+='.'; for(unsigned i=0; i<format_spec.precision; i++) result+='0'; } } else { #if 1 mp_integer position=-_exponent; // 10/2=5 -- this makes it base 10 _fraction*=power(5, position); // apply rounding if(position>format_spec.precision) { mp_integer r=power(10, position-format_spec.precision); mp_integer remainder=_fraction%r; _fraction/=r; // not sure if this is the right kind of rounding here if(remainder>=r/2) ++_fraction; position=format_spec.precision; } std::string tmp=integer2string(_fraction); // pad with zeros from the front, if needed while(mp_integer(tmp.size())<=position) tmp="0"+tmp; unsigned dot=tmp.size()-integer2long(position); result+=std::string(tmp, 0, dot)+'.'; result+=std::string(tmp, dot, std::string::npos); // append zeros if needed for(mp_integer i=position; i<format_spec.precision; ++i) result+='0'; #else result+=integer2string(_fraction); if(_exponent!=0) result+="*2^"+integer2string(_exponent); #endif } } while(result.size()<format_spec.min_width) result=" "+result; return result; }
bool simplify_exprt::simplify_floatbv_op(exprt &expr) { const typet &type=ns.follow(expr.type()); if(type.id()!=ID_floatbv) return true; assert(expr.operands().size()==3); exprt op0=expr.op0(); exprt op1=expr.op1(); exprt op2=expr.op2(); // rounding mode assert(ns.follow(op0.type())==type); assert(ns.follow(op1.type())==type); // Remember that floating-point addition is _NOT_ associative. // Thus, we don't re-sort the operands. // We only merge constants! if(op0.is_constant() && op1.is_constant() && op2.is_constant()) { ieee_floatt v0(to_constant_expr(op0)); ieee_floatt v1(to_constant_expr(op1)); mp_integer rounding_mode; if(!to_integer(op2, rounding_mode)) { v0.rounding_mode=(ieee_floatt::rounding_modet)integer2long(rounding_mode); v1.rounding_mode=v0.rounding_mode; ieee_floatt result=v0; if(expr.id()==ID_floatbv_plus) result+=v1; else if(expr.id()==ID_floatbv_minus) result-=v1; else if(expr.id()==ID_floatbv_mult) result*=v1; else if(expr.id()==ID_floatbv_div) result/=v1; else assert(false); expr=result.to_expr(); return false; } } // division by one? Exact for all rounding modes. if (expr.id()==ID_floatbv_div && op1.is_constant() && op1.is_one()) { exprt tmp; tmp.swap(op0); expr.swap(tmp); return false; } return true; }
bool simplify_exprt::simplify_floatbv_typecast(exprt &expr) { // These casts usually reduce precision, and thus, usually round. assert(expr.operands().size()==2); const typet &dest_type=ns.follow(expr.type()); const typet &src_type=ns.follow(expr.op0().type()); // eliminate redundant casts if(dest_type==src_type) { expr=expr.op0(); return false; } exprt op0=expr.op0(); exprt op1=expr.op1(); // rounding mode // We can soundly re-write (float)((double)x op (double)y) // to x op y. True for any rounding mode! #if 0 if(op0.id()==ID_floatbv_div || op0.id()==ID_floatbv_mult || op0.id()==ID_floatbv_plus || op0.id()==ID_floatbv_minus) { if(op0.operands().size()==3 && op0.op0().id()==ID_typecast && op0.op1().id()==ID_typecast && op0.op0().operands().size()==1 && op0.op1().operands().size()==1 && ns.follow(op0.op0().type())==dest_type && ns.follow(op0.op1().type())==dest_type) { exprt result(op0.id(), expr.type()); result.operands().resize(3); result.op0()=op0.op0().op0(); result.op1()=op0.op1().op0(); result.op2()=op1; simplify_node(result); expr.swap(result); return false; } } #endif // constant folding if(op0.is_constant() && op1.is_constant()) { mp_integer rounding_mode; if(!to_integer(op1, rounding_mode)) { if(src_type.id()==ID_floatbv) { if(dest_type.id()==ID_floatbv) // float to float { ieee_floatt result(to_constant_expr(op0)); result.rounding_mode=(ieee_floatt::rounding_modet)integer2long(rounding_mode); result.change_spec(to_floatbv_type(dest_type)); expr=result.to_expr(); return false; } else if(dest_type.id()==ID_signedbv || dest_type.id()==ID_unsignedbv) { if(rounding_mode==ieee_floatt::ROUND_TO_ZERO) { ieee_floatt result(to_constant_expr(op0)); result.rounding_mode=(ieee_floatt::rounding_modet)integer2long(rounding_mode); mp_integer value=result.to_integer(); expr=from_integer(value, dest_type); return false; } } } else if(src_type.id()==ID_signedbv || src_type.id()==ID_unsignedbv) { mp_integer value; if(!to_integer(op0, value)) { if(dest_type.id()==ID_floatbv) // int to float { ieee_floatt result; result.rounding_mode=(ieee_floatt::rounding_modet)integer2long(rounding_mode); result.spec=to_floatbv_type(dest_type); result.from_integer(value); expr=result.to_expr(); return false; } } } } } #if 0 // (T)(a?b:c) --> a?(T)b:(T)c if(expr.op0().id()==ID_if && expr.op0().operands().size()==3) { exprt tmp_op1=binary_exprt(expr.op0().op1(), ID_floatbv_typecast, expr.op1(), dest_type); exprt tmp_op2=binary_exprt(expr.op0().op2(), ID_floatbv_typecast, expr.op1(), dest_type); simplify_floatbv_typecast(tmp_op1); simplify_floatbv_typecast(tmp_op2); expr=if_exprt(expr.op0().op0(), tmp_op1, tmp_op2, dest_type); simplify_if(expr); return false; } #endif return true; }
exprt flatten_byte_extract( const exprt &src, const namespacet &ns) { assert(src.id()==ID_byte_extract_little_endian || src.id()==ID_byte_extract_big_endian); assert(src.operands().size()==2); bool little_endian; if(src.id()==ID_byte_extract_little_endian) little_endian=true; else if(src.id()==ID_byte_extract_big_endian) little_endian=false; else assert(false); if(src.id()==ID_byte_extract_big_endian) throw "byte_extract flattening of big endian not done yet"; unsigned width= integer2long(pointer_offset_size(ns, src.type())); const typet &t=src.op0().type(); if(t.id()==ID_array) { const array_typet &array_type=to_array_type(t); const typet &subtype=array_type.subtype(); // byte-array? if((subtype.id()==ID_unsignedbv || subtype.id()==ID_signedbv) && subtype.get_int(ID_width)==8) { // get 'width'-many bytes, and concatenate exprt::operandst op; op.resize(width); for(unsigned i=0; i<width; i++) { // the most significant byte comes first in the concatenation! unsigned offset_i= little_endian?(width-i-1):i; plus_exprt offset(from_integer(offset_i, src.op1().type()), src.op1()); index_exprt index_expr(subtype); index_expr.array()=src.op0(); index_expr.index()=offset; op[i]=index_expr; } if(width==1) return op[0]; else // width>=2 { concatenation_exprt concatenation(src.type()); concatenation.operands().swap(op); return concatenation; } } else // non-byte array { const exprt &root=src.op0(); const exprt &offset=src.op1(); const typet &array_type=ns.follow(root.type()); const typet &offset_type=ns.follow(offset.type()); const typet &element_type=ns.follow(array_type.subtype()); mp_integer element_width=pointer_offset_size(ns, element_type); if(element_width==-1) // failed throw "failed to flatten non-byte array with unknown element width"; mp_integer result_width=pointer_offset_size(ns, src.type()); mp_integer num_elements=(element_width+result_width-2)/element_width+1; // compute new root and offset concatenation_exprt concat( unsignedbv_typet(integer2long(element_width*8*num_elements))); exprt first_index= (element_width==1)?offset : div_exprt(offset, from_integer(element_width, offset_type)); // 8*offset/el_w for(mp_integer i=num_elements; i>0; --i) { plus_exprt index(first_index, from_integer(i-1, offset_type)); concat.copy_to_operands(index_exprt(root, index)); } // the new offset is width%offset exprt new_offset= (element_width==1)?from_integer(0, offset_type): mod_exprt(offset, from_integer(element_width, offset_type)); // build new byte-extract expression exprt tmp(src.id(), src.type()); tmp.copy_to_operands(concat, new_offset); return tmp; } } else // non-array { // We turn that into logical right shift and extractbits const exprt &offset=src.op1(); const typet &offset_type=ns.follow(offset.type()); mult_exprt times_eight(offset, from_integer(8, offset_type)); lshr_exprt left_shift(src.op0(), times_eight); extractbits_exprt extractbits; extractbits.src()=left_shift; extractbits.type()=src.type(); extractbits.upper()=from_integer(width*8-1, offset_type); extractbits.lower()=from_integer(0, offset_type); return extractbits; } }
void c_typecheck_baset::do_designated_initializer( exprt &result, designatort &designator, const exprt &value, bool force_constant) { assert(!designator.empty()); if(value.id()==ID_designated_initializer) { assert(value.operands().size()==1); designator= make_designator( designator.front().type, static_cast<const exprt &>(value.find(ID_designator))); assert(!designator.empty()); return do_designated_initializer( result, designator, value.op0(), force_constant); } exprt *dest=&result; // first phase: follow given designator for(unsigned i=0; i<designator.size(); i++) { unsigned index=designator[i].index; const typet &type=designator[i].type; assert(type.id()!=ID_symbol); if(type.id()==ID_array || type.id()==ID_struct || type.id()==ID_incomplete_array) { if(index>=dest->operands().size()) { if(type.id()==ID_incomplete_array) { exprt zero=zero_initializer(type.subtype(), value.location()); dest->operands().resize(integer2long(index)+1, zero); } else { err_location(value); str << "index designator " << index << " out of bounds (" << dest->operands().size() << ")"; throw 0; } } dest=&(dest->operands()[integer2long(index)]); } else if(type.id()==ID_union) { // union initialization is quite special const union_typet &union_type=to_union_type(type); const union_typet::componentt &component=union_type.components()[index]; // build a union expression from the argument exprt union_expr(ID_union, type); union_expr.operands().resize(1); union_expr.op0()=zero_initializer(component.type(), value.location()); union_expr.location()=value.location(); union_expr.set(ID_component_name, component.get_name()); *dest=union_expr; dest=&(dest->op0()); } else assert(false); } // second phase: assign value // for this, we may need to go down, adding to the designator while(true) { // see what type we have to initialize typet type=follow(designator.back().subtype); assert(type.id()!=ID_symbol); // do we initialize a scalar? if(type.id()!=ID_struct && type.id()!=ID_union && type.id()!=ID_array && type.id()!=ID_incomplete_array) { // The initializer for a scalar shall be a single expression, // * optionally enclosed in braces. * if(value.id()==ID_initializer_list && value.operands().size()==1) *dest=do_initializer_rec(value.op0(), type, force_constant); else *dest=do_initializer_rec(value, type, force_constant); assert(type==follow(dest->type())); return; // done } // see what initializer we are given if(value.id()==ID_initializer_list) { *dest=do_initializer_rec(value, type, force_constant); return; // done } else if(value.id()==ID_string_constant) { // We stop for initializers that are string-constants, // which are like arrays. We only do so if we are to // initialize an array of scalars. if((type.id()==ID_array || type.id()==ID_incomplete_array) && (follow(type.subtype()).id()==ID_signedbv || follow(type.subtype()).id()==ID_unsignedbv)) { *dest=do_initializer_rec(value, type, force_constant); return; // done } } else if(follow(value.type())==type) { // a struct/union can be initialized directly with // an expression of the right type. This doesn't // work with arrays, unfortunately. if(type.id()==ID_struct || type.id()==ID_union) { *dest=value; return; // done } } // we are initializing a compound type, and enter it! designator_enter(type, designator); assert(!dest->operands().empty()); dest=&(dest->op0()); // we run into another loop iteration } }