def check_split_induct (p, restrs, hyps, split, tags = None): """perform both the induction check and a function-call based check on successes which can avoid some problematic inductions.""" ((l_split, (_, l_step), _), (r_split, (_, r_step), _), _, n, _) = split if tags == None: tags = p.pairing.tags err_hyp = check.split_r_err_pc_hyp (p, split, restrs, tags = tags) hyps = [err_hyp] + hyps + check.split_loop_hyps (tags, split, restrs, exit = False) rep = mk_graph_slice (p) if not check.check_split_induct_step_group (rep, restrs, hyps, split, tags = tags): return False l_succs = get_n_offset_successes (rep, l_split, l_step, restrs) r_succs = get_n_offset_successes (rep, r_split, r_step, restrs) if not l_succs: return True hyp = syntax.foldr1 (syntax.mk_and, l_succs) if r_succs: hyp = syntax.mk_implies (foldr1 (syntax.mk_and, r_succs), hyp) return rep.test_hyp_whyps (hyp, hyps)
def setup_split_search (rep, head, restrs, hyps, i_opts, j_opts, unfold_limit = None, tags = None): p = rep.p if not tags: tags = p.pairing.tags if unfold_limit == None: unfold_limit = max ([start + (2 * step) + 1 for (start, step) in i_opts + j_opts]) trace ('Split search at %d, unfold limit %d.' % (head, unfold_limit)) l_tag, r_tag = tags loop_elts = [(n, start, step) for n in p.splittable_points (head) for (start, step) in i_opts] init_to_split = init_loops_to_split (p, restrs) r_to_split = [n for n in init_to_split if p.node_tags[n][0] == r_tag] cand_r_loop_elts = [(n2, start, step) for n in r_to_split for n2 in p.splittable_points (n) for (start, step) in j_opts] err_restrs = restr_others (p, tuple ([(sp, vc_upto (unfold_limit)) for sp in r_to_split]) + restrs, 1) nrerr_pc = mk_not (rep.get_pc (('Err', err_restrs), tag = r_tag)) def get_pc (n, k): head = p.loop_id (n) assert head in init_to_split if n != head: k += 1 restrs2 = restrs + ((head, vc_num (k)), ) return rep.get_pc ((n, restrs2)) for n in r_to_split: get_pc (n, unfold_limit) get_pc (head, unfold_limit) premise = foldr1 (mk_and, [nrerr_pc] + map (rep.interpret_hyp, hyps)) premise = logic.weaken_assert (premise) knowledge = SearchKnowledge (rep, 'search at %d (unfold limit %d)' % (head, unfold_limit), restrs, hyps, tags, (loop_elts, cand_r_loop_elts)) knowledge.premise = premise last_knowledge[0] = knowledge # make sure the representation is in sync rep.test_hyp_whyps (true_term, hyps) # make sure all mem eqs are being tracked mem_vs = [v for v in knowledge.v_ids if v[0].typ == builtinTs['Mem']] for (i, v) in enumerate (mem_vs): for v2 in mem_vs[:i]: for pred in expand_var_eqs (knowledge, (v, v2)): smt_expr (pred, {}, rep.solv) for v in knowledge.v_ids: for pred in expand_var_eqs (knowledge, (v, 'Const')): smt_expr (pred, {}, rep.solv) return knowledge
def get_func_assert (self, n_vc, n_vc2): (pair, l_n_vc, r_n_vc) = self.get_func_pairing (n_vc, n_vc2) (ltag, rtag) = pair.tags (inp_eqs, out_eqs) = pair.eqs (lin, lout, lsucc) = self.funcs[l_n_vc] (rin, rout, rsucc) = self.funcs[r_n_vc] lpc = self.get_pc (l_n_vc) rpc = self.get_pc (r_n_vc) envs = {ltag + '_IN': lin, rtag + '_IN': rin, ltag + '_OUT': lout, rtag + '_OUT': rout} inp_eqs = inst_eqs (inp_eqs, envs, self.solv) out_eqs = inst_eqs (out_eqs, envs, self.solv) succ_imp = mk_implies (rsucc, lsucc) return mk_implies (foldr1 (mk_and, inp_eqs + [rpc]), foldr1 (mk_and, out_eqs + [succ_imp]))
def hyps_add_model (self, hyps, assert_progress = True): if hyps: test_expr = foldr1 (mk_and, hyps) else: # we want to learn something, either a new model, or # that all hyps are true. if there are no hyps, # learning they're all true is learning nothing. # instead force a model test_expr = false_term test_expr = mk_implies (self.premise, test_expr) m = {} (r, _) = self.rep.solv.parallel_check_hyps ([(1, test_expr)], {}, model = m) if r == 'unsat': if not hyps: trace ('WARNING: SearchKnowledge: premise unsat.') trace (" ... learning procedure isn't going to work.") return if assert_progress: assert not (set (hyps) <= self.facts), hyps for hyp in hyps: self.facts.add (hyp) else: assert r == 'sat', r self.add_model (m) if assert_progress: assert self.model_trace[-2:-1] != [m]
def __init__ (self, rep, hyps, vs): self.rep = rep self.hyps = hyps self.v_ids = dict ([(v, 1) for v in vs]) self.model_trace = [] self.facts = set () self.premise = foldr1 (mk_and, map (rep.interpret_hyp, hyps))
def check_pairs (pairs, loops = True, report_mode = False, only_build_problem = False): num_pairs = len (pairs) printout ('Checking %d function pair problems' % len (pairs)) results = [(pair, toplevel_check (pair, check_loops = loops, report = report_mode, count = (i, num_pairs), only_build_problem = only_build_problem)) for (i, pair) in enumerate (pairs)] result_dict = logic.dict_list ([(result_codes[r][1], pair) for (pair, r) in results]) if not only_build_problem: printout ('Results: %s' % [(pair.name, r) for (pair, r) in results]) printout ('Result summary:') success = result_dict.get ('Success', []) if only_build_problem: printout (' - %d problems build' % len (success)) else: printout (' - %d proofs checked' % len (success)) skipped = result_dict.get ('Skipped', []) printout (' - %d proofs skipped' % len (skipped)) fails = [pair.name for pair in result_dict.get ('Failed', [])] print_coverage_report (set (skipped), set (success + fails)) printout (' - failures: %s' % fails) return syntax.foldr1 (comb_results, ['True'] + [r for (_, r) in results])
def check_pairs (pairs, loops = True, report_mode = False): num_pairs = len (pairs) results = [toplevel_check_wname (pair, check_loops = loops, report_mode = report_mode, count = (i, num_pairs)) for (i, pair) in enumerate (pairs)] printout ('Result summary: %s' % results) count = len ([1 for (_, r) in results if r == 'True']) printout (' - %d proofs checked' % count) count = len ([1 for (_, r) in results if r in ['ProofAbort', 'None']]) printout (' - %d proofs skipped' % count) fails = [(nm, r) for (nm, r) in results if r not in ['True', 'ProofAbort', 'None']] printout (' - failures: %s' % fails) return syntax.foldr1 (comb_results, ['True'] + [r for (nm, r) in results])
def mk_align_valid_ineq (typ, p): if typ[0] == 'Type': (_, typ) = typ align = typ.align () size = mk_word32 (typ.size ()) else: assert typ[0] == 'Array', typ (kind, typ, num) = typ align = typ.align () size = mk_times (mk_word32 (typ.size ()), num) assert align in [1, 4, 8] w0 = mk_word32 (0) if align > 1: align_req = [mk_eq (mk_bwand (p, mk_word32 (align - 1)), w0)] else: align_req = [] return foldr1 (mk_and, align_req + [mk_not (mk_eq (p, w0)), mk_implies (mk_less (w0, size), mk_less_eq (p, mk_uminus (size)))])
def get_styp_condition_inner2 (inner_typ, outer_typ): if inner_typ[0] == 'Array' and outer_typ[0] == 'Array': (_, ityp, inum, _) = inner_typ (_, otyp, onum, outer_bound) = outer_typ # array fits in another array if the starting element is # a sub-element, and if the size of the left array plus # the offset fits in the right array cond = get_styp_condition_inner1 (('Type', ityp), outer_typ) isize = array_typ_size (inner_typ) osize = array_typ_size (outer_typ) if outer_bound == 'Strong' and cond: return lambda offs: mk_and (cond (offs), mk_less_eq (mk_plus (isize, offs), osize)) else: return cond elif inner_typ == outer_typ: return lambda offs: mk_eq (offs, mk_word32 (0)) elif outer_typ[0] == 'Type' and outer_typ[1].kind == 'Struct': conds = [(get_styp_condition_inner1 (inner_typ, ('Type', sf_typ)), mk_word32 (offs2)) for (_, offs2, sf_typ) in structs[outer_typ[1].name].fields.itervalues()] conds = [cond for cond in conds if cond[0]] if conds: return lambda offs: foldr1 (mk_or, [c (mk_minus (offs, offs2)) for (c, offs2) in conds]) else: return None elif outer_typ[0] == 'Array': (_, el_typ, n, bound) = outer_typ cond = get_styp_condition_inner1 (inner_typ, ('Type', el_typ)) el_size = mk_word32 (el_typ.size ()) size = mk_times (n, el_size) if bound == 'Strong' and cond: return lambda offs: mk_and (mk_less (offs, size), cond (mk_modulus (offs, el_size))) elif cond: return lambda offs: cond (mk_modulus (offs, el_size)) else: return None else: return None
def add_model (knowledge, preds): (rep, (_, _, _, premise), _, facts) = knowledge if preds: pred_expr = foldr1 (mk_and, preds) else: # we want to learn something, either a new model, or that # all of our predicates are true. if there are no predicates, # ''all our predicates are true'' is trivially true. instead # we must want a model (counterexample of false) pred_expr = false_term m = {} r = rep.solv.check_hyp (mk_implies (premise, pred_expr), {}, model = m) if r == 'unsat': if not preds: trace ('WARNING: unsat with no extra assertions.') trace (" ... learning procedure isn't going to work.") for pred in preds: facts.add (pred) else: assert r == 'sat' update_knowledge_for_model (knowledge, m)
def find_unknown_recursion (p, group, idents, tag, assns, extra_unfolds): from syntax import mk_not, mk_and, foldr1 rep = rep_graph.mk_graph_slice (p, fast = True) for n in p.nodes: if p.nodes[n].kind != 'Call': continue if p.node_tags[n][0] != tag: continue fname = p.nodes[n].fname if fname in extra_unfolds: return n if fname not in group: continue (inp_env, _, _) = rep.get_func (default_n_vc (p, n)) pc = rep.get_pc (default_n_vc (p, n)) new = foldr1 (mk_and, [pc] + [syntax.mk_not ( solver.to_smt_expr (ident, inp_env, rep.solv)) for ident in idents.get (fname, [])]) if rep.test_hyp_whyps (mk_not (new), assns): continue return n return None
def get_styp_condition_inner2 (inner_typ, outer_typ, strict = True): if inner_typ[0] == 'Array' and outer_typ[0] == 'Array': (_, ityp, inum) = inner_typ (_, otyp, onum) = outer_typ # array fits in another array if the starting element is # a sub-element, and for the strictness constraint if it's # no smaller cond = get_styp_condition_inner1 (('Type', ityp), outer_typ) if strict and cond: return lambda offs: mk_and (cond (offs), mk_less_eq (inum, onum)) return cond elif inner_typ == outer_typ: return lambda offs: mk_eq (offs, mk_word32 (0)) elif outer_typ[0] == 'Type' and outer_typ[1].kind == 'Struct': conds = [(get_styp_condition_inner1 (inner_typ, ('Type', sf_typ)), mk_word32 (offs2)) for (_, offs2, sf_typ) in structs[outer_typ[1].name].fields.itervalues()] conds = [cond for cond in conds if cond[0]] if conds: return lambda offs: foldr1 (mk_or, [c (mk_minus (offs, offs2)) for (c, offs2) in conds]) else: return None elif outer_typ[0] == 'Array': (_, el_typ, n) = outer_typ cond = get_styp_condition_inner1 (inner_typ, ('Type', el_typ)) el_size = mk_word32 (el_typ.size ()) size = mk_times (n, el_size) if cond: return lambda offs: mk_and (mk_less (offs, size), cond (mk_modulus (offs, el_size))) else: return None else: return None
def find_unknown_recursion(p, group, idents, tag, assns, extra_unfolds): from syntax import mk_not, mk_and, foldr1 rep = rep_graph.mk_graph_slice(p, fast=True) for n in p.nodes: if p.nodes[n].kind != 'Call': continue if p.node_tags[n][0] != tag: continue fname = p.nodes[n].fname if fname in extra_unfolds: return n if fname not in group: continue (inp_env, _, _) = rep.get_func(default_n_vc(p, n)) pc = rep.get_pc(default_n_vc(p, n)) new = foldr1(mk_and, [pc] + [ syntax.mk_not(solver.to_smt_expr(ident, inp_env, rep.solv)) for ident in idents.get(fname, []) ]) if rep.test_hyp_whyps(mk_not(new), assns): continue return n return None
return mk_plus (p, mk_minus (sz, mk_word32 (1))) def pvalid_assertion1 ((typ, k, p, pv), (typ2, k2, p2, pv2)): """first pointer validity assertion: incompatibility. pvalid1 & pvalid2 --> non-overlapping OR somehow-contained. typ/typ2 is ('Type', syntax.Type) or ('Array', Type, Expr) for dynamically sized arrays. """ offs1 = mk_minus (p, p2) cond1 = get_styp_condition (offs1, typ, typ2, strict = False) offs2 = mk_minus (p2, p) cond2 = get_styp_condition (offs2, typ2, typ, strict = False) out1 = mk_less (end_addr (p, typ), p2) out2 = mk_less (end_addr (p2, typ2), p) return mk_implies (mk_and (pv, pv2), foldr1 (mk_or, [cond1, cond2, out1, out2])) def pvalid_assertion2 ((typ, k, p, pv), (typ2, k2, p2, pv2)): """second pointer validity assertion: implication. pvalid1 & strictly-contained --> pvalid2 """ offs1 = mk_minus (p, p2) cond1 = get_styp_condition (offs1, typ, typ2) imp1 = mk_implies (mk_and (cond1, pv2), pv) offs2 = mk_minus (p2, p) cond2 = get_styp_condition (offs2, typ2, typ) imp2 = mk_implies (mk_and (cond2, pv), pv2) return mk_and (imp1, imp2) def sym_distinct_assertion ((typ, p, pv), (start, end)): out1 = mk_less (mk_plus (p, mk_word32 (typ.size () - 1)), mk_word32 (start))
def compile_accs(replaces, expr): r = compile_const_global_acc(expr) if r: return compile_accs(replaces, r) if expr.kind == 'Field': expr = compile_field_acc(expr.field[0], expr.struct, replaces) return compile_accs(replaces, expr) elif expr.is_op('ArrayIndex'): [arr, n] = expr.vals expr2 = compile_array_acc(n, arr, replaces, False) if expr2: return compile_accs(replaces, expr2) arr = compile_accs(replaces, arr) n = compile_accs(replaces, n) expr2 = compile_array_acc(n, arr, replaces, False) if expr2: return compile_accs(replaces, expr2) else: return mk_arr_index(arr, n) elif (expr.is_op('MemUpdate') and expr.vals[2].is_op('MemAcc') and expr.vals[2].vals[0] == expr.vals[0] and expr.vals[2].vals[1] == expr.vals[1]): # null memory copy. probably created by ops below return compile_accs(replaces, expr.vals[0]) elif (expr.is_op('MemUpdate') and expr.vals[2].kind == 'FieldUpd'): [m, p, f_upd] = expr.vals assert f_upd.typ.kind == 'Struct' (typ, offs, _) = structs[f_upd.typ.name].fields[f_upd.field[0]] assert f_upd.val.typ == typ return compile_accs( replaces, mk_memupd(mk_memupd(m, p, f_upd.struct), mk_plus(p, mk_word32(offs)), f_upd.val)) elif (expr.is_op('MemUpdate') and expr.vals[2].typ.kind == 'Struct'): [m, p, s_val] = expr.vals struct = structs[s_val.typ.name] for (nm, (typ, offs, _)) in struct.fields.iteritems(): f = compile_field_acc(nm, s_val, replaces) assert f.typ == typ m = mk_memupd(m, mk_plus(p, mk_word32(offs)), f) return compile_accs(replaces, m) elif (expr.is_op('MemUpdate') and expr.vals[2].is_op('ArrayUpdate')): [m, p, arr_upd] = expr.vals [arr, i, v] = arr_upd.vals return compile_accs( replaces, mk_memupd(mk_memupd(m, p, arr), mk_arroffs(p, arr.typ, i), v)) elif (expr.is_op('MemUpdate') and expr.vals[2].typ.kind == 'Array'): [m, p, arr] = expr.vals n = arr.typ.num typ = arr.typ.el_typ for i in range(n): offs = i * typ.size() assert offs == i or offs % 4 == 0 e = compile_array_acc(i, arr, replaces) m = mk_memupd(m, mk_plus(p, mk_word32(offs)), e) return compile_accs(replaces, m) elif expr.is_op ('Equals') \ and expr.vals[0].typ.kind in ['Struct', 'Array']: [x, y] = expr.vals assert x.typ == y.typ xs = compile_val_fields(x, replaces) ys = compile_val_fields(y, replaces) eq = foldr1(mk_and, map(mk_eq, xs, ys)) return compile_accs(replaces, eq) elif expr.is_op('PAlignValid'): [typ, p] = expr.vals p = compile_accs(replaces, p) assert typ.kind == 'Type' return logic.mk_align_valid_ineq(('Type', typ.val), p) elif expr.kind == 'Op': vals = [compile_accs(replaces, v) for v in expr.vals] return syntax.adjust_op_vals(expr, vals) elif expr.kind == 'Symbol': return mk_word32(symbols[expr.name][0]) else: if expr.kind not in { 'Var': True, 'ConstGlobal': True, 'Num': True, 'Invent': True, 'Type': True }: print expr assert not 'field acc compiled' return expr
def get_necessary_split_opts (p, head, restrs, hyps, tags = None, iters = None): if not tags: tags = p.pairing.tags [l_tag, r_tag] = tags assert p.node_tags[head][0] == l_tag l_seq_vs = get_interesting_linear_series_exprs (p, head) if not l_seq_vs: return None r_seq_vs = {} for n in init_loops_to_split (p, restrs): if p.node_tags[n][0] == r_tag: vs = get_interesting_linear_series_exprs (p, n) r_seq_vs.update (vs) if not r_seq_vs: return None rep = rep_graph.mk_graph_slice (p, fast = True) def vis (n, i): if n != p.loop_id (n): i = i + 1 return (n, tuple ([(p.loop_id (n), vc_num (i))]) + restrs) smt = lambda expr, n, i: rep.to_smt_expr (expr, vis (n, i)) smt_pc = lambda n, i: rep.get_pc (vis (n, i)) # remove duplicates by concretising l_seq_vs = dict ([(smt (expr, n, 2), (kind, n, expr)) for n in l_seq_vs for (kind, expr) in l_seq_vs[n]]).values () r_seq_vs = dict ([(smt (expr, n, 2), (kind, n, expr)) for n in r_seq_vs for (kind, expr) in r_seq_vs[n]]).values () if iters == None: if [n for n in p.loop_body (head) if p.nodes[n].kind == 'Call']: iters = 5 else: iters = 8 r_seq_end = 1 + 2 * iters l_seq_end = 1 + iters l_seq_ineq = 1 + max ([1 << n for n in range (iters) if 1 << n <= iters]) hyps = hyps + [rep_graph.pc_triv_hyp ((vis (n, r_seq_end), r_tag)) for n in set ([n for (_, n, _) in r_seq_vs])] hyps = hyps + [rep_graph.pc_triv_hyp ((vis (n, l_seq_end), l_tag)) for n in set ([n for (_, n, _) in l_seq_vs])] ex_restrs = [(n, rep_graph.vc_upto (r_seq_end + 1)) for n in set ([p.loop_id (n) for (_, n, _) in r_seq_vs])] hyps = hyps + [check.non_r_err_pc_hyp (tags, restr_others (p, restrs + tuple (ex_restrs), 2))] necessary_split_opts_trace[:] = [] necessary_split_opts_long_trace[:] = [] for (kind, n, expr) in sorted (l_seq_vs): rel_r_seq_vs = [v for v in r_seq_vs if v[0] == kind] if not rel_r_seq_vs: necessary_split_opts_trace.append ((n, 'NoneRelevant')) continue m = {} eq = mk_eq (smt (expr, n, 1), smt (expr, n, l_seq_ineq)) ex_hyps = [rep_graph.pc_true_hyp ((vis (n, i), l_tag)) for i in range (1, l_seq_end + 1)] res = rep.test_hyp_whyps (eq, hyps + ex_hyps, model = m) necessary_split_opts_long_trace.append ((n, eq, hyps + ex_hyps, res, m, smt, smt_pc, (kind, n, expr), r_seq_vs, iters)) if not m: necessary_split_opts_trace.append ((n, None)) continue seq_eq = get_linear_seq_eq (rep, m, smt, smt_pc, (kind, n, expr), r_seq_vs, iters) necessary_split_opts_trace.append ((n, ('Seq', seq_eq))) if not seq_eq: continue ((n2, expr2), (l_start, l_step), (r_start, r_step)) = seq_eq eqs = [rep_graph.eq_hyp ((expr, (vis (n, l_start + (i * l_step)), l_tag)), (expr2, (vis (n2, r_start + (i * r_step)), r_tag))) for i in range (10) if l_start + (i * l_step) <= l_seq_end if r_start + (i * r_step) <= r_seq_end] eq = foldr1 (mk_and, map (rep.interpret_hyp, eqs)) if rep.test_hyp_whyps (eq, hyps): mk_i = lambda i: (l_start + (i * l_step), l_step) mk_j = lambda j: (r_start + (j * r_step), r_step) return [([mk_i (0)], [mk_j (0)]), ([mk_i (0), mk_i (1)], [mk_j (0), mk_j (1)])] n_vcs = entry_path_no_loops (rep, l_tag, m, head) path_hyps = [rep_graph.pc_true_hyp ((n_vc, l_tag)) for n_vc in n_vcs] if rep.test_hyp_whyps (eq, hyps + path_hyps): # immediate case split on difference between entry paths checks = [(hyps, eq_hyp, 'eq') for eq_hyp in eqs] return derive_case_split (rep, n_vcs, checks) necessary_split_opts_trace.append ((n, 'Seq check failed')) return None
return mk_plus (p, mk_minus (sz, mk_word32 (1))) def pvalid_assertion1 ((typ, k, p, pv), (typ2, k2, p2, pv2)): """first pointer validity assertion: incompatibility. pvalid1 & pvalid2 --> non-overlapping OR somehow-contained. typ/typ2 is ('Type', syntax.Type) or ('Array', Type, Expr) for dynamically sized arrays. """ offs1 = mk_minus (p, p2) cond1 = get_styp_condition (offs1, typ, typ2) offs2 = mk_minus (p2, p) cond2 = get_styp_condition (offs2, typ2, typ) out1 = mk_less (end_addr (p, typ), p2) out2 = mk_less (end_addr (p2, typ2), p) return mk_implies (mk_and (pv, pv2), foldr1 (mk_or, [cond1, cond2, out1, out2])) def pvalid_assertion2 ((typ, k, p, pv), (typ2, k2, p2, pv2)): """second pointer validity assertion: implication. pvalid1 & strictly-contained --> pvalid2 """ if typ[0] == 'Array' and typ2[0] == 'Array': # this is such a vague notion it's not worth it return true_term offs1 = mk_minus (p, p2) cond1 = get_styp_condition (offs1, typ, typ2) imp1 = mk_implies (mk_and (cond1, pv2), pv) offs2 = mk_minus (p2, p) cond2 = get_styp_condition (offs2, typ2, typ) imp2 = mk_implies (mk_and (cond2, pv), pv2) return mk_and (imp1, imp2)
def tm_with_word32_list (xs): if xs: return foldr1 (mk_plus, map (mk_word32, xs)) else: return mk_uminus (mk_word32 (0))
def find_split (rep, head, restrs, hyps, i_opts, j_opts, unfold_limit, tags = None): p = rep.p if tags: l_tag, r_tag = tags else: l_tag, r_tag = p.pairing.tags loop_elts = [(n, start, step) for n in p.loop_data[head][1] if p.loop_splittables[n] for (start, step) in i_opts] init_to_split = init_loops_to_split (p, restrs) r_to_split = [n for n in init_to_split if p.node_tags[n][0] == r_tag] cand_r_loop_elts = [(n2, start, step) for n in r_to_split for n2 in p.loop_data[n][1] if p.loop_splittables[n2] for (start, step) in j_opts] err_restrs = restr_others (p, tuple ([(sp, vc_upto (unfold_limit)) for sp in r_to_split]) + restrs, 1) nrerr_pc = mk_not (rep.get_pc (('Err', err_restrs), tag = r_tag)) def get_pc (n, k): head = p.loop_id (n) assert head in init_to_split if n != head: k += 1 restrs2 = restrs + ((head, vc_num (k)), ) return rep.get_pc ((n, restrs2)) for n in r_to_split: get_pc (n, unfold_limit) get_pc (head, unfold_limit) premise = foldr1 (mk_and, [nrerr_pc] + map (rep.interpret_hyp, hyps)) premise = logic.weaken_assert (premise) knowledge = (rep, (restrs, loop_elts, cand_r_loop_elts, premise), init_knowledge_pairs (rep, loop_elts, cand_r_loop_elts), set ()) last_knowledge[0] = knowledge # make sure the representation is in sync rep.test_hyp_whyps (true_term, hyps) # make sure all mem eqs are being tracked (_, _, (pairs, vs), _) = knowledge mem_vs = [v for v in vs if v[0].typ == builtinTs['Mem']] for (i, v) in enumerate (mem_vs): for v2 in mem_vs[:i]: for pred in expand_var_eqs (knowledge, (v, v2)): smt_expr (pred, {}, rep.solv) for v in vs: for pred in expand_var_eqs (knowledge, (v, 'Const')): smt_expr (pred, {}, rep.solv) # start the process with a model add_model (knowledge, [mk_not (get_pc (head, unfold_limit))]) num_eqs = 3 while True: trace ('Search at unfold limit %d' % unfold_limit) trace ('Computing live pairings') pair_eqs = [(pair, mk_pairing_v_eqs (knowledge, pair)) for pair in sorted (pairs) if pairs[pair][0] != 'Failed'] endorsed = [(pair, eqs) for (pair, eqs) in pair_eqs if eqs != None] trace (' ... %d live pairings, %d endorsed' % (len (pair_eqs), len (endorsed))) for (pair, eqs) in endorsed: split = v_eqs_to_split (p, pair, eqs, restrs, hyps, tags = tags) if split == None: pairs[pair] = ('Failed', 'SplitWeak', eqs) continue if check_split_induct (p, restrs, hyps, split, tags = tags): trace ('Tested v_eqs!') return ('Split', split) else: pairs[pair] = ('Failed', 'InductFailed', eqs) u_eqs = unknown_eqs (knowledge, num_eqs) if not u_eqs: trace (('Exhausted split candidates for loop at %d,' + ' unfold limit %d') % (head, unfold_limit)) fails = [it for it in pairs.items () if it[1][0] == 'Failed'] fails10 = fails[:10] trace (' %d of %d failed pairings:' % (len (fails10), len (fails))) last_failed_pairings.append (fails) del last_failed_pairings[:-10] for f in fails: trace (' %s' % (f,)) ind_fails = [it for it in fails if str (it[1][1]) == 'InductFailed'] if ind_fails: trace ( 'Inductive failures!') for f in ind_fails: trace (' %s' % (f,)) return (None, ind_fails) add_model_wrapper (knowledge, u_eqs) num_eqs = 4 - num_eqs # oscillate between 3, 1
def inst_eqs_pattern_exprs (pattern, params): (inp_eqs, out_eqs) = inst_eqs_pattern (pattern, params) return (foldr1 (mk_and, [mk_eq (a, c) for (a, c) in inp_eqs]), foldr1 (mk_and, [mk_eq (a, c) for (a, c) in out_eqs]))
def compile_accs (replaces, expr): r = compile_const_global_acc (expr) if r: return compile_accs (replaces, r) if expr.kind == 'Field': expr = compile_field_acc (expr.field[0], expr.struct, replaces) return compile_accs (replaces, expr) elif expr.is_op ('ArrayIndex'): [arr, n] = expr.vals expr2 = compile_array_acc (n, arr, replaces, False) if expr2: return compile_accs (replaces, expr2) arr = compile_accs (replaces, arr) n = compile_accs (replaces, n) expr2 = compile_array_acc (n, arr, replaces, False) if expr2: return compile_accs (replaces, expr2) else: return mk_arr_index (arr, n) elif (expr.is_op ('MemUpdate') and expr.vals[2].is_op ('MemAcc') and expr.vals[2].vals[0] == expr.vals[0] and expr.vals[2].vals[1] == expr.vals[1]): # null memory copy. probably created by ops below return compile_accs (replaces, expr.vals[0]) elif (expr.is_op ('MemUpdate') and expr.vals[2].kind == 'FieldUpd'): [m, p, f_upd] = expr.vals assert f_upd.typ.kind == 'Struct' (typ, offs, _) = structs[f_upd.typ.name].fields[f_upd.field[0]] assert f_upd.val.typ == typ return compile_accs (replaces, mk_memupd (mk_memupd (m, p, f_upd.struct), mk_plus (p, mk_word32 (offs)), f_upd.val)) elif (expr.is_op ('MemUpdate') and expr.vals[2].typ.kind == 'Struct'): [m, p, s_val] = expr.vals struct = structs[s_val.typ.name] for (nm, (typ, offs, _)) in struct.fields.iteritems (): f = compile_field_acc (nm, s_val, replaces) assert f.typ == typ m = mk_memupd (m, mk_plus (p, mk_word32 (offs)), f) return compile_accs (replaces, m) elif (expr.is_op ('MemUpdate') and expr.vals[2].is_op ('ArrayUpdate')): [m, p, arr_upd] = expr.vals [arr, i, v] = arr_upd.vals return compile_accs (replaces, mk_memupd (mk_memupd (m, p, arr), mk_arroffs (p, arr.typ, i), v)) elif (expr.is_op ('MemUpdate') and expr.vals[2].typ.kind == 'Array'): [m, p, arr] = expr.vals n = arr.typ.num typ = arr.typ.el_typ for i in range (n): offs = i * typ.size () assert offs == i or offs % 4 == 0 e = compile_array_acc (i, arr, replaces) m = mk_memupd (m, mk_plus (p, mk_word32 (offs)), e) return compile_accs (replaces, m) elif expr.is_op ('Equals') \ and expr.vals[0].typ.kind in ['Struct', 'Array']: [x, y] = expr.vals assert x.typ == y.typ xs = compile_val_fields (x, replaces) ys = compile_val_fields (y, replaces) eq = foldr1 (mk_and, map (mk_eq, xs, ys)) return compile_accs (replaces, eq) elif expr.is_op ('PAlignValid'): [typ, p] = expr.vals p = compile_accs (replaces, p) assert typ.kind == 'Type' return logic.mk_align_valid_ineq (('Type', typ.val), p) elif expr.kind == 'Op': vals = [compile_accs (replaces, v) for v in expr.vals] return Expr ('Op', expr.typ, expr.name, vals = vals) elif expr.kind == 'Symbol': return mk_word32 (symbols[expr.name][0]) else: if expr.kind not in {'Var':True, 'ConstGlobal':True, 'Num':True, 'Invent':True, 'Type':True}: print expr assert not 'field acc compiled' return expr