Exemple #1
0
def inline_at_point(p, n, do_analysis=True):
    node = p.nodes[n]
    if node.kind != 'Call':
        return

    f_nm = node.fname
    fun = functions[f_nm]
    (tag, detail) = p.node_tags[n]
    idx = p.node_tag_revs[(tag, detail)].index(n)
    p.inline_scripts[tag].append((detail, idx, f_nm))

    trace('Inlining %s into %s' % (f_nm, p.name))
    if n in p.loop_data:
        trace('  inlining into loop %d!' % p.loop_id(n))

    ex = p.alloc_node(tag, (f_nm, 'RetToCaller'))

    (ns, vs) = p.add_function(fun, tag, {'Ret': ex})
    en = ns[fun.entry]

    inp_lvs = [(vs[v], typ) for (v, typ) in fun.inputs]
    p.nodes[n] = Node('Basic', en, azip(inp_lvs, node.args))

    out_vs = [mk_var(vs[v], typ) for (v, typ) in fun.outputs]
    p.nodes[ex] = Node('Basic', node.cont, azip(node.rets, out_vs))

    p.cached_analysis.clear()

    if do_analysis:
        p.do_analysis()

    trace('Problem size now %d' % len(p.nodes))
    sys.stdin.flush()

    return ns.values()
Exemple #2
0
def inline_at_point (p, n, do_analysis = True):
	node = p.nodes[n]
	if node.kind != 'Call':
		return

	f_nm = node.fname
	fun = functions[f_nm]
	(tag, detail) = p.node_tags[n]
	idx = p.node_tag_revs[(tag, detail)].index (n)
	p.inline_scripts[tag].append ((detail, idx, f_nm))

	trace ('Inlining %s into %s' % (f_nm, p.name))
	if n in p.loop_data:
		trace ('  inlining into loop %d!' % p.loop_id (n))

	ex = p.alloc_node (tag, (f_nm, 'RetToCaller'))

	(ns, vs) = p.add_function (fun, tag, {'Ret': ex})
	en = ns[fun.entry]

	inp_lvs = [(vs[v], typ) for (v, typ) in fun.inputs]
	p.nodes[n] = Node ('Basic', en, azip (inp_lvs, node.args))

	out_vs = [mk_var (vs[v], typ) for (v, typ) in fun.outputs]
	p.nodes[ex] = Node ('Basic', node.cont, azip (node.rets, out_vs))

	p.cached_analysis.clear ()
 
	if do_analysis:
		p.do_analysis ()

	trace ('Problem size now %d' % len(p.nodes))
	sys.stdin.flush ()

	return ns.values ()
Exemple #3
0
	def adj (seq):
		(x_stack, y_stack) = seq[stack_idx]
		xsub = dict ([(v, xv) for (v, (xv, _)) in azip (inps, seq)])
		ysub = dict ([(v, yv) for (v, (_, yv)) in azip (inps, seq)])
		from logic import var_subst
		stk_eqs = [(syntax.mk_memacc (x_stack, var_subst (p, xsub), t),
			syntax.mk_memacc (y_stack, var_subst (p, ysub), t))
			for (p, t) in addrs]
		return seq[:stack_idx] + seq[stack_idx + 1:] + stk_eqs
Exemple #4
0
 def adj(seq):
     (x_stack, y_stack) = seq[stack_idx]
     xsub = dict([(v, xv) for (v, (xv, _)) in azip(inps, seq)])
     ysub = dict([(v, yv) for (v, (_, yv)) in azip(inps, seq)])
     from logic import var_subst
     stk_eqs = [(syntax.mk_memacc(x_stack, var_subst(p, xsub), t),
                 syntax.mk_memacc(y_stack, var_subst(p, ysub), t))
                for (p, t) in addrs]
     return seq[:stack_idx] + seq[stack_idx + 1:] + stk_eqs
