expr2tc from_integer(const mp_integer &int_value, const type2tc &type) { switch(type->type_id) { case type2t::bool_id: return !int_value.is_zero() ? gen_true_expr() : gen_false_expr(); case type2t::unsignedbv_id: case type2t::signedbv_id: return constant_int2tc(type, int_value); case type2t::fixedbv_id: { constant_fixedbv2tc f(fixedbvt(fixedbv_spect( to_fixedbv_type(type).width, to_fixedbv_type(type).integer_bits))); f->value.from_integer(int_value); return f; } case type2t::floatbv_id: { constant_floatbv2tc f(ieee_floatt(ieee_float_spect( to_floatbv_type(type).fraction, to_floatbv_type(type).exponent))); f->value.from_integer(int_value); return f; } default: abort(); } }
literalt boolbvt::convert_ieee_float_rel(const exprt &expr) { const exprt::operandst &operands=expr.operands(); const irep_idt &rel=expr.id(); if(operands.size()==2) { const exprt &op0=expr.op0(); const exprt &op1=expr.op1(); bvtypet bvtype0=get_bvtype(op0.type()); bvtypet bvtype1=get_bvtype(op1.type()); const bvt &bv0=convert_bv(op0); const bvt &bv1=convert_bv(op1); if(bv0.size()==bv1.size() && !bv0.empty() && bvtype0==IS_FLOAT && bvtype1==IS_FLOAT) { float_utilst float_utils(prop); float_utils.spec=to_floatbv_type(op0.type()); if(rel==ID_ieee_float_equal) return float_utils.relation(bv0, float_utilst::EQ, bv1); else if(rel==ID_ieee_float_notequal) return !float_utils.relation(bv0, float_utilst::EQ, bv1); else return SUB::convert_rest(expr); } } return SUB::convert_rest(expr); }
exprt gen_one(const typet &type) { const irep_idt type_id=type.id(); exprt result=constant_exprt(type); if(type_id==ID_bool || type_id==ID_rational || type_id==ID_real || type_id==ID_integer || type_id==ID_natural) { result.set(ID_value, ID_1); } else if(type_id==ID_unsignedbv || type_id==ID_signedbv || type_id==ID_c_enum) { std::string value; unsigned width=to_bitvector_type(type).get_width(); for(unsigned i=0; i<width-1; i++) value+='0'; value+='1'; result.set(ID_value, value); } else if(type_id==ID_fixedbv) { fixedbvt fixedbv; fixedbv.spec=to_fixedbv_type(type); fixedbv.from_integer(1); result=fixedbv.to_expr(); } else if(type_id==ID_floatbv) { ieee_floatt ieee_float; ieee_float.spec=to_floatbv_type(type); ieee_float.from_integer(1); result=ieee_float.to_expr(); } else if(type_id==ID_complex) { result=exprt(ID_complex, type); result.operands().resize(2); result.op0()=gen_one(type.subtype()); result.op1()=gen_zero(type.subtype()); } else result.make_nil(); return result; }
void boolbvt::convert_floatbv_typecast( const floatbv_typecast_exprt &expr, bvt &bv) { const exprt &op0=expr.op(); // number to convert const exprt &op1=expr.rounding_mode(); // rounding mode bvt bv0=convert_bv(op0); bvt bv1=convert_bv(op1); const typet &src_type=ns.follow(expr.op0().type()); const typet &dest_type=ns.follow(expr.type()); if(src_type==dest_type) // redundant type cast? { bv=bv0; return; } float_utilst float_utils(prop); float_utils.set_rounding_mode(convert_bv(op1)); if(src_type.id()==ID_floatbv && dest_type.id()==ID_floatbv) { float_utils.spec=to_floatbv_type(src_type); bv=float_utils.conversion(bv0, to_floatbv_type(dest_type)); } else if(src_type.id()==ID_signedbv && dest_type.id()==ID_floatbv) { float_utils.spec=to_floatbv_type(dest_type); bv=float_utils.from_signed_integer(bv0); } else if(src_type.id()==ID_unsignedbv && dest_type.id()==ID_floatbv) { float_utils.spec=to_floatbv_type(dest_type); bv=float_utils.from_unsigned_integer(bv0); } else if(src_type.id()==ID_floatbv && dest_type.id()==ID_signedbv) { std::size_t dest_width=to_signedbv_type(dest_type).get_width(); float_utils.spec=to_floatbv_type(src_type); bv=float_utils.to_signed_integer(bv0, dest_width); } else if(src_type.id()==ID_floatbv && dest_type.id()==ID_unsignedbv) { std::size_t dest_width=to_unsignedbv_type(dest_type).get_width(); float_utils.spec=to_floatbv_type(src_type); bv=float_utils.to_unsigned_integer(bv0, dest_width); } else return conversion_failed(expr, bv); }
bvt boolbvt::convert_abs(const exprt &expr) { std::size_t width=boolbv_width(expr.type()); if(width==0) return conversion_failed(expr); const exprt::operandst &operands=expr.operands(); if(operands.size()!=1) throw "abs takes one operand"; const exprt &op0=expr.op0(); const bvt &op_bv=convert_bv(op0); if(op0.type()!=expr.type()) return conversion_failed(expr); bvtypet bvtype=get_bvtype(expr.type()); if(bvtype==IS_FIXED || bvtype==IS_SIGNED || bvtype==IS_UNSIGNED) { return bv_utils.absolute_value(op_bv); } else if(bvtype==IS_FLOAT) { float_utilst float_utils(prop); float_utils.spec=to_floatbv_type(expr.type()); return float_utils.abs(op_bv); } return conversion_failed(expr); }
void bv_refinementt::check_SAT(approximationt &a) { // get values get_values(a); // see if the satisfying assignment is spurious in any way const typet &type=ns.follow(a.expr.type()); if(type.id()==ID_floatbv) { // these are all trinary assert(a.expr.operands().size()==3); if(a.over_state==MAX_STATE) return; ieee_float_spect spec(to_floatbv_type(type)); ieee_floatt o0(spec), o1(spec); o0.unpack(a.op0_value); o1.unpack(a.op1_value); ieee_floatt result=o0; o0.rounding_mode=RM; o1.rounding_mode=RM; result.rounding_mode=RM; if(a.expr.id()==ID_floatbv_plus) result+=o1; else if(a.expr.id()==ID_floatbv_minus) result-=o1; else if(a.expr.id()==ID_floatbv_mult) result*=o1; else if(a.expr.id()==ID_floatbv_div) result/=o1; else assert(false); if(result.pack()==a.result_value) // ok return; #ifdef DEBUG ieee_floatt rr(spec); rr.unpack(a.result_value); std::cout << "S1: " << o0 << " " << a.expr.id() << " " << o1 << " != " << rr << std::endl; std::cout << "S2: " << integer2binary(a.op0_value, spec.width()) << " " << a.expr.id() << " " << integer2binary(a.op1_value, spec.width()) << "!=" << integer2binary(a.result_value, spec.width()) << std::endl; std::cout << "S3: " << integer2binary(a.op0_value, spec.width()) << " " << a.expr.id() << " " << integer2binary(a.op1_value, spec.width()) << "==" << integer2binary(result.pack(), spec.width()) << std::endl; #endif //if(a.over_state==1) { std::cout << "DISAGREEMENT!\n"; exit(1); } if(a.over_state<max_node_refinement) { bvt r; float_utilst float_utils(prop); float_utils.spec=spec; float_utils.rounding_mode_bits.set(RM); literalt op0_equal= bv_utils.equal(a.op0_bv, float_utils.build_constant(o0)); literalt op1_equal= bv_utils.equal(a.op1_bv, float_utils.build_constant(o1)); literalt result_equal= bv_utils.equal(a.result_bv, float_utils.build_constant(result)); literalt op0_and_op1_equal= prop.land(op0_equal, op1_equal); prop.l_set_to_true( prop.limplies(op0_and_op1_equal, result_equal)); } else { // give up // remove any previous over-approximation a.over_assumptions.clear(); a.over_state=MAX_STATE; bvt r; float_utilst float_utils(prop); float_utils.spec=spec; float_utils.rounding_mode_bits.set(RM); bvt op0=a.op0_bv, op1=a.op1_bv, res=a.result_bv; if(a.expr.id()==ID_floatbv_plus) r=float_utils.add(op0, op1); else if(a.expr.id()==ID_floatbv_minus) r=float_utils.sub(op0, op1); else if(a.expr.id()==ID_floatbv_mult) r=float_utils.mul(op0, op1); else if(a.expr.id()==ID_floatbv_div) r=float_utils.div(op0, op1); else assert(0); assert(r.size()==res.size()); bv_utils.set_equal(r, res); } } else if(type.id()==ID_signedbv || type.id()==ID_unsignedbv) { // these are all binary assert(a.expr.operands().size()==2); // already full interpretation? if(a.over_state>0) return; bv_spect spec(type); bv_arithmetict o0(spec), o1(spec); o0.unpack(a.op0_value); o1.unpack(a.op1_value); // division by zero is never spurious if((a.expr.id()==ID_div || a.expr.id()==ID_mod) && o1==0) return; if(a.expr.id()==ID_mult) o0*=o1; else if(a.expr.id()==ID_div) o0/=o1; else if(a.expr.id()==ID_mod) o0%=o1; else assert(false); if(o0.pack()==a.result_value) // ok return; if(a.over_state==0) { // we give up right away and add the full interpretation bvt r; if(a.expr.id()==ID_mult) { r=bv_utils.multiplier( a.op0_bv, a.op1_bv, a.expr.type().id()==ID_signedbv?bv_utilst::SIGNED:bv_utilst::UNSIGNED); } else if(a.expr.id()==ID_div) { r=bv_utils.divider( a.op0_bv, a.op1_bv, a.expr.type().id()==ID_signedbv?bv_utilst::SIGNED:bv_utilst::UNSIGNED); } else if(a.expr.id()==ID_mod) { r=bv_utils.remainder( a.op0_bv, a.op1_bv, a.expr.type().id()==ID_signedbv?bv_utilst::SIGNED:bv_utilst::UNSIGNED); } else assert(0); bv_utils.set_equal(r, a.result_bv); } else assert(0); } else assert(0); status() << "Found spurious `" << a.as_string() << "' (state " << a.over_state << ")" << eom; progress=true; if(a.over_state<MAX_STATE) a.over_state++; }
xmlt xml( const typet &type, const namespacet &ns) { if(type.id()==ID_symbol) return xml(ns.follow(type), ns); xmlt result; if(type.id()==ID_unsignedbv) { result.name="integer"; result.set_attribute("width", to_unsignedbv_type(type).get_width()); } else if(type.id()==ID_signedbv) { result.name="integer"; result.set_attribute("width", to_signedbv_type(type).get_width()); } else if(type.id()==ID_floatbv) { result.name="float"; result.set_attribute("width", to_floatbv_type(type).get_width()); } else if(type.id()==ID_bv) { result.name="integer"; result.set_attribute("width", to_bv_type(type).get_width()); } else if(type.id()==ID_c_bit_field) { result.name="integer"; result.set_attribute("width", to_c_bit_field_type(type).get_width()); } else if(type.id()==ID_c_enum_tag) { // we return the base type return xml(ns.follow_tag(to_c_enum_tag_type(type)).subtype(), ns); } else if(type.id()==ID_fixedbv) { result.name="fixed"; result.set_attribute("width", to_fixedbv_type(type).get_width()); } else if(type.id()==ID_pointer) { result.name="pointer"; result.new_element("subtype").new_element()=xml(type.subtype(), ns); } else if(type.id()==ID_bool) { result.name="boolean"; } else if(type.id()==ID_array) { result.name="array"; result.new_element("subtype").new_element()=xml(type.subtype(), ns); } else if(type.id()==ID_vector) { result.name="vector"; result.new_element("subtype").new_element()=xml(type.subtype(), ns); result.new_element("size").new_element()=xml(to_vector_type(type).size(), ns); } else if(type.id()==ID_struct) { result.name="struct"; const struct_typet::componentst &components= to_struct_type(type).components(); for(struct_typet::componentst::const_iterator it=components.begin(); it!=components.end(); it++) { xmlt &e=result.new_element("member"); e.set_attribute("name", id2string(it->get_name())); e.new_element("type").new_element()=xml(it->type(), ns); } } else if(type.id()==ID_union) { result.name="union"; const union_typet::componentst &components= to_union_type(type).components(); for(union_typet::componentst::const_iterator it=components.begin(); it!=components.end(); it++) { xmlt &e=result.new_element("member"); e.set_attribute("name", id2string(it->get_name())); e.new_element("type").new_element()=xml(it->type(), ns); } } else result.name="unknown"; return result; }
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 goto_checkt::nan_check( const exprt &expr, const guardt &guard) { if(!enable_nan_check) return; // first, check type if(expr.type().id()!=ID_floatbv) return; if(expr.id()!=ID_plus && expr.id()!=ID_mult && expr.id()!=ID_div && expr.id()!=ID_minus) return; // add NaN subgoal exprt isnan; if(expr.id()==ID_div) { assert(expr.operands().size()==2); // there a two ways to get a new NaN on division: // 0/0 = NaN and x/inf = NaN // (note that x/0 = +-inf for x!=0 and x!=inf) exprt zero_div_zero=and_exprt( ieee_float_equal_exprt(expr.op0(), gen_zero(expr.op0().type())), ieee_float_equal_exprt(expr.op1(), gen_zero(expr.op1().type()))); exprt div_inf=unary_exprt(ID_isinf, expr.op1(), bool_typet()); isnan=or_exprt(zero_div_zero, div_inf); } else if(expr.id()==ID_mult) { if(expr.operands().size()>=3) return nan_check(make_binary(expr), guard); assert(expr.operands().size()==2); // Inf * 0 is NaN exprt inf_times_zero=and_exprt( unary_exprt(ID_isinf, expr.op0(), bool_typet()), ieee_float_equal_exprt(expr.op1(), gen_zero(expr.op1().type()))); exprt zero_times_inf=and_exprt( ieee_float_equal_exprt(expr.op1(), gen_zero(expr.op1().type())), unary_exprt(ID_isinf, expr.op0(), bool_typet())); isnan=or_exprt(inf_times_zero, zero_times_inf); } else if(expr.id()==ID_plus) { if(expr.operands().size()>=3) return nan_check(make_binary(expr), guard); assert(expr.operands().size()==2); // -inf + +inf = NaN and +inf + -inf = NaN, // i.e., signs differ ieee_float_spect spec=ieee_float_spect(to_floatbv_type(expr.type())); exprt plus_inf=ieee_floatt::plus_infinity(spec).to_expr(); exprt minus_inf=ieee_floatt::minus_infinity(spec).to_expr(); isnan=or_exprt( and_exprt(equal_exprt(expr.op0(), minus_inf), equal_exprt(expr.op1(), plus_inf)), and_exprt(equal_exprt(expr.op0(), plus_inf), equal_exprt(expr.op1(), minus_inf))); } else if(expr.id()==ID_minus) { assert(expr.operands().size()==2); // +inf - +inf = NaN and -inf - -inf = NaN, // i.e., signs match ieee_float_spect spec=ieee_float_spect(to_floatbv_type(expr.type())); exprt plus_inf=ieee_floatt::plus_infinity(spec).to_expr(); exprt minus_inf=ieee_floatt::minus_infinity(spec).to_expr(); isnan=or_exprt( and_exprt(equal_exprt(expr.op0(), plus_inf), equal_exprt(expr.op1(), plus_inf)), and_exprt(equal_exprt(expr.op0(), minus_inf), equal_exprt(expr.op1(), minus_inf))); } else assert(false); isnan.make_not(); add_guarded_claim( isnan, "NaN on "+expr.id_string(), "NaN", expr.find_source_location(), expr, guard); }
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 convert_float_literal(const std::string &src, exprt &dest) { mp_integer significand; mp_integer exponent; bool is_float, is_long; unsigned base; parse_float(src, significand, exponent, base, is_float, is_long); dest = exprt("constant"); dest.cformat(src); if(is_float) { dest.type() = float_type(); dest.type().set("#cpp_type", "float"); } else if(is_long) { dest.type() = long_double_type(); dest.type().set("#cpp_type", "long_double"); } else { dest.type() = double_type(); dest.type().set("#cpp_type", "double"); } if(config.ansi_c.use_fixed_for_float) { unsigned width = atoi(dest.type().width().c_str()); unsigned fraction_bits; const std::string &integer_bits = dest.type().integer_bits().as_string(); if(integer_bits == "") fraction_bits = width / 2; else fraction_bits = width - atoi(integer_bits.c_str()); mp_integer factor = mp_integer(1) << fraction_bits; mp_integer value = significand * factor; if(value != 0) { if(exponent < 0) value /= power(base, -exponent); else { value *= power(base, exponent); if(value >= power(2, width - 1)) { // saturate: use "biggest value" value = power(2, width - 1) - 1; } else if(value <= -power(2, width - 1) - 1) { // saturate: use "smallest value" value = -power(2, width - 1); } } } dest.value(integer2binary(value, width)); } else { ieee_floatt a; a.spec = to_floatbv_type(dest.type()); if(base == 10) a.from_base10(significand, exponent); else if(base == 2) // hex a.build(significand, exponent); else assert(false); dest.value(integer2binary(a.pack(), a.spec.width())); } }
void goto_checkt::conversion_check( const exprt &expr, const guardt &guard) { if(!enable_conversion_check) return; // First, check type. const typet &type=ns.follow(expr.type()); if(type.id()!=ID_signedbv && type.id()!=ID_unsignedbv) return; if(expr.id()==ID_typecast) { // conversion to signed int may overflow if(expr.operands().size()!=1) throw "typecast takes one operand"; const typet &old_type=ns.follow(expr.op0().type()); if(type.id()==ID_signedbv) { std::size_t new_width=to_signedbv_type(type).get_width(); if(old_type.id()==ID_signedbv) // signed -> signed { std::size_t old_width=to_signedbv_type(old_type).get_width(); if(new_width>=old_width) return; // always ok binary_relation_exprt no_overflow_upper(ID_le); no_overflow_upper.lhs()=expr.op0(); no_overflow_upper.rhs()=from_integer(power(2, new_width-1)-1, old_type); binary_relation_exprt no_overflow_lower(ID_ge); no_overflow_lower.lhs()=expr.op0(); no_overflow_lower.rhs()=from_integer(-power(2, new_width-1), old_type); add_guarded_claim( and_exprt(no_overflow_lower, no_overflow_upper), "arithmetic overflow on signed type conversion", "overflow", expr.find_source_location(), expr, guard); } else if(old_type.id()==ID_unsignedbv) // unsigned -> signed { std::size_t old_width=to_unsignedbv_type(old_type).get_width(); if(new_width>=old_width+1) return; // always ok binary_relation_exprt no_overflow_upper(ID_le); no_overflow_upper.lhs()=expr.op0(); no_overflow_upper.rhs()=from_integer(power(2, new_width-1)-1, old_type); add_guarded_claim( no_overflow_upper, "arithmetic overflow on unsigned to signed type conversion", "overflow", expr.find_source_location(), expr, guard); } else if(old_type.id()==ID_floatbv) // float -> signed { // Note that the fractional part is truncated! ieee_floatt upper(to_floatbv_type(old_type)); upper.from_integer(power(2, new_width-1)); binary_relation_exprt no_overflow_upper(ID_lt); no_overflow_upper.lhs()=expr.op0(); no_overflow_upper.rhs()=upper.to_expr(); ieee_floatt lower(to_floatbv_type(old_type)); lower.from_integer(-power(2, new_width-1)-1); binary_relation_exprt no_overflow_lower(ID_gt); no_overflow_lower.lhs()=expr.op0(); no_overflow_lower.rhs()=lower.to_expr(); add_guarded_claim( and_exprt(no_overflow_lower, no_overflow_upper), "arithmetic overflow on float to signed integer type conversion", "overflow", expr.find_source_location(), expr, guard); } } else if(type.id()==ID_unsignedbv) { std::size_t new_width=to_unsignedbv_type(type).get_width(); if(old_type.id()==ID_signedbv) // signed -> unsigned { std::size_t old_width=to_signedbv_type(old_type).get_width(); if(new_width>=old_width-1) { // only need lower bound check binary_relation_exprt no_overflow_lower(ID_ge); no_overflow_lower.lhs()=expr.op0(); no_overflow_lower.rhs()=from_integer(0, old_type); add_guarded_claim( no_overflow_lower, "arithmetic overflow on signed to unsigned type conversion", "overflow", expr.find_source_location(), expr, guard); } else { // need both binary_relation_exprt no_overflow_upper(ID_le); no_overflow_upper.lhs()=expr.op0(); no_overflow_upper.rhs()=from_integer(power(2, new_width)-1, old_type); binary_relation_exprt no_overflow_lower(ID_ge); no_overflow_lower.lhs()=expr.op0(); no_overflow_lower.rhs()=from_integer(0, old_type); add_guarded_claim( and_exprt(no_overflow_lower, no_overflow_upper), "arithmetic overflow on signed to unsigned type conversion", "overflow", expr.find_source_location(), expr, guard); } } else if(old_type.id()==ID_unsignedbv) // unsigned -> unsigned { std::size_t old_width=to_unsignedbv_type(old_type).get_width(); if(new_width>=old_width) return; // always ok binary_relation_exprt no_overflow_upper(ID_le); no_overflow_upper.lhs()=expr.op0(); no_overflow_upper.rhs()=from_integer(power(2, new_width)-1, old_type); add_guarded_claim( no_overflow_upper, "arithmetic overflow on unsigned to unsigned type conversion", "overflow", expr.find_source_location(), expr, guard); } else if(old_type.id()==ID_floatbv) // float -> unsigned { // Note that the fractional part is truncated! ieee_floatt upper(to_floatbv_type(old_type)); upper.from_integer(power(2, new_width)-1); binary_relation_exprt no_overflow_upper(ID_lt); no_overflow_upper.lhs()=expr.op0(); no_overflow_upper.rhs()=upper.to_expr(); ieee_floatt lower(to_floatbv_type(old_type)); lower.from_integer(-1); binary_relation_exprt no_overflow_lower(ID_gt); no_overflow_lower.lhs()=expr.op0(); no_overflow_lower.rhs()=lower.to_expr(); add_guarded_claim( and_exprt(no_overflow_lower, no_overflow_upper), "arithmetic overflow on float to unsigned integer type conversion", "overflow", expr.find_source_location(), expr, guard); } } } }
void boolbvt::convert_add_sub(const exprt &expr, bvt &bv) { const typet &type=ns.follow(expr.type()); if(type.id()!=ID_unsignedbv && type.id()!=ID_signedbv && type.id()!=ID_fixedbv && type.id()!=ID_floatbv && type.id()!=ID_range && type.id()!=ID_vector) return conversion_failed(expr, bv); unsigned width=boolbv_width(type); if(width==0) return conversion_failed(expr, bv); const exprt::operandst &operands=expr.operands(); if(operands.size()==0) throw "operand "+expr.id_string()+" takes at least one operand"; const exprt &op0=expr.op0(); if(op0.type()!=type) { std::cerr << expr.pretty() << std::endl; throw "add/sub with mixed types"; } convert_bv(op0, bv); if(bv.size()!=width) throw "convert_add_sub: unexpected operand 0 width"; bool subtract=(expr.id()==ID_minus || expr.id()=="no-overflow-minus"); bool no_overflow=(expr.id()=="no-overflow-plus" || expr.id()=="no-overflow-minus"); typet arithmetic_type= (type.id()==ID_vector)?ns.follow(type.subtype()):type; bv_utilst::representationt rep= (arithmetic_type.id()==ID_signedbv || arithmetic_type.id()==ID_fixedbv)?bv_utilst::SIGNED: bv_utilst::UNSIGNED; for(exprt::operandst::const_iterator it=operands.begin()+1; it!=operands.end(); it++) { if(it->type()!=type) { std::cerr << expr.pretty() << std::endl; throw "add/sub with mixed types"; } bvt op; convert_bv(*it, op); if(op.size()!=width) throw "convert_add_sub: unexpected operand width"; if(type.id()==ID_vector) { const typet &subtype=ns.follow(type.subtype()); unsigned sub_width=boolbv_width(subtype); if(sub_width==0 || width%sub_width!=0) throw "convert_add_sub: unexpected vector operand width"; unsigned size=width/sub_width; bv.resize(width); for(unsigned i=0; i<size; i++) { bvt tmp_op; tmp_op.resize(sub_width); for(unsigned j=0; j<tmp_op.size(); j++) { assert(i*sub_width+j<op.size()); tmp_op[j]=op[i*sub_width+j]; } bvt tmp_result; tmp_result.resize(sub_width); for(unsigned j=0; j<tmp_result.size(); j++) { assert(i*sub_width+j<bv.size()); tmp_result[j]=bv[i*sub_width+j]; } if(type.subtype().id()==ID_floatbv) { #ifdef HAVE_FLOATBV float_utilst float_utils(prop); float_utils.spec=to_floatbv_type(subtype); tmp_result=float_utils.add_sub(tmp_result, tmp_op, subtract); #else return conversion_failed(expr, bv); #endif } else tmp_result=bv_utils.add_sub(tmp_result, tmp_op, subtract); assert(tmp_result.size()==sub_width); for(unsigned j=0; j<tmp_result.size(); j++) { assert(i*sub_width+j<bv.size()); bv[i*sub_width+j]=tmp_result[j]; } } } else if(type.id()==ID_floatbv) { #ifdef HAVE_FLOATBV float_utilst float_utils(prop); float_utils.spec=to_floatbv_type(arithmetic_type); bv=float_utils.add_sub(bv, op, subtract); #else return conversion_failed(expr, bv); #endif } else if(no_overflow) bv=bv_utils.add_sub_no_overflow(bv, op, subtract, rep); else bv=bv_utils.add_sub(bv, op, subtract); } }
void boolbvt::convert_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; }
const boolbv_widtht::entryt &boolbv_widtht::get_entry(const typet &type) const { // check cache first std::pair<cachet::iterator, bool> cache_result= cache.insert(std::pair<typet, entryt>(type, entryt())); entryt &entry=cache_result.first->second; if(!cache_result.second) // found! return entry; entry.total_width=0; const irep_idt type_id=type.id(); if(type_id==ID_struct) { const struct_typet::componentst &components= to_struct_type(type).components(); std::size_t offset=0; entry.members.resize(components.size()); for(std::size_t i=0; i<entry.members.size(); i++) { std::size_t sub_width=operator()(components[i].type()); entry.members[i].offset=offset; entry.members[i].width=sub_width; offset+=sub_width; } entry.total_width=offset; } else if(type_id==ID_union) { const union_typet::componentst &components= to_union_type(type).components(); entry.members.resize(components.size()); std::size_t max_width=0; for(std::size_t i=0; i<entry.members.size(); i++) { std::size_t sub_width=operator()(components[i].type()); entry.members[i].width=sub_width; max_width=std::max(max_width, sub_width); } entry.total_width=max_width; } else if(type_id==ID_bool) entry.total_width=1; else if(type_id==ID_c_bool) { entry.total_width=to_c_bool_type(type).get_width(); assert(entry.total_width!=0); } else if(type_id==ID_signedbv) { entry.total_width=to_signedbv_type(type).get_width(); assert(entry.total_width!=0); } else if(type_id==ID_unsignedbv) { entry.total_width=to_unsignedbv_type(type).get_width(); assert(entry.total_width!=0); } else if(type_id==ID_floatbv) { entry.total_width=to_floatbv_type(type).get_width(); assert(entry.total_width!=0); } else if(type_id==ID_fixedbv) { entry.total_width=to_fixedbv_type(type).get_width(); assert(entry.total_width!=0); } else if(type_id==ID_bv) { entry.total_width=to_bv_type(type).get_width(); assert(entry.total_width!=0); } else if(type_id==ID_verilogbv) { // we encode with two bits entry.total_width=type.get_unsigned_int(ID_width)*2; assert(entry.total_width!=0); } else if(type_id==ID_range) { mp_integer from=string2integer(type.get_string(ID_from)), to=string2integer(type.get_string(ID_to)); mp_integer size=to-from+1; if(size>=1) { entry.total_width=integer2unsigned(address_bits(size)); assert(entry.total_width!=0); } } else if(type_id==ID_array) { const array_typet &array_type=to_array_type(type); std::size_t sub_width=operator()(array_type.subtype()); mp_integer array_size; if(to_integer(array_type.size(), array_size)) { // we can still use the theory of arrays for this entry.total_width=0; } else { mp_integer total=array_size*sub_width; if(total>(1<<30)) // realistic limit throw "array too large for flattening"; entry.total_width=integer2unsigned(total); } } else if(type_id==ID_vector) { const vector_typet &vector_type=to_vector_type(type); std::size_t sub_width=operator()(vector_type.subtype()); mp_integer vector_size; if(to_integer(vector_type.size(), vector_size)) { // we can still use the theory of arrays for this entry.total_width=0; } else { mp_integer total=vector_size*sub_width; if(total>(1<<30)) // realistic limit throw "vector too large for flattening"; entry.total_width=integer2unsigned(vector_size*sub_width); } } else if(type_id==ID_complex) { std::size_t sub_width=operator()(type.subtype()); entry.total_width=integer2unsigned(2*sub_width); } else if(type_id==ID_code) { } else if(type_id==ID_enum) { // get number of necessary bits std::size_t size=type.find(ID_elements).get_sub().size(); entry.total_width=integer2unsigned(address_bits(size)); assert(entry.total_width!=0); } else if(type_id==ID_c_enum) { // these have a subtype entry.total_width=type.subtype().get_unsigned_int(ID_width); assert(entry.total_width!=0); } else if(type_id==ID_incomplete_c_enum) { // no width } else if(type_id==ID_pointer || type_id==ID_reference) { entry.total_width=config.ansi_c.pointer_width; } else if(type_id==ID_symbol) entry=get_entry(ns.follow(type)); else if(type_id==ID_struct_tag) entry=get_entry(ns.follow_tag(to_struct_tag_type(type))); else if(type_id==ID_union_tag) entry=get_entry(ns.follow_tag(to_union_tag_type(type))); else if(type_id==ID_c_enum_tag) entry=get_entry(ns.follow_tag(to_c_enum_tag_type(type))); else if(type_id==ID_c_bit_field) { entry.total_width=to_c_bit_field_type(type).get_width(); } return entry; }
exprt convert_float_literal(const std::string &src) { mp_integer significand; mp_integer exponent; bool is_float, is_long, is_fixed, is_accum; unsigned base; parse_float(src, significand, exponent, base, is_float, is_long, is_fixed, is_accum); exprt result=exprt(ID_constant); result.set(ID_C_cformat, src); // In ANSI-C, float literals are double by default // unless marked with 'f'. if(is_float) { result.type()=float_type(); result.type().set(ID_C_cpp_type, ID_float); } else if(is_long) { result.type()=long_double_type(); result.type().set(ID_C_cpp_type, ID_long_double); } else if(is_fixed) { result.type()=fixed_type(); result.type().set(ID_C_cpp_type, ID_fixed); } else if(is_accum) { result.type()=accum_type(); result.type().set(ID_C_cpp_type, ID_accum); } else { result.type()=double_type(); // default result.type().set(ID_C_cpp_type, ID_double); } if(config.ansi_c.use_fixed_for_float || is_fixed || is_accum) { unsigned width=result.type().get_int(ID_width); unsigned fraction_bits; const irep_idt integer_bits=result.type().get(ID_integer_bits); assert(width!=0); if(is_fixed) { fraction_bits = width - 1; } else if(is_accum) { fraction_bits = width - 9; } else if(integer_bits==irep_idt()) fraction_bits=width/2; // default else fraction_bits=width-safe_string2int(id2string(integer_bits)); mp_integer factor=mp_integer(1)<<fraction_bits; mp_integer value=significand*factor; if(value!=0) { if(exponent<0) value/=power(base, -exponent); else { value*=power(base, exponent); if(value>=power(2, width-1)) { // saturate: use "biggest value" value=power(2, width-1)-1; } else if(value<=-power(2, width-1)-1) { // saturate: use "smallest value" value=-power(2, width-1); } } } result.set(ID_value, integer2binary(value, width)); } else { ieee_floatt a; a.spec=to_floatbv_type(result.type()); if(base==10) a.from_base10(significand, exponent); else if(base==2) // hex a.build(significand, exponent); else assert(false); result.set(ID_value, integer2binary(a.pack(), a.spec.width())); } return result; }
void ieee_floatt::from_expr(const constant_exprt &expr) { spec=ieee_float_spect(to_floatbv_type(expr.type())); unpack(binary2integer(id2string(expr.get_value()), false)); }
void ieee_floatt::from_expr(const exprt &expr) { assert(expr.is_constant()); spec=to_floatbv_type(expr.type()); unpack(binary2integer(expr.get_string(ID_value), false)); }
exprt convert_float_literal(const std::string &src) { mp_integer significand; mp_integer exponent; bool is_float, is_long, is_imaginary; bool is_decimal, is_float80, is_float128; // GCC extensions unsigned base; parse_float(src, significand, exponent, base, is_float, is_long, is_imaginary, is_decimal, is_float80, is_float128); exprt result=exprt(ID_constant); result.set(ID_C_cformat, src); // In ANSI-C, float literals are double by default, // unless marked with 'f'. // All of these can be complex as well. // This can be overriden with // config.ansi_c.single_precision_constant. if(is_float) result.type()=float_type(); else if(is_long) result.type()=long_double_type(); else if(is_float80) { result.type()=ieee_float_spect(64, 15).to_type(); result.type().set(ID_C_c_type, ID_long_double); } else if(is_float128) { result.type()=ieee_float_spect::quadruple_precision().to_type(); result.type().set(ID_C_c_type, ID_gcc_float128); } else { // default if(config.ansi_c.single_precision_constant) result.type()=float_type(); // default else result.type()=double_type(); // default } if(is_decimal) { // TODO - should set ID_gcc_decimal32/ID_gcc_decimal64/ID_gcc_decimal128, // but these aren't handled anywhere } if(config.ansi_c.use_fixed_for_float) { unsigned width=result.type().get_int(ID_width); unsigned fraction_bits; const irep_idt integer_bits=result.type().get(ID_integer_bits); assert(width!=0); if(integer_bits==irep_idt()) fraction_bits=width/2; // default else fraction_bits=width-safe_string2int(id2string(integer_bits)); mp_integer factor=mp_integer(1)<<fraction_bits; mp_integer value=significand*factor; if(value!=0) { if(exponent<0) value/=power(base, -exponent); else { value*=power(base, exponent); if(value>=power(2, width-1)) { // saturate: use "biggest value" value=power(2, width-1)-1; } else if(value<=-power(2, width-1)-1) { // saturate: use "smallest value" value=-power(2, width-1); } } } result.set(ID_value, integer2binary(value, width)); } else { ieee_floatt a; a.spec=to_floatbv_type(result.type()); if(base==10) a.from_base10(significand, exponent); else if(base==2) // hex a.build(significand, exponent); else assert(false); result.set(ID_value, integer2binary(a.pack(), a.spec.width())); } if(is_imaginary) { complex_typet complex_type; complex_type.subtype()=result.type(); exprt complex_expr(ID_complex, complex_type); complex_expr.operands().resize(2); complex_expr.op0()=gen_zero(result.type()); complex_expr.op1()=result; return complex_expr; } return result; }
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); }
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)integer2size_t(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)integer2size_t(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)integer2size_t(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; }
json_objectt json( const typet &type, const namespacet &ns) { if(type.id()==ID_symbol) return json(ns.follow(type), ns); json_objectt result; if(type.id()==ID_unsignedbv) { result["name"]=json_stringt("integer"); result["width"]= json_numbert(i2string(to_unsignedbv_type(type).get_width())); } else if(type.id()==ID_signedbv) { result["name"]=json_stringt("integer"); result["width"]=json_numbert(i2string(to_signedbv_type(type).get_width())); } else if(type.id()==ID_floatbv) { result["name"]=json_stringt("float"); result["width"]=json_numbert(i2string(to_floatbv_type(type).get_width())); } else if(type.id()==ID_bv) { result["name"]=json_stringt("integer"); result["width"]=json_numbert(i2string(to_bv_type(type).get_width())); } else if(type.id()==ID_c_bit_field) { result["name"]=json_stringt("integer"); result["width"]= json_numbert(i2string(to_c_bit_field_type(type).get_width())); } else if(type.id()==ID_c_enum_tag) { // we return the base type return json(ns.follow_tag(to_c_enum_tag_type(type)).subtype(), ns); } else if(type.id()==ID_fixedbv) { result["name"]=json_stringt("fixed"); result["width"]=json_numbert(i2string(to_fixedbv_type(type).get_width())); } else if(type.id()==ID_pointer) { result["name"]=json_stringt("pointer"); result["subtype"]=json(type.subtype(), ns); } else if(type.id()==ID_bool) { result["name"]=json_stringt("boolean"); } else if(type.id()==ID_array) { result["name"]=json_stringt("array"); result["subtype"]=json(type.subtype(), ns); } else if(type.id()==ID_vector) { result["name"]=json_stringt("vector"); result["subtype"]=json(type.subtype(), ns); result["size"]=json(to_vector_type(type).size(), ns); } else if(type.id()==ID_struct) { result["name"]=json_stringt("struct"); json_arrayt &members=result["members"].make_array(); const struct_typet::componentst &components= to_struct_type(type).components(); for(const auto & it : components) { json_objectt &e=members.push_back().make_object(); e["name"]=json_stringt(id2string(it.get_name())); e["type"]=json(it.type(), ns); } } else if(type.id()==ID_union) { result["name"]=json_stringt("union"); json_arrayt &members=result["members"].make_array(); const union_typet::componentst &components= to_union_type(type).components(); for(const auto & it : components) { json_objectt &e=members.push_back().make_object(); e["name"]=json_stringt(id2string(it.get_name())); e["type"]=json(it.type(), ns); } } else result["name"]=json_stringt("unknown"); return result; }