/** * Return the smallest type that both t1 and t2 can be cast to without losing * information. * * e.g. * * join_types(unsignedbv_typet(32), unsignedbv_typet(16))=unsignedbv_typet(32) * join_types(signedbv_typet(16), unsignedbv_typet(16))=signedbv_typet(17) * join_types(signedbv_typet(32), signedbv_typet(32))=signedbv_typet(32) */ typet join_types(const typet &t1, const typet &t2) { // Handle the simple case first... if(t1==t2) { return t1; } // OK, they're not the same type. Are they both bitvectors? if(is_bitvector(t1) && is_bitvector(t2)) { // They are. That makes things easy! There are three cases to consider: // both types are unsigned, both types are signed or there's one of each. bitvector_typet b1=to_bitvector_type(t1); bitvector_typet b2=to_bitvector_type(t2); if(is_unsigned(b1) && is_unsigned(b2)) { // We just need to take the max of their widths. std::size_t width=std::max(b1.get_width(), b2.get_width()); return unsignedbv_typet(width); } else if(is_signed(b1) && is_signed(b2)) { // Again, just need to take the max of the widths. std::size_t width=std::max(b1.get_width(), b2.get_width()); return signedbv_typet(width); } else { // This is the (slightly) tricky case. If we have a signed and an // unsigned type, we're going to return a signed type. And to cast // an unsigned type to a signed type, we need the signed type to be // at least one bit wider than the unsigned type we're casting from. std::size_t signed_width=is_signed(t1) ? b1.get_width() : b2.get_width(); std::size_t unsigned_width=is_signed(t1) ? b2.get_width() : b1.get_width(); // unsigned_width++; std::size_t width=std::max(signed_width, unsigned_width); return signedbv_typet(width); } } std::cerr << "Tried to join types: " << t1.pretty() << " and " << t2.pretty() << '\n'; assert(!"Couldn't join types"); }
typet signed_char_type() { typet result=signedbv_typet(config.ansi_c.char_width); result.set(ID_C_c_type, ID_signed_char); return result; }
typet wchar_t_type() { typet result; if(config.ansi_c.wchar_t_is_unsigned) result=unsignedbv_typet(config.ansi_c.wchar_t_width); else result=signedbv_typet(config.ansi_c.wchar_t_width); result.set(ID_C_c_type, ID_wchar_t); return result; }
symbolt scratch_programt::fresh_symbol(string base) { string name = base + "_" + i2string(num_symbols++); symbolt ret; ret.module = "scratch"; ret.name = name; ret.base_name = name; ret.pretty_name = name; ret.type = signedbv_typet(32); shadow_symbol_table.add(ret); return ret; }
void object_descriptor_exprt::build( const exprt &expr, const namespacet &ns) { assert(object().id()==ID_unknown); object()=expr; if(offset().id()==ID_unknown) offset()=from_integer(0, signedbv_typet(config.ansi_c.pointer_width)); build_object_descriptor_rec(ns, expr, *this); assert(root_object().type().id()!=ID_empty); }
typet char_type() { typet result; // this can be signed or unsigned, depending on the architecture if(config.ansi_c.char_is_unsigned) result=unsignedbv_typet(config.ansi_c.char_width); else result=signedbv_typet(config.ansi_c.char_width); // There are 3 char types, i.e., this one is // different from either signed char or unsigned char! result.set(ID_C_c_type, ID_char); return result; }
exprt ranking_synthesis_satt::coefficient(const exprt &expr) { assert(expr.id()==ID_symbol); exprt &entry = coefficient_map[expr]; if(entry==exprt()) { irep_idt ident=expr.get_string(ID_identifier) + "$C"; // set up a new coefficient entry.id(ID_symbol); entry.set(ID_identifier, ident); // adjust the coefficient type entry.type()=signedbv_typet(2); //expr.type(); } return entry; }
typet signed_short_int_type() { typet result=signedbv_typet(config.ansi_c.short_int_width); result.set(ID_C_c_type, ID_signed_short_int); return result; }
typet gcc_signed_int128_type() { typet result=signedbv_typet(128); result.set(ID_C_c_type, ID_signed_int128); return result; }
typet java_short_type() { return signedbv_typet(16); }
typet java_long_type() { return signedbv_typet(64); }
typet java_int_type() { return signedbv_typet(32); }
typet bv_spect::to_type() const { if(is_signed) return signedbv_typet(width); return unsignedbv_typet(width); }
void c_typecastt::implicit_typecast_arithmetic( exprt &expr1, exprt &expr2) { const typet &type1=ns.follow(expr1.type()); const typet &type2=ns.follow(expr2.type()); c_typet c_type1=minimum_promotion(type1), c_type2=minimum_promotion(type2); c_typet max_type=std::max(c_type1, c_type2); if(max_type==LARGE_SIGNED_INT || max_type==LARGE_UNSIGNED_INT) { // get the biggest width of both unsigned width1=type1.get_int(ID_width); unsigned width2=type2.get_int(ID_width); // produce type typet result_type; if(width1==width2) { if(max_type==LARGE_SIGNED_INT) result_type=signedbv_typet(width1); else result_type=unsignedbv_typet(width1); } else if(width1>width2) result_type=type1; else // width1<width2 result_type=type2; do_typecast(expr1, result_type); do_typecast(expr2, result_type); return; } else if(max_type==COMPLEX) { if(c_type1==COMPLEX && c_type2==COMPLEX) { // promote to the one with bigger subtype if(get_c_type(type1.subtype())>get_c_type(type2.subtype())) do_typecast(expr2, type1); else do_typecast(expr1, type2); } else if(c_type1==COMPLEX) { assert(c_type1==COMPLEX && c_type2!=COMPLEX); do_typecast(expr2, type1.subtype()); do_typecast(expr2, type1); } else { assert(c_type1!=COMPLEX && c_type2==COMPLEX); do_typecast(expr1, type2.subtype()); do_typecast(expr1, type2); } return; } else if(max_type==SINGLE || max_type==DOUBLE || max_type==LONGDOUBLE || max_type==FLOAT128) { // Special-case optimisation: // If we have two non-standard sized floats, don't do implicit type // promotion if we can possibly avoid it. if(type1==type2) return; } implicit_typecast_arithmetic(expr1, max_type); implicit_typecast_arithmetic(expr2, max_type); if(max_type==PTR) { if(c_type1==VOIDPTR) do_typecast(expr1, expr2.type()); if(c_type2==VOIDPTR) do_typecast(expr2, expr1.type()); } }
void c_typecastt::implicit_typecast_arithmetic( exprt &expr1, exprt &expr2) { const typet &type1=ns.follow(expr1.type()); const typet &type2=ns.follow(expr2.type()); c_typet c_type1=get_c_type(type1), c_type2=get_c_type(type2); c_typet max_type=std::max(c_type1, c_type2); // "If an int can represent all values of the original type, the // value is converted to an int; otherwise, it is converted to // an unsigned int." // The second case can arise if we promote any unsigned type // that is as large as unsigned int. if(config.ansi_c.short_int_width==config.ansi_c.int_width && max_type==USHORT) max_type=UINT; else if(config.ansi_c.char_width==config.ansi_c.int_width && max_type==UCHAR) max_type=UINT; else max_type=std::max(max_type, INT); if(max_type==LARGE_SIGNED_INT || max_type==LARGE_UNSIGNED_INT) { // get the biggest width of both unsigned width1=type1.get_int(ID_width); unsigned width2=type2.get_int(ID_width); // produce type typet result_type; if(width1==width2) { if(max_type==LARGE_SIGNED_INT) result_type=signedbv_typet(width1); else result_type=unsignedbv_typet(width1); } else if(width1>width2) result_type=type1; else // width1<width2 result_type=type2; do_typecast(expr1, result_type); do_typecast(expr2, result_type); return; } else if(max_type==COMPLEX) { if(c_type1==COMPLEX && c_type2==COMPLEX) { // promote to the one with bigger subtype if(get_c_type(type1.subtype())>get_c_type(type2.subtype())) do_typecast(expr2, type1); else do_typecast(expr1, type2); } else if(c_type1==COMPLEX) { assert(c_type1==COMPLEX && c_type2!=COMPLEX); do_typecast(expr2, type1.subtype()); do_typecast(expr2, type1); } else { assert(c_type1!=COMPLEX && c_type2==COMPLEX); do_typecast(expr1, type2.subtype()); do_typecast(expr1, type2); } return; } implicit_typecast_arithmetic(expr1, max_type); implicit_typecast_arithmetic(expr2, max_type); if(max_type==PTR) { if(c_type1==VOIDPTR) do_typecast(expr1, expr2.type()); if(c_type2==VOIDPTR) do_typecast(expr2, expr1.type()); } }
signedbv_typet signed_poly_type() { return signedbv_typet(config.ansi_c.int_width); }
typet java_byte_type() { return signedbv_typet(8); }
bool disjunctive_polynomial_accelerationt::fit_polynomial( exprt &var, polynomialt &polynomial, patht &path) { // These are the variables that var depends on with respect to the body. std::vector<expr_listt> parameters; std::set<std::pair<expr_listt, exprt> > coefficients; expr_listt exprs; scratch_programt program(symbol_table); expr_sett influence; cone_of_influence(var, influence); #ifdef DEBUG std::cout << "Fitting a polynomial for " << expr2c(var, ns) << ", which depends on:" << std::endl; for (expr_sett::iterator it = influence.begin(); it != influence.end(); ++it) { std::cout << expr2c(*it, ns) << std::endl; } #endif for (expr_sett::iterator it = influence.begin(); it != influence.end(); ++it) { if (it->id() == ID_index || it->id() == ID_dereference) { // Hack: don't accelerate anything that depends on an array // yet... return false; } exprs.clear(); exprs.push_back(*it); parameters.push_back(exprs); exprs.push_back(loop_counter); parameters.push_back(exprs); } // N exprs.clear(); exprs.push_back(loop_counter); parameters.push_back(exprs); // N^2 exprs.push_back(loop_counter); parameters.push_back(exprs); // Constant exprs.clear(); parameters.push_back(exprs); for (std::vector<expr_listt>::iterator it = parameters.begin(); it != parameters.end(); ++it) { symbolt coeff = utils.fresh_symbol("polynomial::coeff", signed_poly_type()); coefficients.insert(make_pair(*it, coeff.symbol_expr())); // XXX HACK HACK HACK // I'm just constraining these coefficients to prevent overflows messing things // up later... Should really do this properly somehow. program.assume(binary_relation_exprt(from_integer(-(1 << 10), signed_poly_type()), "<", coeff.symbol_expr())); program.assume(binary_relation_exprt(coeff.symbol_expr(), "<", from_integer(1 << 10, signed_poly_type()))); } // Build a set of values for all the parameters that allow us to fit a // unique polynomial. std::map<exprt, exprt> ivals1; std::map<exprt, exprt> ivals2; std::map<exprt, exprt> ivals3; for (expr_sett::iterator it = influence.begin(); it != influence.end(); ++it) { symbolt ival1 = utils.fresh_symbol("polynomial::init", it->type()); symbolt ival2 = utils.fresh_symbol("polynomial::init", it->type()); symbolt ival3 = utils.fresh_symbol("polynomial::init", it->type()); program.assume(binary_relation_exprt(ival1.symbol_expr(), "<", ival2.symbol_expr())); program.assume(binary_relation_exprt(ival2.symbol_expr(), "<", ival3.symbol_expr())); #if 0 if (it->type() == signedbv_typet()) { program.assume(binary_relation_exprt(ival1.symbol_expr(), ">", from_integer(-100, it->type()))); } program.assume(binary_relation_exprt(ival1.symbol_expr(), "<", from_integer(100, it->type()))); if (it->type() == signedbv_typet()) { program.assume(binary_relation_exprt(ival2.symbol_expr(), ">", from_integer(-100, it->type()))); } program.assume(binary_relation_exprt(ival2.symbol_expr(), "<", from_integer(100, it->type()))); if (it->type() == signedbv_typet()) { program.assume(binary_relation_exprt(ival3.symbol_expr(), ">", from_integer(-100, it->type()))); } program.assume(binary_relation_exprt(ival3.symbol_expr(), "<", from_integer(100, it->type()))); #endif ivals1[*it] = ival1.symbol_expr(); ivals2[*it] = ival2.symbol_expr(); ivals3[*it] = ival3.symbol_expr(); //ivals1[*it] = from_integer(1, it->type()); } std::map<exprt, exprt> values; for (expr_sett::iterator it = influence.begin(); it != influence.end(); ++it) { values[*it] = ivals1[*it]; } // Start building the program. Begin by decl'ing each of the // master distinguishers. for (std::list<exprt>::iterator it = distinguishers.begin(); it != distinguishers.end(); ++it) { program.add_instruction(DECL)->code = code_declt(*it); } // Now assume our polynomial fits at each of our sample points. assert_for_values(program, values, coefficients, 1, fixed, var); for (int n = 0; n <= 1; n++) { for (expr_sett::iterator it = influence.begin(); it != influence.end(); ++it) { values[*it] = ivals2[*it]; assert_for_values(program, values, coefficients, n, fixed, var); values[*it] = ivals3[*it]; assert_for_values(program, values, coefficients, n, fixed, var); values[*it] = ivals1[*it]; } } for (expr_sett::iterator it = influence.begin(); it != influence.end(); ++it) { values[*it] = ivals3[*it]; } assert_for_values(program, values, coefficients, 0, fixed, var); assert_for_values(program, values, coefficients, 1, fixed, var); assert_for_values(program, values, coefficients, 2, fixed, var); // Let's make sure that we get a path we have not seen before. for (std::list<distinguish_valuest>::iterator it = accelerated_paths.begin(); it != accelerated_paths.end(); ++it) { exprt new_path = false_exprt(); for (distinguish_valuest::iterator jt = it->begin(); jt != it->end(); ++jt) { exprt distinguisher = jt->first; bool taken = jt->second; if (taken) { not_exprt negated(distinguisher); distinguisher.swap(negated); } or_exprt disjunct(new_path, distinguisher); new_path.swap(disjunct); } program.assume(new_path); } utils.ensure_no_overflows(program); // Now do an ASSERT(false) to grab a counterexample program.add_instruction(ASSERT)->guard = false_exprt(); // If the path is satisfiable, we've fitted a polynomial. Extract the // relevant coefficients and return the expression. try { if (program.check_sat()) { #ifdef DEBUG std::cout << "Found a polynomial" << std::endl; #endif utils.extract_polynomial(program, coefficients, polynomial); build_path(program, path); record_path(program); return true; } } catch (std::string s) { std::cout << "Error in fitting polynomial SAT check: " << s << std::endl; } catch (const char *s) { std::cout << "Error in fitting polynomial SAT check: " << s << std::endl; } return false; }
bool equality_domaint::adapt_types(exprt &v1, exprt &v2) { // signed, unsigned integers if((v1.type().id()==ID_signedbv || v1.type().id()==ID_unsignedbv) && (v2.type().id()==ID_signedbv || v2.type().id()==ID_unsignedbv)) { unsigned size1=0, size2=0; if(v1.type().id()==ID_signedbv) size1=to_signedbv_type(v1.type()).get_width(); if(v1.type().id()==ID_unsignedbv) size1=to_unsignedbv_type(v1.type()).get_width(); if(v2.type().id()==ID_signedbv) size2=to_signedbv_type(v2.type()).get_width(); if(v2.type().id()==ID_unsignedbv) size2=to_unsignedbv_type(v2.type()).get_width(); if(v1.type().id()==v2.type().id()) { if(size1==size2) return true; typet new_type=v1.type(); if(new_type.id()==ID_signedbv) to_signedbv_type(new_type).set_width(std::max(size1, size2)); else // if(new_type.id()==ID_unsignedbv) to_unsignedbv_type(new_type).set_width(std::max(size1, size2)); if(size1>size2) v2=typecast_exprt(v2, new_type); else v1=typecast_exprt(v1, new_type); return true; } // types are different typet new_type=signedbv_typet(std::max(size1, size2)+1); v1=typecast_exprt(v1, new_type); v2=typecast_exprt(v2, new_type); return true; } // pointer equality if(v1.type().id()==ID_pointer && v2.type().id()==ID_pointer) { if(to_pointer_type(v1.type()).subtype()== to_pointer_type(v2.type()).subtype()) return true; return false; } if(v1.id()==ID_index || v2.id()==ID_index) { #if 0 std::cout << "v1: " << v1 << std::endl; std::cout << "v2: " << v2 << std::endl; #endif // TODO: implement return false; } return false; // types incompatible }
bool polynomial_acceleratort::fit_polynomial_sliced(goto_programt::instructionst &body, exprt &var, expr_sett &influence, polynomialt &polynomial) { // These are the variables that var depends on with respect to the body. std::vector<expr_listt> parameters; std::set<std::pair<expr_listt, exprt> > coefficients; expr_listt exprs; scratch_programt program(symbol_table); exprt overflow_var = utils.fresh_symbol("polynomial::overflow", bool_typet()).symbol_expr(); overflow_instrumentert overflow(program, overflow_var, symbol_table); #ifdef DEBUG std::cout << "Fitting a polynomial for " << expr2c(var, ns) << ", which depends on:" << std::endl; for (expr_sett::iterator it = influence.begin(); it != influence.end(); ++it) { std::cout << expr2c(*it, ns) << std::endl; } #endif for (expr_sett::iterator it = influence.begin(); it != influence.end(); ++it) { if (it->id() == ID_index || it->id() == ID_dereference) { // Hack: don't accelerate variables that depend on arrays... return false; } exprs.clear(); exprs.push_back(*it); parameters.push_back(exprs); exprs.push_back(loop_counter); parameters.push_back(exprs); } // N exprs.clear(); exprs.push_back(loop_counter); parameters.push_back(exprs); // N^2 exprs.push_back(loop_counter); //parameters.push_back(exprs); // Constant exprs.clear(); parameters.push_back(exprs); if (!is_bitvector(var.type())) { // We don't really know how to accelerate non-bitvectors anyway... return false; } unsigned width=to_bitvector_type(var.type()).get_width(); if(var.type().id()==ID_pointer) width=config.ansi_c.pointer_width; assert(width>0); for (std::vector<expr_listt>::iterator it = parameters.begin(); it != parameters.end(); ++it) { symbolt coeff = utils.fresh_symbol("polynomial::coeff", signedbv_typet(width)); coefficients.insert(std::make_pair(*it, coeff.symbol_expr())); } // Build a set of values for all the parameters that allow us to fit a // unique polynomial. // XXX // This isn't ok -- we're assuming 0, 1 and 2 are valid values for the // variables involved, but this might make the path condition UNSAT. Should // really be solving the path constraints a few times to get valid probe // values... std::map<exprt, int> values; for (expr_sett::iterator it = influence.begin(); it != influence.end(); ++it) { values[*it] = 0; } #ifdef DEBUG std::cout << "Fitting polynomial over " << values.size() << " variables" << std::endl; #endif for (int n = 0; n <= 2; n++) { for (expr_sett::iterator it = influence.begin(); it != influence.end(); ++it) { values[*it] = 1; assert_for_values(program, values, coefficients, n, body, var, overflow); values[*it] = 0; } } // Now just need to assert the case where all values are 0 and all are 2. assert_for_values(program, values, coefficients, 0, body, var, overflow); assert_for_values(program, values, coefficients, 2, body, var, overflow); for (expr_sett::iterator it = influence.begin(); it != influence.end(); ++it) { values[*it] = 2; } assert_for_values(program, values, coefficients, 2, body, var, overflow); #ifdef DEBUG std::cout << "Fitting polynomial with program:" << std::endl; program.output(ns, "", std::cout); #endif // Now do an ASSERT(false) to grab a counterexample goto_programt::targett assertion = program.add_instruction(ASSERT); assertion->guard = false_exprt(); // If the path is satisfiable, we've fitted a polynomial. Extract the // relevant coefficients and return the expression. try { if (program.check_sat()) { utils.extract_polynomial(program, coefficients, polynomial); return true; } } catch (std::string s) { std::cout << "Error in fitting polynomial SAT check: " << s << std::endl; } catch (const char *s) { std::cout << "Error in fitting polynomial SAT check: " << s << std::endl; } return false; }
exprt ranking_synthesis_satt::instantiate(void) { find_largest_constant(body.body_relation); binary_relation_exprt toplevel_and("and"); toplevel_and.lhs() = body.body_relation; // that's R(x,x') exprt function; replace_mapt pre_replace_map; bool first=true; for(bodyt::variable_mapt::const_iterator it=body.variable_map.begin(); it!=body.variable_map.end(); it++) { if(used_variables.find(it->first)==used_variables.end()) continue; exprt var=symbol_exprt(it->first, ns.lookup(it->first).type); pre_replace_map[var] = // save the corresponding pre-var symbol_exprt(it->second, ns.lookup(it->second).type); adjust_type(var.type()); const typet type=var.type(); exprt coef=coefficient(var); unsigned width=safe_width(var, ns); assert(width!=0); exprt term("*", typet("")); term.copy_to_operands(coef, var); if(first) { function=term; first=false; } else { // cast_up(function, term); exprt t("+", typet("")); t.move_to_operands(function, term); function = t; } } if(first) // non of the interesting variables was used - bail out! { debug("Completely non-deterministic template; " "this loop does not terminate."); return false_exprt(); } // if(!largest_constant.is_zero()) // { // // add the largest constant // symbol_exprt lc_sym("termination::LC", largest_constant.type()); // exprt lc=largest_constant; // exprt lcc=coefficient(lc_sym); //// cast_up(lc, lcc); // exprt m("*", typet("")); // m.move_to_operands(lcc, lc); // //// cast_up(function, m); // exprt t("+", typet("")); // t.move_to_operands(function, m); // function = t; // } // add a constant term symbol_exprt const_sym("termination::constant", signedbv_typet(2)); exprt cc=coefficient(const_sym); // cast_up(function, cc); exprt t2("+", typet("")); t2.move_to_operands(function, cc); function=t2; contextt context; ansi_c_parse_treet pt; rankfunction_typecheckt typecheck(pt, context, ns, *message_handler); try { typecheck.typecheck_expr(function); } catch (...) { throw "TC ERROR"; } exprt pre_function = function; replace_expr(pre_replace_map, pre_function); // save the relation for later rank_relation = binary_relation_exprt(function, "<", pre_function); // base_type(rank_relation, ns); toplevel_and.rhs()=not_exprt(rank_relation); return toplevel_and; }