Exemple #5
0
def node_const_rets(node):
    if "instruction'" in node.fname:
        return inst_const_rets(node)
    if node.fname in pre_pairings:
        if pre_pairings[node.fname]['ASM'] != node.fname:
            return None
        cc = get_asm_calling_convention_at_node(node)
        input_set = set(
            [v for arg in node.args for v in syntax.get_expr_var_set(arg)])
        callee_saved_set = set(cc['callee_saved'])
        return [
            mk_var(nm, typ) for (nm, typ) in node.rets
            if mk_var(nm, typ) in callee_saved_set if (nm, typ) in input_set
        ]
    elif preserves_sp(node.fname):
        if node.fname not in get_functions_with_tag('ASM'):
            return None
        f_outs = functions[node.fname].outputs
        return [
            mk_var(nm, typ)
            for ((nm, typ), (nm2, _)) in azip(node.rets, f_outs)
            if nm2 == 'r13'
        ]
    else:
        return None
Exemple #6
0
 def all_subproblems(self, p, restrs, hyps, name):
     subproblems = proof_subproblems(p, self.kind, self.args, restrs, hyps,
                                     name)
     subproofs = logic.azip(subproblems, self.subproofs)
     return [(self, restrs, hyps)] + [
         problem for ((restrs2, hyps2, name2), proof) in subproofs
         for problem in proof.all_subproblems(p, restrs2, hyps2, name2)
     ]
Exemple #7
0
def proof_checks_rec(p, restrs, hyps, proof, path):
    checks = proof_checks_imm(p, restrs, hyps, proof, path)

    subproblems = proof_subproblems(p, proof.kind, proof.args, restrs, hyps,
                                    path)
    for (subprob, subproof) in logic.azip(subproblems, proof.subproofs):
        (restrs, hyps, path) = subprob
        checks.extend(proof_checks_rec(p, restrs, hyps, subproof, path))
    return checks
Exemple #8
0
def get_asm_calling_convention_at_node (node):
	cc = get_asm_calling_convention (node.fname)
	if not cc:
		return None

	fun = functions[node.fname]
	arg_input_map = dict (azip (fun.inputs, node.args))
	ret_output_map = dict (azip (fun.outputs,
		[mk_var (nm, typ) for (nm, typ) in node.rets]))

	args = [logic.var_subst (arg, arg_input_map) for arg in cc['args']]
	rets = [logic.var_subst (ret, ret_output_map) for ret in cc['rets']]
	# these are useful because they happen to map ret r0_input back to
	# the previous value r0, rather than the useless value r0_input_ignore.
	rets_inp = [logic.var_subst (ret, arg_input_map) for ret in cc['rets']]
	saved = [logic.var_subst (v, ret_output_map)
		for v in cc['callee_saved']]
	return {'args': args, 'rets': rets,
		'rets_inp': rets_inp, 'callee_saved': saved}
Exemple #9
0
def adjusted_var_dep_outputs_for_tag(p, tag):
    (ent, fname, _) = p.get_entry_details(tag)
    fun = functions[fname]
    cc = get_asm_calling_convention(fname)
    callee_saved_set = set(cc['callee_saved'])
    ret_set = set([(nm, typ) for ret in cc['rets']
                   for (nm, typ) in syntax.get_expr_var_set(ret)])
    rets = [(nm2, typ)
            for ((nm, typ), (nm2, _)) in azip(fun.outputs, p.outputs[tag])
            if (nm, typ) in ret_set or mk_var(nm, typ) in callee_saved_set]
    return rets
Exemple #10
0
def adjusted_var_dep_outputs_for_tag (p, tag):
	(ent, fname, _) = p.get_entry_details (tag)
	fun = functions[fname]
	cc = get_asm_calling_convention (fname)
	callee_saved_set = set (cc['callee_saved'])
	ret_set = set ([(nm, typ) for ret in cc['rets']
		for (nm, typ) in syntax.get_expr_var_set (ret)])
	rets = [(nm2, typ) for ((nm, typ), (nm2, _))
			in azip (fun.outputs, p.outputs[tag])
			if (nm, typ) in ret_set
				or mk_var (nm, typ) in callee_saved_set]
	return rets
