def find_split_limit (p, n, restrs, hyps, kind, bound = 51, must_find = True, hints = [], use_rep = None): tag = p.node_tags[n][0] trace ('Finding split limit: %d (%s) %s' % (n, tag, restrs)) trace (' (restrs = %s)' % (restrs, )) trace (' (hyps = %s)' % (hyps, ), push = 1) if use_rep == None: rep = mk_graph_slice (p, fast = True) else: rep = use_rep check_order = hints + [i for i in split_sample_set (bound) if i not in hints] for i in check_order: restrs2 = restrs + ((n, VisitCount (kind, i)), ) pc = rep.get_pc ((n, restrs2)) restrs3 = restr_others (p, restrs2, 2) epc = rep.get_pc (('Err', restrs3), tag = tag) hyp = mk_implies (mk_not (epc), mk_not (pc)) if rep.test_hyp_whyps (hyp, hyps): trace ('split limit found: %d' % i, push = -1) return i trace ('No split limit found for %d (%s).' % (n, tag), push = -1) if must_find: assert not 'split limit found' return None
def tryLoopBound(p_n, p, bounds, rep, restrs=None, hints=None, kind='Number', bin_return=False, hyps=None): if restrs == None: restrs = () if hints == None: hints = [] if hyps == None: hyps = [] tag = p.node_tags[p_n][0] from stack_logic import default_n_vc print 'trying bound: %s' % bounds ret_bounds = [] for (index, i) in enumerate(bounds): print 'testing %d' % i restrs2 = restrs + ((p_n, VisitCount(kind, i)), ) try: pc = rep.get_pc((p_n, restrs2)) except: print 'get_pc failed' if bin_return: return False else: return -1 #print 'got rep_.get_pc' restrs3 = restr_others(p, restrs2, 2) epc = rep.get_pc(('Err', restrs3), tag=tag) hyp = mk_implies(mk_not(epc), mk_not(pc)) hyps = hyps + noHaltHyps(p_n, p) #hyps = [] #print 'calling test_hyp_whyps' if rep.test_hyp_whyps(hyp, hyps): print 'p_n %d: split limit found: %d' % (p_n, i) if bin_return: return True return index if bin_return: return False print 'loop bound not found!' return -1 assert False, 'failed to find loop bound for p_n %d' % p_n
def ident_conds (fname, idents): rolling = syntax.true_term conds = [] for ident in idents.get (fname, [syntax.true_term]): conds.append ((ident, syntax.mk_and (rolling, ident))) rolling = syntax.mk_and (rolling, syntax.mk_not (ident)) return conds
def ident_conds(fname, idents): rolling = syntax.true_term conds = [] for ident in idents.get(fname, [syntax.true_term]): conds.append((ident, syntax.mk_and(rolling, ident))) rolling = syntax.mk_and(rolling, syntax.mk_not(ident)) return conds
def test(n): assert n > 10 hyp = check.mk_loop_counter_eq_hyp(p, split, restrs, n - 2) visit = ((split, vc_offs(2)), ) + restrs continue_to_split_guess = rep.get_pc((split, visit)) return rep.test_hyp_whyps(syntax.mk_not(continue_to_split_guess), [hyp] + l_hyps + hyps)
def test (n): assert n > 10 hyp = get_induct_eq_hyp (p, split, restrs, n - 2) visit = ((split, vc_offs (2)), ) + restrs continue_to_split_guess = rep.get_pc ((split, visit)) return rep.test_hyp_whyps (syntax.mk_not (continue_to_split_guess), [hyp] + l_hyps + 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_proof_visit_restr (p, sp, restrs, hyps, kind, must_find = False): rep = rep_graph.mk_graph_slice (p) pc = rep.get_pc ((sp, restrs)) if rep.test_hyp_whyps (pc, hyps): return (1, 2) elif rep.test_hyp_whyps (mk_not (pc), hyps): return (0, 1) else: assert not must_find return None
def loop_no_match_unroll (rep, restrs, hyps, split, other_tag, unroll): p = rep.p assert p.node_tags[split][0] != other_tag restr = ((split, vc_num (unroll)), ) restrs2 = restr_others (p, restr + restrs, 2) loop_cond = rep.get_pc ((split, restr + restrs)) ret_cond = rep.get_pc (('Ret', restrs2), tag = other_tag) # loop should be reachable if rep.test_hyp_whyps (mk_not (loop_cond), hyps): trace ('Loop weak at %d (unroll count %d).' % (split, unroll)) return True # reaching the loop should imply reaching a loop on the other side hyp = mk_not (mk_and (loop_cond, ret_cond)) if not rep.test_hyp_whyps (hyp, hyps): trace ('Loop independent at %d (unroll count %d).' % (split, unroll)) return True return False
def simplify_expr_whyps(sexpr, rep, hyps, cache=None, extra_defs={}, bool_hyps=None): if cache == None: cache = {} if bool_hyps == None: bool_hyps = [] if sexpr in extra_defs: sexpr = extra_defs[sexpr] if sexpr in rep.solv.defs: sexpr = rep.solv.defs[sexpr] if sexpr[0] == 'ite': (_, cond, x, y) = sexpr cond_exp = solver.mk_smt_expr(solver.flat_s_expression(cond), syntax.boolT) (mk_nimp, mk_not) = (syntax.mk_n_implies, syntax.mk_not) if rep.test_hyp_whyps(mk_nimp(bool_hyps, cond_exp), hyps, cache=cache): return x elif rep.test_hyp_whyps(mk_nimp(bool_hyps, mk_not(cond_exp)), hyps, cache=cache): return y x = simplify_expr_whyps(x, rep, hyps, cache=cache, extra_defs=extra_defs, bool_hyps=bool_hyps + [cond_exp]) y = simplify_expr_whyps(y, rep, hyps, cache=cache, extra_defs=extra_defs, bool_hyps=bool_hyps + [syntax.mk_not(cond_exp)]) if x == y: return x return ('ite', cond, x, y) return sexpr
def strengthen_hyp (expr, sign = 1): if not expr.kind == 'Op': return expr if expr.name in ['And', 'Or']: vals = [strengthen_hyp (v, sign) for v in expr.vals] return syntax.Expr ('Op', expr.typ, name = expr.name, vals = vals) elif expr.name == 'Implies': [l, r] = expr.vals l = strengthen_hyp (l, - sign) r = strengthen_hyp (r, sign) return syntax.mk_implies (l, r) elif expr.name == 'Not': [x] = expr.vals x = strengthen_hyp (x, - sign) return syntax.mk_not (x) elif expr.name == 'StackEquals': if sign == 1: return syntax.Expr ('Op', boolT, name = 'ImpliesStackEquals', vals = expr.vals) else: return syntax.Expr ('Op', boolT, name = 'StackEqualsImplies', vals = expr.vals) elif expr.name == 'ROData': if sign == 1: return syntax.Expr ('Op', boolT, name = 'ImpliesROData', vals = expr.vals) else: return expr elif expr.name == 'Equals' and expr.vals[0].typ == boolT: vals = expr.vals if vals[1] in [syntax.true_term, syntax.false_term]: vals = [vals[1], vals[0]] if vals[0] == syntax.true_term: return strengthen_hyp (vals[1], sign) elif vals[0] == syntax.false_term: return strengthen_hyp (syntax.mk_not (vals[1]), sign) else: return expr else: return expr
def tryLoopBound(p_n, p, bounds, rep, restrs=None, hints=None, kind="Number", bin_return=False, hyps=None): if restrs == None: restrs = () if hints == None: hints = [] if hyps == None: hyps = [] tag = p.node_tags[p_n][0] from stack_logic import default_n_vc print "trying bound: %s" % bounds ret_bounds = [] for (index, i) in enumerate(bounds): print "testing %d" % i restrs2 = restrs + ((p_n, VisitCount(kind, i)),) try: pc = rep.get_pc((p_n, restrs2)) except: print "get_pc failed" if bin_return: return False else: return -1 # print 'got rep_.get_pc' restrs3 = restr_others(p, restrs2, 2) epc = rep.get_pc(("Err", restrs3), tag=tag) hyp = mk_implies(mk_not(epc), mk_not(pc)) hyps = hyps + noHaltHyps(p_n, p) # hyps = [] # print 'calling test_hyp_whyps' if rep.test_hyp_whyps(hyp, hyps): print "p_n %d: split limit found: %d" % (p_n, i) if bin_return: return True return index if bin_return: return False print "loop bound not found!" return -1 assert False, "failed to find loop bound for p_n %d" % p_n
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 find_case_split (p, head, restrs, hyps, tags = None): # are there multiple paths to the loop head 'head' and can we # restrict to one of them? preds = set () frontier = list (set ([n2 for n in p.loop_body (head) for n2 in p.preds[n] if p.loop_id (n2) != head])) while frontier: n2 = frontier.pop () if n2 in preds: continue preds.add (n2) frontier.extend (p.preds[n2]) divs = [n2 for n2 in preds if len (set ([n3 for n3 in p.nodes[n2].get_conts () if n3 in preds or n3 == head])) > 1 if n2 not in p.loop_data] trace ('find_case_split: possible divs %s.' % divs) rep = mk_graph_slice (p) err_restrs = restr_others (p, restrs, 2) if tags: l_tag, r_tag = tags else: l_tag, r_tag = p.pairing.tags hvis_restrs = tuple ([(head, rep_graph.vc_num (0))]) + restrs lhyps = hyps + [rep_graph.pc_false_hyp ((('Err', err_restrs), r_tag)), rep_graph.pc_true_hyp (((head, hvis_restrs), p.node_tags[head][0]))] # for this to be a usable case split, both paths must be possible for div in divs: dhyps = lhyps + [rep_graph.pc_true_hyp (((div, restrs), p.node_tags[div][0]))] assert p.nodes[div].kind == 'Cond' (_, env) = rep.get_node_pc_env ((div, restrs)) c = to_smt_expr (p.nodes[div].cond, env, rep.solv) if (rep.test_hyp_whyps (c, dhyps) or rep.test_hyp_whyps (mk_not (c), dhyps)): continue trace ("attempting case split at %d" % div) sides = [n for n in p.nodes[div].get_conts () if n not in p.loop_data if p.preds[n] == [div]] if not sides: trace ("skipping case split, no notable succ") n = sides[0] return ('CaseSplit', (n, p.node_tags[n][0])) trace ('find_case_split: no case splits possible') 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
def try_inline (self, n, pc, env): if not self.inliner: return False inline = self.inliner ((self.p, n)) if not inline: return False # make sure this node is reachable before inlining if self.solv.test_hyp (mk_not (pc), env): trace ('Skipped inlining at %d.' % n) return False trace ('Inlining at %d.' % n) inline () raise InlineEvent ()
def ident_callables (fname, callees, idents): from solver import to_smt_expr, smt_expr from syntax import mk_not, mk_and, true_term auto_callables = dict ([((ident, f, true_term), True) for ident in idents.get (fname, [true_term]) for f in callees if f not in idents]) if not [f for f in callees if f in idents]: return auto_callables fun = functions[fname] p = fun.as_problem (problem.Problem, name = 'Target') check_ns = [(n, ident, cond) for n in p.nodes if p.nodes[n].kind == 'Call' if p.nodes[n].fname in idents for (ident, cond) in ident_conds (p.nodes[n].fname, idents)] p.do_analysis () assert check_ns rep = rep_graph.mk_graph_slice (p, fast = True) err_hyp = rep_graph.pc_false_hyp ((default_n_vc (p, 'Err'), 'Target')) callables = auto_callables nhyps = mk_not_callable_hyps (p) for (ident, cond) in ident_conds (fname, idents): renames = p.entry_exit_renames (tags = ['Target']) cond = syntax.rename_expr (cond, renames['Target_IN']) entry = p.get_entry ('Target') e_vis = ((entry, ()), 'Target') hyps = [err_hyp, rep_graph.eq_hyp ((cond, e_vis), (true_term, e_vis))] for (n, ident2, cond2) in check_ns: k = (ident, p.nodes[n].fname, ident2) (inp_env, _, _) = rep.get_func (default_n_vc (p, n)) pc = rep.get_pc (default_n_vc (p, n)) cond2 = to_smt_expr (cond2, inp_env, rep.solv) if rep.test_hyp_whyps (mk_not (mk_and (pc, cond2)), hyps + nhyps): callables[k] = False else: callables[k] = True return callables
def ident_callables(fname, callees, idents): from solver import to_smt_expr, smt_expr from syntax import mk_not, mk_and, true_term auto_callables = dict([((ident, f, true_term), True) for ident in idents.get(fname, [true_term]) for f in callees if f not in idents]) if not [f for f in callees if f in idents]: return auto_callables fun = functions[fname] p = fun.as_problem(problem.Problem, name='Target') check_ns = [(n, ident, cond) for n in p.nodes if p.nodes[n].kind == 'Call' if p.nodes[n].fname in idents for (ident, cond) in ident_conds(p.nodes[n].fname, idents)] p.do_analysis() assert check_ns rep = rep_graph.mk_graph_slice(p, fast=True) err_hyp = rep_graph.pc_false_hyp((default_n_vc(p, 'Err'), 'Target')) callables = auto_callables nhyps = mk_not_callable_hyps(p) for (ident, cond) in ident_conds(fname, idents): renames = p.entry_exit_renames(tags=['Target']) cond = syntax.rename_expr(cond, renames['Target_IN']) entry = p.get_entry('Target') e_vis = ((entry, ()), 'Target') hyps = [err_hyp, rep_graph.eq_hyp((cond, e_vis), (true_term, e_vis))] for (n, ident2, cond2) in check_ns: k = (ident, p.nodes[n].fname, ident2) (inp_env, _, _) = rep.get_func(default_n_vc(p, n)) pc = rep.get_pc(default_n_vc(p, n)) cond2 = to_smt_expr(cond2, inp_env, rep.solv) if rep.test_hyp_whyps(mk_not(mk_and(pc, cond2)), hyps + nhyps): callables[k] = False else: callables[k] = True return callables
def simplify_expr_whyps (sexpr, rep, hyps, cache = None, extra_defs = {}): if cache == None: cache = {} if sexpr in extra_defs: sexpr = extra_defs[sexpr] if sexpr[0] == 'ite': (_, cond, x, y) = sexpr cond_exp = solver.mk_smt_expr (solver.flat_s_expression (cond), syntax.boolT) if rep.test_hyp_whyps (cond_exp, hyps, cache = cache): return x elif rep.test_hyp_whyps (syntax.mk_not (cond_exp), hyps, cache = cache): return y x = simplify_expr_whyps (x, rep, hyps, cache = cache, extra_defs = extra_defs) y = simplify_expr_whyps (y, rep, hyps, cache = cache, extra_defs = extra_defs) if x == y: return x return ('ite', cond, x, y) return sexpr
def init_proof_case_split (p, restrs, hyps): ps = init_case_splits (p, hyps) if ps == None: return None p.cached_analysis.setdefault ('finished_init_case_splits', []) fin = p.cached_analysis['finished_init_case_splits'] known_s = set.union (set (restrs), set (hyps)) for rs in fin: if rs <= known_s: return None rep = rep_graph.mk_graph_slice (p) no_loop_restrs = tuple ([(n, vc_num (0)) for n in p.loop_heads ()]) err_pc_hyps = [rep_graph.pc_false_hyp ((('Err', no_loop_restrs), tag)) for tag in p.pairing.tags] for (n1, n2) in ps: pc = rep.get_pc ((n1, ())) if rep.test_hyp_whyps (pc, hyps + err_pc_hyps): continue if rep.test_hyp_whyps (mk_not (pc), hyps + err_pc_hyps): continue case_split_tr.append ((n1, restrs, hyps)) return ('CaseSplit', ((n1, p.node_tags[n1][0]), [n1, n2])) fin.append (known_s) return None
def mk_not_red (v): if v.is_op ('Not'): [v] = v.vals return v else: return syntax.mk_not (v)
p = rep.p tag = p.node_tags[n][0] is_C = tag == 'C' or p.hook_tag_hints.get(tag, None) == 'C' if not is_C: return upd_ps = [ rep.to_smt_expr(ptr, (n, vc)) for (kind, ptr, v, m) in p.nodes[n].get_mem_accesses() if kind == 'MemUpdate' ] if not upd_ps: return cache = get_cache(p) for ptr in set(upd_ps): pc = rep.get_pc((n, vc)) eq_rodata = rep.solv.get_eq_rodata_witness(ptr) hyp = rep.to_smt_expr(syntax.mk_implies(pc, syntax.mk_not(eq_rodata)), (n, vc)) if ((n, vc), ptr) in cache: res = cache[((n, vc), ptr)] else: res = rep.test_hyp_whyps(hyp, [], cache=cache) cache[((n, vc), ptr)] = res if res: rep.solv.assert_fact(hyp, {}) module_hook_k = 'c_rodata' target_objects.add_hook('post_emit_node', module_hook_k, hook) target_objects.use_hooks.add(module_hook_k)
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 emit_node (self, n): (pc, env) = self.get_node_pc_env (n, request = False) tag = self.p.node_tags[n[0]][0] app_eqs = self.apply_known_eqs_tm (n, tag) # node = logic.simplify_node_elementary (self.p.nodes[n[0]]) # whether to ignore unreachable Cond arcs seems to be a huge # dilemma. if we ignore them, some reachable sites become # unreachable and we can't interpret all hyps # if we don't ignore them, the variable set disagrees with # var_deps and so the abstracted loop pc/env may not be # sufficient and we get EnvMiss again. I don't really know # what to do about this corner case. node = self.p.nodes[n[0]] env = dict (env) if node.kind == 'Call': self.try_inline (n[0], pc, env) if pc == false_term: return [(c, false_term, {}) for c in node.get_conts()] elif node.kind == 'Cond' and node.left == node.right: return [(node.left, pc, env)] elif node.kind == 'Cond' and node.cond == true_term: return [(node.left, pc, env), (node.right, false_term, env)] elif node.kind == 'Basic': upds = [] for (lv, v) in node.upds: if v.kind == 'Var': upds.append ((lv, env[(v.name, v.typ)])) else: name = self.local_name (lv[0], n) v = app_eqs (v) vname = self.add_local_def (n, ('Var', lv), name, v, env) upds.append ((lv, vname)) for (lv, v) in upds: env[lv] = v return [(node.cont, pc, env)] elif node.kind == 'Cond': name = self.cond_name (n) cond = self.p.fresh_var (name, boolT) env[(cond.name, boolT)] = self.add_local_def (n, 'Cond', name, app_eqs (node.cond), env) lpc = mk_and (cond, pc) rpc = mk_and (mk_not (cond), pc) return [(node.left, lpc, env), (node.right, rpc, env)] elif node.kind == 'Call': nm = self.success_name (node.fname, n) success = self.solv.add_var (nm, boolT) success = mk_smt_expr (success, boolT) fun = functions[node.fname] ins = dict ([((x, typ), smt_expr (app_eqs (arg), env, self.solv)) for ((x, typ), arg) in azip (fun.inputs, node.args)]) mem_name = None for (x, typ) in reversed (fun.inputs): if typ == builtinTs['Mem']: mem_name = (node.fname, ins[(x, typ)]) outs = {} for ((x, typ), (y, typ2)) in azip (node.rets, fun.outputs): assert typ2 == typ if self.fast_const_ret (n[0], x, typ): outs[(y, typ2)] = env [(x, typ)] continue name = self.local_name (x, n) env[(x, typ)] = self.solv.add_var_restr (name, typ, mem_name = mem_name) outs[(y, typ2)] = env[(x, typ)] for ((x, typ), (y, _)) in azip (node.rets, fun.outputs): z = self.var_rep_request ((x, typ), 'Call', n, env) if z != None: env[(x, typ)] = z outs[(y, typ)] = z self.add_func (node.fname, ins, outs, success, n) return [(node.cont, pc, env)] else: assert not 'node kind understood'