示例#1
0
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
示例#2
0
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
示例#3
0
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
示例#4
0
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
示例#5
0
 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)
示例#6
0
 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)
示例#7
0
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
示例#8
0
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
示例#9
0
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
示例#10
0
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
示例#11
0
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
示例#12
0
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
示例#13
0
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
示例#14
0
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, ())
示例#15
0
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
示例#16
0
	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 ()
示例#17
0
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
示例#18
0
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
示例#19
0
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
示例#20
0
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
示例#21
0
def mk_not_red (v):
	if v.is_op ('Not'):
		[v] = v.vals
		return v
	else:
		return syntax.mk_not (v)
示例#22
0
    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)
示例#23
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
示例#24
0
	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'