Exemple #11
0
def get_asm_calling_convention_at_node(node):
    cc = get_asm_calling_convention(node.fname)
    if not cc:
        return None

    fun = functions[node.fname]
    arg_input_map = dict(azip(fun.inputs, node.args))
    ret_output_map = dict(
        azip(fun.outputs, [mk_var(nm, typ) for (nm, typ) in node.rets]))

    args = [logic.var_subst(arg, arg_input_map) for arg in cc['args']]
    rets = [logic.var_subst(ret, ret_output_map) for ret in cc['rets']]
    # these are useful because they happen to map ret r0_input back to
    # the previous value r0, rather than the useless value r0_input_ignore.
    rets_inp = [logic.var_subst(ret, arg_input_map) for ret in cc['rets']]
    saved = [logic.var_subst(v, ret_output_map) for v in cc['callee_saved']]
    return {
        'args': args,
        'rets': rets,
        'rets_inp': rets_inp,
        'callee_saved': saved
    }
Exemple #12
0
    def entry_exit_renames(self, tags=None):
        """computes the rename set of a function's formal parameters
		to the actual input/output variable names at the various entry
		and exit points"""
        mk = lambda xs, ys: dict([(x[0], y[0]) for (x, y) in azip(xs, ys)])
        renames = {}
        if tags == None:
            tags = self.tags()
        for tag in tags:
            (_, fname, args) = self.get_entry_details(tag)
            fun = functions[fname]
            out = self.outputs[tag]
            renames[tag + '_IN'] = mk(fun.inputs, args)
            renames[tag + '_OUT'] = mk(fun.outputs, out)
        return renames
Exemple #13
0
    def entry_exit_renames(self, tags=None):
        """computes the rename set of a function's formal parameters
		to the actual input/output variable names at the various entry
		and exit points"""
        mk = lambda xs, ys: dict([(x[0], y[0]) for (x, y) in azip(xs, ys)])
        renames = {}
        if tags == None:
            tags = self.tags()
        for tag in tags:
            (_, fname, args) = self.get_entry_details(tag)
            fun = functions[fname]
            out = self.outputs[tag]
            renames[tag + "_IN"] = mk(fun.inputs, args)
            renames[tag + "_OUT"] = mk(fun.outputs, out)
        return renames
Exemple #14
0
def inst_const_rets (node):
	assert "instruction'" in node.fname
	bits = set ([s.lower () for s in node.fname.split ('_')])
	fun = functions[node.fname]
	def is_const (nm, typ):
		if typ in [builtinTs['Mem'], builtinTs['Dom']]:
			return True
		if typ != word32T:
			return False
		return not (nm in bits or [al for al in reg_aliases.get (nm, [])
				if al in bits])
	is_consts = [is_const (nm, typ) for (nm, typ) in fun.outputs]
	input_set = set ([v for arg in node.args
		for v in syntax.get_expr_var_set (arg)])
	return [mk_var (nm, typ)
		for ((nm, typ), const) in azip (node.rets, is_consts)
		if const and (nm, typ) in input_set]
Exemple #15
0
def mk_function_link_hyps (p, call_vis, tag, adjust_eq_seq = None):
	(entry, _, args) = p.get_entry_details (tag)
	((call_site, restrs), call_tag) = call_vis
	assert p.nodes[call_site].kind == 'Call'
	entry_vis = ((entry, ()), p.node_tags[entry][0])

	args = [syntax.mk_var (nm, typ) for (nm, typ) in args]

	pc = pc_true_hyp (call_vis)
	eq_seq = logic.azip (p.nodes[call_site].args, args)
	if adjust_eq_seq:
		eq_seq = adjust_eq_seq (eq_seq)
	hyps = [pc] + [eq_hyp ((x, call_vis), (y, entry_vis))
		for (x, y) in eq_seq
		if x.typ.kind == 'Word' or x.typ == syntax.builtinTs['Mem']
			or x.typ.kind == 'WordArray']

	return hyps
Exemple #16
0
def proof_checks_rec (p, restrs, hyps, proof, path):
	if proof.kind == 'Restr':
		checks = proof_restr_checks (proof.point, proof.restr_range,
			p, restrs, hyps)
	elif proof.kind == 'Split':
		checks = split_checks (p, restrs, hyps, proof.split)
	elif proof.kind == 'Leaf':
		checks = leaf_condition_checks (p, restrs, hyps)
	elif proof.kind == 'CaseSplit':
		checks = []

	checks = [(hs, hyp, '%s on %s' % (name, path))
		for (hs, hyp, name) in checks]

	subproblems = proof_subproblems (p, proof.kind,
		proof.args, restrs, hyps, path)
	for (subprob, subproof) in logic.azip (subproblems, proof.subproofs):
		(restrs, hyps, path) = subprob
		checks.extend (proof_checks_rec (p, restrs, hyps, subproof, path))
	return checks
