smt_astt smt_convt::overflow_cast(const expr2tc &expr) { // If in integer mode, this is completely pointless. Return false. if (int_encoding) return mk_smt_bool(false); const overflow_cast2t &ocast = to_overflow_cast2t(expr); unsigned int width = ocast.operand->type->get_width(); unsigned int bits = ocast.bits; smt_sortt boolsort = boolean_sort; if (ocast.bits >= width || ocast.bits == 0) { std::cerr << "SMT conversion: overflow-typecast got wrong number of bits" << std::endl; abort(); } // Basically: if it's positive in the first place, ensure all the top bits // are zero. If neg, then all the top are 1's /and/ the next bit, so that // it's considered negative in the next interpretation. constant_int2tc zero(ocast.operand->type, BigInt(0)); lessthan2tc isnegexpr(ocast.operand, zero); smt_astt isneg = convert_ast(isnegexpr); smt_astt orig_val = convert_ast(ocast.operand); // Difference bits unsigned int pos_zero_bits = width - bits; unsigned int neg_one_bits = (width - bits) + 1; smt_sortt pos_zero_bits_sort = mk_sort(SMT_SORT_BV, pos_zero_bits, false); smt_sortt neg_one_bits_sort = mk_sort(SMT_SORT_BV, neg_one_bits, false); smt_astt pos_bits = mk_smt_bvint(BigInt(0), false, pos_zero_bits); smt_astt neg_bits = mk_smt_bvint(BigInt((1 << neg_one_bits) - 1), false, neg_one_bits); smt_astt pos_sel = mk_extract(orig_val, width - 1, width - pos_zero_bits, pos_zero_bits_sort); smt_astt neg_sel = mk_extract(orig_val, width - 1, width - neg_one_bits, neg_one_bits_sort); smt_astt pos_eq = mk_func_app(boolsort, SMT_FUNC_EQ, pos_bits, pos_sel); smt_astt neg_eq = mk_func_app(boolsort, SMT_FUNC_EQ, neg_bits, neg_sel); // isneg -> neg_eq, !isneg -> pos_eq smt_astt notisneg = mk_func_app(boolsort, SMT_FUNC_NOT, &isneg, 1); smt_astt c1 = mk_func_app(boolsort, SMT_FUNC_IMPLIES, isneg, neg_eq); smt_astt c2 = mk_func_app(boolsort, SMT_FUNC_IMPLIES, notisneg, pos_eq); smt_astt nooverflow = mk_func_app(boolsort, SMT_FUNC_AND, c1, c2); return mk_func_app(boolsort, SMT_FUNC_NOT, &nooverflow, 1); }
sort * array_decl_plugin::mk_sort(decl_kind k, unsigned num_parameters, parameter const * parameters) { if (k == _SET_SORT) { if (num_parameters != 1) { m_manager->raise_exception("invalid array sort definition, invalid number of parameters"); return 0; } parameter params[2] = { parameters[0], parameter(m_manager->mk_bool_sort()) }; return mk_sort(ARRAY_SORT, 2, params); } SASSERT(k == ARRAY_SORT); if (num_parameters < 2) { m_manager->raise_exception("invalid array sort definition, invalid number of parameters"); return 0; } for (unsigned i = 0; i < num_parameters; i++) { if (!parameters[i].is_ast() || !is_sort(parameters[i].get_ast())) { m_manager->raise_exception("invalid array sort definition, parameter is not a sort"); return 0; } } sort * range = to_sort(parameters[num_parameters - 1].get_ast()); TRACE("array_decl_plugin_bug", tout << mk_pp(range, *m_manager) << "\n";);
smt_astt smt_convt::overflow_arith(const expr2tc &expr) { // If in integer mode, this is completely pointless. Return false. if (int_encoding) return mk_smt_bool(false); const overflow2t &overflow = to_overflow2t(expr); const arith_2ops &opers = static_cast<const arith_2ops &>(*overflow.operand); assert(opers.side_1->type == opers.side_2->type); constant_int2tc zero(opers.side_1->type, BigInt(0)); lessthan2tc op1neg(opers.side_1, zero); lessthan2tc op2neg(opers.side_2, zero); equality2tc op1iszero(opers.side_1, zero); equality2tc op2iszero(opers.side_2, zero); or2tc containszero(op1iszero, op2iszero); // Guess whether we're performing a signed or unsigned comparison. bool is_signed = (is_signedbv_type(opers.side_1) || is_signedbv_type(opers.side_2)); if (is_add2t(overflow.operand)) { if (is_signed) { // Two cases: pos/pos, and neg/neg, which can over and underflow resp. // In pos/neg cases, no overflow or underflow is possible, for any value. constant_int2tc zero(opers.side_1->type, BigInt(0)); lessthan2tc op1pos(zero, opers.side_1); lessthan2tc op2pos(zero, opers.side_2); and2tc both_pos(op1pos, op2pos); not2tc negop1(op1pos); not2tc negop2(op2pos); and2tc both_neg(negop1, negop2); implies2tc nooverflow(both_pos, greaterthanequal2tc(overflow.operand, zero)); implies2tc nounderflow(both_neg, lessthanequal2tc(overflow.operand, zero)); return convert_ast(not2tc(and2tc(nooverflow, nounderflow))); } else { // Just ensure the result is >= both operands. greaterthanequal2tc ge1(overflow.operand, opers.side_1); greaterthanequal2tc ge2(overflow.operand, opers.side_2); and2tc res(ge1, ge2); not2tc inv(res); return convert_ast(inv); } } else if (is_sub2t(overflow.operand)) { if (is_signed) { // Convert to be an addition neg2tc negop2(opers.side_2->type, opers.side_2); add2tc anadd(opers.side_1->type, opers.side_1, negop2); expr2tc add_overflows(new overflow2t(anadd)); // Corner case: subtracting MIN_INT from many things overflows. The result // should always be positive. constant_int2tc zero(opers.side_1->type, BigInt(0)); uint64_t topbit = 1ULL << (opers.side_1->type->get_width() - 1); constant_int2tc min_int(opers.side_1->type, BigInt(topbit)); equality2tc is_min_int(min_int, opers.side_2); implies2tc imp(is_min_int, greaterthan2tc(overflow.operand, zero)); return convert_ast(or2tc(add_overflows, is_min_int)); } else { // Just ensure the result is >= the operands. lessthanequal2tc le1(overflow.operand, opers.side_1); lessthanequal2tc le2(overflow.operand, opers.side_2); and2tc res(le1, le2); not2tc inv(res); return convert_ast(inv); } } else { assert(is_mul2t(overflow.operand) && "unexpected overflow_arith operand"); // Zero extend; multiply; Make a decision based on the top half. unsigned int sz = zero->type->get_width(); smt_sortt boolsort = boolean_sort; smt_sortt normalsort = mk_sort(SMT_SORT_BV, sz, false); smt_sortt bigsort = mk_sort(SMT_SORT_BV, sz * 2, false); // All one bit vector is tricky, might be 64 bits wide for all we know. constant_int2tc allonesexpr(zero->type, BigInt((sz == 64) ? 0xFFFFFFFFFFFFFFFFULL : ((1ULL << sz) - 1))); smt_astt allonesvector = convert_ast(allonesexpr); smt_astt arg1_ext, arg2_ext; if (is_signed) { // sign extend top bits. arg1_ext = convert_ast(opers.side_1); arg1_ext = convert_sign_ext(arg1_ext, bigsort, sz - 1, sz); arg2_ext = convert_ast(opers.side_2); arg2_ext = convert_sign_ext(arg2_ext, bigsort, sz - 1, sz); } else { // Zero extend the top parts arg1_ext = convert_ast(opers.side_1); arg1_ext = convert_zero_ext(arg1_ext, bigsort, sz); arg2_ext = convert_ast(opers.side_2); arg2_ext = convert_zero_ext(arg2_ext, bigsort, sz); } smt_astt result = mk_func_app(bigsort, SMT_FUNC_BVMUL, arg1_ext, arg2_ext); // Extract top half. smt_astt toppart = mk_extract(result, (sz * 2) - 1, sz, normalsort); if (is_signed) { // It should either be zero or all one's; which depends on what // configuration of signs it had. If both pos / both neg, then the top // should all be zeros, otherwise all ones. Implement with xor. smt_astt op1neg_ast = convert_ast(op1neg); smt_astt op2neg_ast = convert_ast(op2neg); smt_astt allonescond = mk_func_app(boolsort, SMT_FUNC_XOR, op1neg_ast, op2neg_ast); smt_astt zerovector = convert_ast(zero); smt_astt initial_switch = mk_func_app(normalsort, SMT_FUNC_ITE, allonescond, allonesvector, zerovector); // either value being zero means the top must be zero. smt_astt contains_zero_ast = convert_ast(containszero); smt_astt second_switch = mk_func_app(normalsort, SMT_FUNC_ITE, contains_zero_ast, zerovector, initial_switch); smt_astt is_eq = mk_func_app(boolsort, SMT_FUNC_EQ, second_switch, toppart); return mk_func_app(boolsort, SMT_FUNC_NOT, &is_eq, 1); } else { // It should be zero; if not, overflow smt_astt iseq = mk_func_app(boolsort, SMT_FUNC_EQ, toppart, convert_ast(zero)); return mk_func_app(boolsort, SMT_FUNC_NOT, &iseq, 1); } } return NULL; }
static environment mk_below(environment const & env, name const & n, bool ibelow) { if (!is_recursive_datatype(env, n)) return env; if (is_inductive_predicate(env, n)) return env; inductive::inductive_decls decls = *inductive::is_inductive_decl(env, n); type_checker tc(env); name_generator ngen; unsigned nparams = std::get<1>(decls); declaration ind_decl = env.get(n); declaration rec_decl = env.get(inductive::get_elim_name(n)); unsigned nindices = *inductive::get_num_indices(env, n); unsigned nminors = *inductive::get_num_minor_premises(env, n); unsigned ntypeformers = length(std::get<2>(decls)); level_param_names lps = rec_decl.get_univ_params(); bool is_reflexive = is_reflexive_datatype(tc, n); level lvl = mk_param_univ(head(lps)); levels lvls = param_names_to_levels(tail(lps)); level_param_names blvls; // universe level parameters of ibelow/below level rlvl; // universe level of the resultant type // The arguments of below (ibelow) are the ones in the recursor - minor premises. // The universe we map to is also different (l+1 for below of reflexive types) and (0 fo ibelow). expr ref_type; expr Type_result; if (ibelow) { // we are eliminating to Prop blvls = tail(lps); rlvl = mk_level_zero(); ref_type = instantiate_univ_param(rec_decl.get_type(), param_id(lvl), mk_level_zero()); } else if (is_reflexive) { blvls = lps; rlvl = get_datatype_level(ind_decl.get_type()); // if rlvl is of the form (max 1 l), then rlvl <- l if (is_max(rlvl) && is_one(max_lhs(rlvl))) rlvl = max_rhs(rlvl); rlvl = mk_max(mk_succ(lvl), rlvl); ref_type = instantiate_univ_param(rec_decl.get_type(), param_id(lvl), mk_succ(lvl)); } else { // we can simplify the universe levels for non-reflexive datatypes blvls = lps; rlvl = mk_max(mk_level_one(), lvl); ref_type = rec_decl.get_type(); } Type_result = mk_sort(rlvl); buffer<expr> ref_args; to_telescope(ngen, ref_type, ref_args); if (ref_args.size() != nparams + ntypeformers + nminors + nindices + 1) throw_corrupted(n); // args contains the below/ibelow arguments buffer<expr> args; buffer<name> typeformer_names; // add parameters and typeformers for (unsigned i = 0; i < nparams; i++) args.push_back(ref_args[i]); for (unsigned i = nparams; i < nparams + ntypeformers; i++) { args.push_back(ref_args[i]); typeformer_names.push_back(mlocal_name(ref_args[i])); } // we ignore minor premises in below/ibelow for (unsigned i = nparams + ntypeformers + nminors; i < ref_args.size(); i++) args.push_back(ref_args[i]); // We define below/ibelow using the recursor for this type levels rec_lvls = cons(mk_succ(rlvl), lvls); expr rec = mk_constant(rec_decl.get_name(), rec_lvls); for (unsigned i = 0; i < nparams; i++) rec = mk_app(rec, args[i]); // add type formers for (unsigned i = nparams; i < nparams + ntypeformers; i++) { buffer<expr> targs; to_telescope(ngen, mlocal_type(args[i]), targs); rec = mk_app(rec, Fun(targs, Type_result)); } // add minor premises for (unsigned i = nparams + ntypeformers; i < nparams + ntypeformers + nminors; i++) { expr minor = ref_args[i]; expr minor_type = mlocal_type(minor); buffer<expr> minor_args; minor_type = to_telescope(ngen, minor_type, minor_args); buffer<expr> prod_pairs; for (expr & minor_arg : minor_args) { buffer<expr> minor_arg_args; expr minor_arg_type = to_telescope(tc, mlocal_type(minor_arg), minor_arg_args); if (is_typeformer_app(typeformer_names, minor_arg_type)) { expr fst = mlocal_type(minor_arg); minor_arg = update_mlocal(minor_arg, Pi(minor_arg_args, Type_result)); expr snd = Pi(minor_arg_args, mk_app(minor_arg, minor_arg_args)); prod_pairs.push_back(mk_prod(tc, fst, snd, ibelow)); } } expr new_arg = foldr([&](expr const & a, expr const & b) { return mk_prod(tc, a, b, ibelow); }, [&]() { return mk_unit(rlvl, ibelow); }, prod_pairs.size(), prod_pairs.data()); rec = mk_app(rec, Fun(minor_args, new_arg)); } // add indices and major premise for (unsigned i = nparams + ntypeformers; i < args.size(); i++) { rec = mk_app(rec, args[i]); } name below_name = ibelow ? name{n, "ibelow"} : name{n, "below"}; expr below_type = Pi(args, Type_result); expr below_value = Fun(args, rec); bool use_conv_opt = true; declaration new_d = mk_definition(env, below_name, blvls, below_type, below_value, use_conv_opt); environment new_env = module::add(env, check(env, new_d)); new_env = set_reducible(new_env, below_name, reducible_status::Reducible); if (!ibelow) new_env = add_unfold_hint(new_env, below_name, nparams + nindices + ntypeformers); return add_protected(new_env, below_name); }
expr update_sort(expr const & e, level const & new_level) { if (!is_eqp(sort_level(e), new_level)) return mk_sort(new_level, e.get_tag()); else return e; }
void initialize_expr() { g_dummy = new expr(mk_constant("__expr_for_default_constructor__")); g_default_name = new name("a"); g_Type1 = new expr(mk_sort(mk_level_one())); g_Prop = new expr(mk_sort(mk_level_zero())); }
void test_inductive() { // declare list type lean_exception ex = 0; lean_env env = mk_env(); lean_name l_name = mk_name("l"); lean_univ l = mk_uparam("l"); lean_univ one = mk_one(); lean_univ m1l = mk_max(one, l); lean_expr Typel = mk_sort(l); lean_expr Typem1l = mk_sort(m1l); lean_expr list_type = mk_pi("A", Typel, Typem1l); lean_name list_name = mk_name("list"); lean_expr list = mk_const("list", l); lean_expr v0 = mk_var(0); // nil : Pi (A : Type.{l}), list.{l} A lean_expr list_v0 = mk_app(list, v0); lean_expr nil_type = mk_pi("A", Typel, list_v0); lean_expr nil = mk_local("nil", nil_type); // cons : Pi (A : Type.{l}), A -> list.{l} A -> list.{l} A lean_expr v1 = mk_var(1); lean_expr v2 = mk_var(2); lean_expr list_v2 = mk_app(list, v2); lean_expr list_v1 = mk_app(list, v1); lean_expr cons_type1 = mk_pi("tail", list_v1, list_v2); lean_expr cons_type2 = mk_pi("head", v0, cons_type1); lean_expr cons_type = mk_pi("A", Typel, cons_type2); lean_expr cons = mk_local("cons", cons_type); // lean_list_expr cs1, cs2, list_cs; lean_inductive_type list_ind_type; lean_list_inductive_type li1, list_ind_types; lean_list_name ls1, ls; lean_inductive_decl list_decl; lean_env new_env; check(lean_list_name_mk_nil(&ls1, &ex)); check(lean_list_name_mk_cons(l_name, ls1, &ls, &ex)); check(lean_list_expr_mk_nil(&cs1, &ex)); check(lean_list_expr_mk_cons(nil, cs1, &cs2, &ex)); check(lean_list_expr_mk_cons(cons, cs2, &list_cs, &ex)); check(lean_inductive_type_mk(list_name, list_type, list_cs, &list_ind_type, &ex)); check(lean_list_inductive_type_mk_nil(&li1, &ex)); check(lean_list_inductive_type_mk_cons(list_ind_type, li1, &list_ind_types, &ex)); check(lean_inductive_decl_mk(ls, 1, list_ind_types, &list_decl, &ex)); check(lean_env_add_inductive(env, list_decl, &new_env, &ex)); { unsigned n; lean_inductive_decl d; lean_name cons_name = mk_name("cons"); lean_name r_name; lean_list_inductive_type types; check(lean_env_get_inductive_type_num_indices(new_env, list_name, &n, &ex) && n == 0); check(lean_env_get_inductive_type_num_minor_premises(new_env, list_name, &n, &ex) && n == 2); check(!lean_env_is_inductive_type(env, list_name, &d, &ex)); check(lean_env_is_inductive_type(new_env, list_name, &d, &ex)); check(lean_inductive_decl_get_num_params(d, &n, &ex) && n == 1); check(lean_inductive_decl_get_types(d, &types, &ex)); check(lean_list_inductive_type_is_cons(types)); check(lean_env_is_constructor(new_env, cons_name, &r_name, &ex) && lean_name_eq(list_name, r_name)); lean_inductive_decl_del(d); lean_name_del(cons_name); lean_name_del(r_name); } lean_env_del(env); lean_name_del(list_name); lean_name_del(l_name); lean_univ_del(l); lean_univ_del(one); lean_univ_del(m1l); lean_expr_del(Typel); lean_expr_del(Typem1l); lean_expr_del(list_type); lean_expr_del(list); lean_expr_del(v0); lean_expr_del(list_v0); lean_expr_del(nil_type); lean_expr_del(nil); lean_expr_del(v1); lean_expr_del(v2); lean_expr_del(list_v2); lean_expr_del(list_v1); lean_expr_del(cons_type1); lean_expr_del(cons_type2); lean_expr_del(cons_type); lean_expr_del(cons); lean_list_expr_del(cs1); lean_list_expr_del(cs2); lean_list_expr_del(list_cs); lean_inductive_type_del(list_ind_type); lean_list_inductive_type_del(li1); lean_list_inductive_type_del(list_ind_types); lean_list_name_del(ls1); lean_list_name_del(ls); lean_inductive_decl_del(list_decl); lean_env_del(new_env); }
void test_id() { lean_exception ex; lean_univ l = mk_uparam("l"); lean_env env = mk_env(); lean_expr v0 = mk_var(0); lean_expr v1 = mk_var(1); lean_expr AA = mk_pi("a", v0, v1); lean_expr Type = mk_sort(l); lean_expr id_type = mk_pi("A", Type, AA); lean_expr f = mk_lambda("a", v0, v0); lean_expr id_val = mk_lambda("A", Type, f); lean_name l_name = mk_name("l"); lean_list_name id_ps = mk_unary_name_list(l_name); lean_decl id_def = mk_def("id", id_ps, id_type, id_val); lean_name id_name = mk_name("id"); lean_cert_decl id_cert_def; lean_env new_env; lean_univ zero, one; lean_bool is_lt; check(lean_expr_lt(f, id_val, &is_lt, &ex) && is_lt); check(lean_expr_lt(id_val, f, &is_lt, &ex) && !is_lt); printf("id type: "); print_expr(id_type); printf("id value: "); print_expr(id_val); printf("-------\n"); /* type check definition */ check(lean_decl_check(env, id_def, &id_cert_def, &ex)); /* add certified definition to environment */ check(lean_env_add(env, id_cert_def, &new_env, &ex)); check(!lean_env_contains_decl(env, id_name)); check(lean_env_contains_decl(new_env, id_name)); check(lean_env_for_each_decl(new_env, print_decl_and_del, &ex)); check(lean_univ_mk_zero(&zero, &ex)); check(lean_univ_mk_succ(zero, &one, &ex)); check(lean_univ_lt(zero, one, &is_lt, &ex) && is_lt); check(lean_univ_lt(one, zero, &is_lt, &ex) && !is_lt); { lean_type_checker tc; lean_expr T0 = mk_sort(zero); lean_expr T1 = mk_sort(one); lean_expr id1 = mk_const("id", one); lean_expr id1T1, id1T1T0; lean_expr n1; lean_cnstr_seq s1; check(lean_expr_mk_app(id1, T1, &id1T1, &ex)); check(lean_expr_mk_app(id1T1, T0, &id1T1T0, &ex)); check(lean_type_checker_mk(new_env, &tc, &ex)); printf("WHNF test\n"); print_expr(id1T1T0); check(lean_type_checker_whnf(tc, id1T1T0, &n1, &s1, &ex)); printf("=====>\n"); print_expr(n1); lean_expr_del(n1); lean_cnstr_seq_del(s1); printf("Infer type test\n"); print_expr(id1T1); check(lean_type_checker_infer(tc, id1T1, &n1, &s1, &ex)); printf("=====>\n"); print_expr(n1); lean_expr_del(n1); lean_cnstr_seq_del(s1); lean_type_checker_del(tc); lean_expr_del(T0); lean_expr_del(T1); lean_expr_del(id1); lean_expr_del(id1T1); lean_expr_del(id1T1T0); } lean_univ_del(l); lean_env_del(env); lean_expr_del(v0); lean_expr_del(v1); lean_expr_del(Type); lean_expr_del(AA); lean_expr_del(id_type); lean_expr_del(f); lean_expr_del(id_val); lean_decl_del(id_def); lean_list_name_del(id_ps); lean_name_del(l_name); lean_cert_decl_del(id_cert_def); lean_env_del(new_env); lean_name_del(id_name); lean_univ_del(zero); lean_univ_del(one); }
optional<environment> mk_no_confusion_type(environment const & env, name const & n) { optional<inductive::inductive_decls> decls = inductive::is_inductive_decl(env, n); if (!decls) throw exception(sstream() << "error in 'no_confusion' generation, '" << n << "' is not an inductive datatype"); if (is_inductive_predicate(env, n)) return optional<environment>(); // type is a proposition name_generator ngen; unsigned nparams = std::get<1>(*decls); declaration ind_decl = env.get(n); declaration cases_decl = env.get(name(n, "cases_on")); level_param_names lps = cases_decl.get_univ_params(); level rlvl = mk_param_univ(head(lps)); levels ilvls = param_names_to_levels(tail(lps)); if (length(ilvls) != length(ind_decl.get_univ_params())) return optional<environment>(); // type does not have only a restricted eliminator expr ind_type = instantiate_type_univ_params(ind_decl, ilvls); name eq_name("eq"); name heq_name("heq"); // All inductive datatype parameters and indices are arguments buffer<expr> args; ind_type = to_telescope(ngen, ind_type, args, some(mk_implicit_binder_info())); if (!is_sort(ind_type) || args.size() < nparams) throw_corrupted(n); lean_assert(!(env.impredicative() && is_zero(sort_level(ind_type)))); unsigned nindices = args.size() - nparams; // Create inductive datatype expr I = mk_app(mk_constant(n, ilvls), args); // Add (P : Type) expr P = mk_local(ngen.next(), "P", mk_sort(rlvl), binder_info()); args.push_back(P); // add v1 and v2 elements of the inductive type expr v1 = mk_local(ngen.next(), "v1", I, binder_info()); expr v2 = mk_local(ngen.next(), "v2", I, binder_info()); args.push_back(v1); args.push_back(v2); expr R = mk_sort(rlvl); name no_confusion_type_name{n, "no_confusion_type"}; expr no_confusion_type_type = Pi(args, R); // Create type former buffer<expr> type_former_args; for (unsigned i = nparams; i < nparams + nindices; i++) type_former_args.push_back(args[i]); type_former_args.push_back(v1); expr type_former = Fun(type_former_args, R); // Create cases_on levels clvls = levels(mk_succ(rlvl), ilvls); expr cases_on = mk_app(mk_app(mk_constant(cases_decl.get_name(), clvls), nparams, args.data()), type_former); cases_on = mk_app(cases_on, nindices, args.data() + nparams); expr cases_on1 = mk_app(cases_on, v1); expr cases_on2 = mk_app(cases_on, v2); type_checker tc(env); expr t1 = tc.infer(cases_on1).first; expr t2 = tc.infer(cases_on2).first; buffer<expr> outer_cases_on_args; unsigned idx1 = 0; while (is_pi(t1)) { buffer<expr> minor1_args; expr minor1 = to_telescope(tc, binding_domain(t1), minor1_args); expr curr_t2 = t2; buffer<expr> inner_cases_on_args; unsigned idx2 = 0; while (is_pi(curr_t2)) { buffer<expr> minor2_args; expr minor2 = to_telescope(tc, binding_domain(curr_t2), minor2_args); if (idx1 != idx2) { // infeasible case, constructors do not match inner_cases_on_args.push_back(Fun(minor2_args, P)); } else { if (minor1_args.size() != minor2_args.size()) throw_corrupted(n); buffer<expr> rtype_hyp; // add equalities for (unsigned i = 0; i < minor1_args.size(); i++) { expr lhs = minor1_args[i]; expr rhs = minor2_args[i]; expr lhs_type = mlocal_type(lhs); expr rhs_type = mlocal_type(rhs); level l = sort_level(tc.ensure_type(lhs_type).first); expr h_type; if (tc.is_def_eq(lhs_type, rhs_type).first) { h_type = mk_app(mk_constant(eq_name, to_list(l)), lhs_type, lhs, rhs); } else { h_type = mk_app(mk_constant(heq_name, to_list(l)), lhs_type, lhs, rhs_type, rhs); } rtype_hyp.push_back(mk_local(ngen.next(), local_pp_name(lhs).append_after("_eq"), h_type, binder_info())); } inner_cases_on_args.push_back(Fun(minor2_args, mk_arrow(Pi(rtype_hyp, P), P))); } idx2++; curr_t2 = binding_body(curr_t2); } outer_cases_on_args.push_back(Fun(minor1_args, mk_app(cases_on2, inner_cases_on_args))); idx1++; t1 = binding_body(t1); } expr no_confusion_type_value = Fun(args, mk_app(cases_on1, outer_cases_on_args)); bool opaque = false; bool use_conv_opt = true; declaration new_d = mk_definition(env, no_confusion_type_name, lps, no_confusion_type_type, no_confusion_type_value, opaque, ind_decl.get_module_idx(), use_conv_opt); environment new_env = module::add(env, check(env, new_d)); return some(add_protected(new_env, no_confusion_type_name)); }
smt_astt smt_convt::convert_byte_update(const expr2tc &expr) { const byte_update2t &data = to_byte_update2t(expr); assert(is_scalar_type(data.source_value) && "Byte update only works on " "scalar variables now"); if (!is_constant_int2t(data.source_offset)) { expr2tc source = data.source_value; unsigned int src_width = source->type->get_width(); if (!is_bv_type(source)) source = typecast2tc(get_uint_type(src_width), source); expr2tc offs = data.source_offset; // Endian-ness: if we're in non-"native" endian-ness mode, then flip the // offset distance. The rest of these calculations will still apply. if (data.big_endian) { auto data_size = type_byte_size(*source->type); constant_int2tc data_size_expr(source->type, data_size - 1); sub2tc sub(source->type, data_size_expr, offs); offs = sub; } if (offs->type->get_width() != src_width) offs = typecast2tc(get_uint_type(src_width), offs); expr2tc update = data.update_value; if (update->type->get_width() != src_width) update = typecast2tc(get_uint_type(src_width), update); // The approach: mask, shift and or. XXX, byte order? // Massively inefficient. expr2tc eight = constant_int2tc(get_uint_type(src_width), BigInt(8)); expr2tc effs = constant_int2tc(eight->type, BigInt(255)); offs = mul2tc(eight->type, offs, eight); expr2tc shl = shl2tc(offs->type, effs, offs); expr2tc noteffs = bitnot2tc(effs->type, shl); source = bitand2tc(source->type, source, noteffs); expr2tc shl2 = shl2tc(offs->type, update, offs); return convert_ast(bitor2tc(offs->type, shl2, source)); } // We are merging two values: an 8 bit update value, and a larger source // value that we will have to merge it into. Start off by collecting // information about the source values and their widths. assert(is_number_type(data.source_value->type) && "Byte update of unsupported data type"); smt_astt value, src_value; unsigned int width_op0, width_op2, src_offset; value = convert_ast(data.update_value); src_value = convert_ast(data.source_value); width_op2 = data.update_value->type->get_width(); width_op0 = data.source_value->type->get_width(); src_offset = to_constant_int2t(data.source_offset).constant_value.to_ulong(); // Flip location if we're in big-endian mode if (data.big_endian) { unsigned int data_size = type_byte_size(*data.source_value->type).to_ulong() - 1; src_offset = data_size - src_offset; } if (int_encoding) { std::cerr << "Can't byte update in integer mode; rerun in bitvector mode" << std::endl; abort(); } // Assertion some of our assumptions, which broadly mean that we'll only work // on bytes that are going into non-byte words assert(width_op2 == 8 && "Can't byte update non-byte operations"); assert(width_op2 != width_op0 && "Can't byte update bytes, sorry"); smt_astt top, middle, bottom; // Build in three parts: the most significant bits, any in the middle, and // the bottom, of the reconstructed / merged output. There might not be a // middle if the update byte is at the top or the bottom. unsigned int top_of_update = (8 * src_offset) + 8; unsigned int bottom_of_update = (8 * src_offset); if (top_of_update == width_op0) { top = value; } else { smt_sortt s = mk_sort(SMT_SORT_BV, width_op0 - top_of_update, false); top = mk_extract(src_value, width_op0 - 1, top_of_update, s); } if (top == value) { middle = NULL; } else { middle = value; } if (src_offset == 0) { middle = NULL; bottom = value; } else { smt_sortt s = mk_sort(SMT_SORT_BV, bottom_of_update, false); bottom = mk_extract(src_value, bottom_of_update - 1, 0, s); } // Concatenate the top and bottom, and possible middle, together. smt_astt concat; if (middle != NULL) { smt_sortt s = mk_sort(SMT_SORT_BV, width_op0 - bottom_of_update, false); concat = mk_func_app(s, SMT_FUNC_CONCAT, top, middle); } else { concat = top; } return mk_func_app(src_value->sort, SMT_FUNC_CONCAT, concat, bottom); }
smt_astt smt_convt::convert_byte_extract(const expr2tc &expr) { const byte_extract2t &data = to_byte_extract2t(expr); assert(is_scalar_type(data.source_value) && "Byte extract now only works on " "scalar variables"); if (!is_constant_int2t(data.source_offset)) { expr2tc source = data.source_value; unsigned int src_width = source->type->get_width(); if (!is_bv_type(source)) { source = typecast2tc(get_uint_type(src_width), source); } // The approach: the argument is now a bitvector. Just shift it the // appropriate amount, according to the source offset, and select out the // bottom byte. expr2tc offs = data.source_offset; // Endian-ness: if we're in non-"native" endian-ness mode, then flip the // offset distance. The rest of these calculations will still apply. if (data.big_endian) { auto data_size = type_byte_size(*source->type); constant_int2tc data_size_expr(source->type, data_size - 1); sub2tc sub(source->type, data_size_expr, offs); offs = sub; } if (offs->type->get_width() != src_width) // Z3 requires these two arguments to be the same width offs = typecast2tc(source->type, data.source_offset); lshr2tc shr(source->type, source, offs); smt_astt ext = convert_ast(shr); smt_astt res = mk_extract(ext, 7, 0, convert_sort(get_uint8_type())); return res; } const constant_int2t &intref = to_constant_int2t(data.source_offset); unsigned width; width = data.source_value->type->get_width(); uint64_t upper, lower; if (!data.big_endian) { upper = ((intref.constant_value.to_long() + 1) * 8) - 1; //((i+1)*w)-1; lower = intref.constant_value.to_long() * 8; //i*w; } else { uint64_t max = width - 1; upper = max - (intref.constant_value.to_long() * 8); //max-(i*w); lower = max - ((intref.constant_value.to_long() + 1) * 8 - 1); //max-((i+1)*w-1); } smt_astt source = convert_ast(data.source_value);; if (int_encoding) { std::cerr << "Refusing to byte extract in integer mode; re-run in " "bitvector mode" << std::endl; abort(); } else { if (is_bv_type(data.source_value)) { ; } else if (is_fixedbv_type(data.source_value)) { ; } else if (is_bool_type(data.source_value)) { // We cdan extract a byte from a bool -- zero or one. typecast2tc cast(get_uint8_type(), data.source_value); source = convert_ast(cast); } else { std::cerr << "Unrecognized type in operand to byte extract." << std::endl; data.dump(); abort(); } unsigned int sort_sz = data.source_value->type->get_width(); if (sort_sz <= upper) { smt_sortt s = mk_sort(SMT_SORT_BV, 8, false); return mk_smt_symbol("out_of_bounds_byte_extract", s); } else { return mk_extract(source, upper, lower, convert_sort(expr->type)); } } }