Exemple #17
0
def inst_const_rets(node):
    assert "instruction'" in node.fname
    bits = set([s.lower() for s in node.fname.split('_')])
    fun = functions[node.fname]

    def is_const(nm, typ):
        if typ in [builtinTs['Mem'], builtinTs['Dom']]:
            return True
        if typ != word32T:
            return False
        return not (nm in bits
                    or [al for al in reg_aliases.get(nm, []) if al in bits])

    is_consts = [is_const(nm, typ) for (nm, typ) in fun.outputs]
    input_set = set(
        [v for arg in node.args for v in syntax.get_expr_var_set(arg)])
    return [
        mk_var(nm, typ) for ((nm, typ), const) in azip(node.rets, is_consts)
        if const and (nm, typ) in input_set
    ]
Exemple #18
0
def check_proof_report_rec(p,
                           restrs,
                           hyps,
                           proof,
                           step_num,
                           ctxt,
                           inducts,
                           do_check=True):
    printout('Step %d: %s' % (step_num, ctxt))
    if proof.kind == 'Restr':
        (kind, (x, y)) = proof.restr_range
        if kind == 'Offset':
            v = inducts[1][proof.point]
            rexpr = '{%s + %s ..< %s + %s}' % (v, x, v, y)
        else:
            rexpr = '{%s ..< %s}' % (x, y)
        printout('  Prove the number of visits to %d is in %s' %
                 (proof.point, rexpr))

        checks = proof_restr_checks(proof.point, proof.restr_range, p, restrs,
                                    hyps)
        cases = ['']
    elif proof.kind == 'SingleRevInduct':
        printout('  Proving a predicate by future induction.')
        (eqs, n) = proof.eqs_proof
        point = proof.point
        printout('    proving these invariants by %d-induction' % n)
        for x in eqs:
            printout('      %s (@ addr %s)' % (pretty_lambda(x), point))
        printout('    then establishing this predicate')
        (pred, n_bound) = proof.rev_proof
        printout('      %s (@ addr %s)' % (pretty_lambda(pred), point))
        printout('    at large iterations (%d) and by back induction.' %
                 n_bound)
        cases = ['']
        checks = all_rev_induct_checks(p, restrs, hyps, point, proof.eqs_proof,
                                       proof.rev_proof)
    elif proof.kind == 'Split':
        (l_dts, r_dts, eqs, n, lrmx) = proof.split
        v = next_induct_var(inducts[0])
        inducts = (inducts[0] + 1, dict(inducts[1]))
        inducts[1][l_dts[0]] = v
        inducts[1][r_dts[0]] = v
        printout('  prove %s related to %s' %
                 (pretty_vseq(l_dts), pretty_vseq(r_dts)))
        printout('    with equalities')
        for (x, y) in eqs:
            printout('      %s (@ addr %s)' % (pretty_lambda(x), l_dts[0]))
            printout('      = %s (@ addr %s)' % (pretty_lambda(y), r_dts[0]))
        printout('    and with invariants')
        for x in l_dts[2]:
            printout('      %s (@ addr %s)' % (pretty_lambda(x), l_dts[0]))
        for x in r_dts[2]:
            printout('      %s (@ addr %s)' % (pretty_lambda(x), r_dts[0]))
        checks = split_checks(p, restrs, hyps, proof.split)
        cases = [
            'case in (%d) where the length of the sequence < %d' %
            (step_num, n),
            'case in (%d) where the length of the sequence is %s + %s' %
            (step_num, v, n)
        ]
    elif proof.kind == 'Leaf':
        printout('  prove all verification conditions')
        checks = leaf_condition_checks(p, restrs, hyps)
        cases = []
    elif proof.kind == 'CaseSplit':
        printout('  case split on whether %d is visited' % proof.point)
        checks = []
        cases = [
            'case in (%d) where %d is visited' % (step_num, proof.point),
            'case in (%d) where %d is not visited' % (step_num, proof.point)
        ]

    if checks and do_check:
        groups = proof_check_groups(checks)
        for group in groups:
            rep = rep_graph.mk_graph_slice(p)
            detail = [0]
            (res, _) = test_hyp_group(rep, group, detail)
            if not res:
                printout('    .. failed to prove this.')
                printout('      (failure kind: %r)' % detail[0])
                return

        printout('    .. proven.')

    subproblems = proof_subproblems(p, proof.kind, proof.args, restrs, hyps,
                                    '')
    xs = logic.azip(subproblems, proof.subproofs)
    xs = logic.azip(xs, cases)
    step_num += 1
    for ((subprob, subproof), case) in xs:
        (restrs, hyps, _) = subprob
        res = check_proof_report_rec(p,
                                     restrs,
                                     hyps,
                                     subproof,
                                     step_num,
                                     case,
                                     inducts,
                                     do_check=do_check)
        if not res:
            return
        (step_num, induct_var_num) = res
        inducts = (induct_var_num, inducts[1])
    return (step_num, inducts[0])
Exemple #19
0
def check_proof_report_rec (p, restrs, hyps, proof, step_num, ctxt, inducts):
	import sys
	printout ('Step %d: %s' % (step_num, ctxt))
	if proof.kind == 'Restr':
		(kind, (x, y)) = proof.restr_range
		if kind == 'Offset':
			v = inducts[1][proof.point]
			rexpr = '{%s + %s ..< %s + %s}' % (v, x, v, y)
		else:
			rexpr = '{%s ..< %s}' % (x, y)
		printout ('  Prove the number of visits to %d is in %s'
			% (proof.point, rexpr))
		
		checks = proof_restr_checks (proof.point, proof.restr_range,
			p, restrs, hyps)
		cases = ['']
	elif proof.kind == 'Split':
		(l_dts, r_dts, eqs, n, lrmx) = proof.split
		v = next_induct_var (inducts[0])
		inducts = (inducts[0] + 1, dict (inducts[1]))
		inducts[1][l_dts[0]] = v
		inducts[1][r_dts[0]] = v
		printout ('  prove %s related to %s' % (pretty_vseq (l_dts),
			pretty_vseq (r_dts)))
		printout ('    with equalities')
		for (x, y) in eqs:
			printout ('      %s (@ addr %s)' % (pretty_lambda (x),
				l_dts[0]))
			printout ('      = %s (@ addr %s)' % (pretty_lambda (y),
				r_dts[0]))
		printout ('    and with invariants')
		for x in l_dts[2]:
			printout ('      %s (@ addr %s)'
				% (pretty_lambda (x), l_dts[0]))
		for x in r_dts[2]:
			printout ('      %s (@ addr %s)'
				% (pretty_lambda (x), r_dts[0]))
		checks = split_checks (p, restrs, hyps, proof.split)
		cases = ['case in (%d) where the length of the sequence < %d'
				% (step_num, n),
			'case in (%d) where the length of the sequence is %s + %s'
				% (step_num, v, n)]
	elif proof.kind == 'Leaf':
		printout ('  prove all verification conditions')
		checks = leaf_condition_checks (p, restrs, hyps)
		cases = []
	elif proof.kind == 'CaseSplit':
		printout ('  case split on whether %d is visited' % proof.point)
		checks = []
		cases = ['case in (%d) where %d is visited' % (step_num, proof.point),
			'case in (%d) where %d is not visited' % (step_num, proof.point)]

	if checks:
		groups = proof_check_groups (checks)
		for group in groups:
			rep = rep_graph.mk_graph_slice (p)
			(res, _) = test_hyp_group (rep, group)
			if not res:
				printout ('    .. failed to prove this.')
				sys.stdout.flush ()
				return

		printout ('    .. proven.')
		sys.stdout.flush ()

	subproblems = proof_subproblems (p, proof.kind,
		proof.args, restrs, hyps, '')
	xs = logic.azip (subproblems, proof.subproofs)
	xs = logic.azip (xs, cases)
	step_num += 1
	for ((subprob, subproof), case) in xs:
		(restrs, hyps, _) = subprob
		res = check_proof_report_rec (p, restrs, hyps, subproof,
			step_num, case, inducts)
		if not res:
			return
		(step_num, induct_var_num) = res
		inducts = (induct_var_num, inducts[1])
	return (step_num, inducts[0])
Exemple #20
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'