示例#1
0
def mk_bin_inst_spec(fname):
    if not fname.startswith("instruction'"):
        return
    if functions[fname].entry:
        return
    (_, ident) = fname.split("'", 1)
    (ident, addr) = split_inst_name_addr(ident)
    (regs, ident) = split_inst_name_regs(ident)
    ident = instruction_name_aliases.get(ident, ident)
    base_ident = ident.split("_")[0]
    if base_ident not in instruction_fun_specs:
        return
    (impl_fname, regspecs) = instruction_fun_specs[base_ident]
    add_impl_fun(impl_fname, regspecs)
    assert len(regspecs) == len(regs), (fname, regs, regspecs)
    inp_regs = [reg for (reg, d) in zip(regs, regspecs) if d == 'I']
    out_regs = [reg for (reg, d) in zip(regs, regspecs) if d == 'O']
    call = syntax.Node(
        'Call', 'Ret',
        ('l_' + impl_fname,
         [syntax.mk_var(reg, syntax.word32T)
          for reg in inp_regs] + [syntax.mk_token(ident)] +
         [syntax.mk_var(nm, typ)
          for (nm, typ) in bin_globs], [(reg, syntax.word32T)
                                        for reg in out_regs] + bin_globs))
    assert not functions[fname].nodes
    functions[fname].nodes[1] = call
    functions[fname].entry = 1
示例#2
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
示例#3
0
def mk_bin_inst_spec (fname):
	if not fname.startswith ("instruction'"):
		return
	if functions[fname].entry:
		return
	(_, ident) = fname.split ("'", 1)
	(ident, addr) = split_inst_name_addr (ident)
	(regs, ident) = split_inst_name_regs (ident)
	ident = instruction_name_aliases.get (ident, ident)
	base_ident = ident.split ("_")[0]
	if base_ident not in instruction_fun_specs:
		return
	(impl_fname, regspecs) = instruction_fun_specs[base_ident]
	add_impl_fun (impl_fname, regspecs)
	assert len (regspecs) == len (regs), (fname, regs, regspecs)
	inp_regs = [reg for (reg, d) in zip (regs, regspecs) if d == 'I']
	out_regs = [reg for (reg, d) in zip (regs, regspecs) if d == 'O']
	call = syntax.Node ('Call', 'Ret', (impl_fname,
		[syntax.mk_var (reg, syntax.word32T) for reg in inp_regs]
			+ [syntax.mk_token (ident)]
			+ [syntax.mk_var (nm, typ) for (nm, typ) in bin_globs],
		[(reg, syntax.word32T) for reg in out_regs] + bin_globs))
	assert not functions[fname].nodes
	functions[fname].nodes[1] = call
	functions[fname].entry = 1
示例#4
0
def get_stack_sp(p, tag):
    """get stack and stack-pointer variables"""
    entry = p.get_entry(tag)
    renames = p.entry_exit_renames(tags=[tag])
    r = renames[tag + '_IN']

    sp = syntax.rename_expr(mk_var('r13', syntax.word32T), r)
    stack = syntax.rename_expr(mk_var('stack', syntax.builtinTs['Mem']), r)
    return (stack, sp)
示例#5
0
def get_stack_sp (p, tag):
	"""get stack and stack-pointer variables"""
	entry = p.get_entry (tag)
	renames = p.entry_exit_renames (tags = [tag])
	r = renames[tag + '_IN']

	sp = syntax.rename_expr (mk_var ('r13', syntax.word32T), r)
	stack = syntax.rename_expr (mk_var ('stack',
		syntax.builtinTs['Mem']), r)
	return (stack, sp)
示例#6
0
def node_const_rets (node):
	if "instruction'" in node.fname:
		return inst_const_rets (node)
	if node.fname not in pre_pairings:
		return None
	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]
示例#7
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()
示例#8
0
def stack_virtualise_expr(expr, sp_offs):
    if expr.is_op('MemAcc') and is_stack(expr.vals[0]):
        [m, p] = expr.vals
        if expr.typ == syntax.word8T:
            ps = [(syntax.mk_minus(p, syntax.mk_word32(n)), n)
                  for n in [0, 1, 2, 3]]
        elif expr.typ == syntax.word32T:
            ps = [(p, 0)]
        else:
            assert expr.typ == syntax.word32T, expr
        ptrs = [(p, 'MemAcc') for (p, _) in ps]
        if sp_offs == None:
            return (ptrs, None)
        # FIXME: very 32-bit specific
        ps = [(p, n) for (p, n) in ps if p in sp_offs
              if sp_offs[p][1] % 4 == 0]
        if not ps:
            return (ptrs, expr)
        [(p, n)] = ps
        if p not in sp_offs:
            raise StackOffsMissing()
        (k, offs) = sp_offs[p]
        v = mk_var(('Fake', k, offs), syntax.word32T)
        if n != 0:
            v = syntax.mk_shiftr(v, n * 8)
        v = syntax.mk_cast(v, expr.typ)
        return (ptrs, v)
    elif expr.kind == 'Op':
        vs = [stack_virtualise_expr(v, sp_offs) for v in expr.vals]
        return ([p for (ptrs, _) in vs for p in ptrs],
                syntax.adjust_op_vals(expr, [v for (_, v) in vs]))
    else:
        return ([], expr)
示例#9
0
def get_induct_eq_hyp(p, split, restrs, n):
    details = (split, (0, 1), [])
    (tag, _) = p.node_tags[split]
    visit = split_visit_one_visit(tag, details, restrs, vc_offs(0))
    from syntax import mk_var, word32T, mk_word32

    return eq_hyp((mk_var("%n", word32T), visit), (mk_word32(n), visit), (split, 0))
示例#10
0
def split_hyps_at_visit (tags, split, restrs, visit):
	(l_details, r_details, eqs, _, _) = split
	(l_split, (l_seq_start, l_step), l_eqs) = l_details
	(r_split, (r_seq_start, r_step), r_eqs) = r_details

	(l_visit, r_visit) = split_visit_visits (tags, split, restrs, visit)
	(l_start, r_start) = split_visit_visits (tags, split, restrs, vc_num (0))
	(l_tag, r_tag) = tags

	def mksub (v):
		return lambda exp: logic.var_subst (exp, {('%i', word32T) : v},
			must_subst = False)
	def inst (exp):
		return logic.inst_eq_at_visit (exp, visit)
	zsub = mksub (mk_word32 (0))
	if visit.kind == 'Number':
		lsub = mksub (mk_word32 (visit.n))
	else:
		lsub = mksub (mk_plus (mk_var ('%n', word32T),
			mk_word32 (visit.n)))

	hyps = [(Hyp ('PCImp', l_visit, r_visit), 'pc imp'),
		(Hyp ('PCImp', l_visit, l_start), '%s pc imp' % l_tag),
		(Hyp ('PCImp', r_visit, r_start), '%s pc imp' % r_tag)]
	hyps += [(eq_hyp ((zsub (l_exp), l_start), (lsub (l_exp), l_visit),
				(l_split, r_split)), '%s const' % l_tag)
			for l_exp in l_eqs if inst (l_exp)]
	hyps += [(eq_hyp ((zsub (r_exp), r_start), (lsub (r_exp), r_visit),
				(l_split, r_split)), '%s const' % r_tag)
			for r_exp in r_eqs if inst (r_exp)]
	hyps += [(eq_hyp ((lsub (l_exp), l_visit), (lsub (r_exp), r_visit),
				(l_split, r_split)), 'eq')
			for (l_exp, r_exp) in eqs
			if inst (l_exp) and inst (r_exp)]
	return hyps
示例#11
0
def mk_seq_eqs (p, split, step, with_rodata):
	# eqs take the form of a number of constant expressions
	eqs = []

	# the variable 'loop' will be converted to the point in
	# the sequence - note this should be multiplied by the step size
	loop = mk_var ('%i', word32T)
	if step == 1:
		minus_loop_step = mk_uminus (loop)
	else:
		minus_loop_step = mk_times (loop, mk_word32 (- step))

	for (var, data) in get_loop_var_analysis_at (p, split):
		if data == 'LoopVariable':
			if with_rodata and var.typ == builtinTs['Mem']:
				eqs.append (logic.mk_rodata (var))
		elif data == 'LoopConst':
			if var.typ not in syntax.phantom_types:
				eqs.append (var)
		elif data == 'LoopLeaf':
			continue
		elif data[0] == 'LoopLinearSeries':
			(_, form, _) = data
			eqs.append (form (var, minus_loop_step))
		else:
			assert not 'var_deps type understood'

	return eqs
示例#12
0
def stack_virtualise_expr (expr, sp_offs):
	if expr.is_op ('MemAcc') and is_stack (expr.vals[0]):
		[m, p] = expr.vals
		if expr.typ == syntax.word8T:
			ps = [(syntax.mk_minus (p, syntax.mk_word32 (n)), n)
				for n in [0, 1, 2, 3]]
		elif expr.typ == syntax.word32T:
			ps = [(p, 0)]
		else:
			assert expr.typ == syntax.word32T, expr
		ptrs = [(p, 'MemAcc') for (p, _) in ps]
		if sp_offs == None:
			return (ptrs, None)
		# FIXME: very 32-bit specific
		ps = [(p, n) for (p, n) in ps if p in sp_offs
			if sp_offs[p][1] % 4 == 0]
		if not ps:
			return (ptrs, expr)
		[(p, n)] = ps
		(k, offs) = sp_offs[p]
		v = mk_var (('Fake', k, offs), syntax.word32T)
		if n != 0:
			v = syntax.mk_shiftr (v, n * 8)
		v = syntax.mk_cast (v, expr.typ)
		return (ptrs, v)
	elif expr.kind == 'Op':
		vs = [stack_virtualise_expr (v, sp_offs) for v in expr.vals]
		return ([p for (ptrs, _) in vs for p in ptrs],
			syntax.Expr ('Op', expr.typ, name = expr.name,
				vals = [v for (_, v) in vs]))
	else:
		return ([], expr)
示例#13
0
def split_hyps_at_visit(tags, split, restrs, visit):
    (l_details, r_details, eqs, _, _) = split
    (l_split, (l_seq_start, l_step), l_eqs) = l_details
    (r_split, (r_seq_start, r_step), r_eqs) = r_details

    (l_visit, r_visit) = split_visit_visits(tags, split, restrs, visit)
    (l_start, r_start) = split_visit_visits(tags, split, restrs, vc_num(0))
    (l_tag, r_tag) = tags

    def mksub(v):
        return lambda exp: logic.var_subst(exp, {('%i', word32T): v},
                                           must_subst=False)

    def inst(exp):
        return logic.inst_eq_at_visit(exp, visit)

    zsub = mksub(mk_word32(0))
    if visit.kind == 'Number':
        lsub = mksub(mk_word32(visit.n))
    else:
        lsub = mksub(mk_plus(mk_var('%n', word32T), mk_word32(visit.n)))

    hyps = [(Hyp('PCImp', l_visit, r_visit), 'pc imp'),
            (Hyp('PCImp', l_visit, l_start), '%s pc imp' % l_tag),
            (Hyp('PCImp', r_visit, r_start), '%s pc imp' % r_tag)]
    hyps += [(eq_hyp((zsub(l_exp), l_start), (lsub(l_exp), l_visit),
                     (l_split, r_split)), '%s const' % l_tag)
             for l_exp in l_eqs if inst(l_exp)]
    hyps += [(eq_hyp((zsub(r_exp), r_start), (lsub(r_exp), r_visit),
                     (l_split, r_split)), '%s const' % r_tag)
             for r_exp in r_eqs if inst(r_exp)]
    hyps += [(eq_hyp((lsub(l_exp), l_visit), (lsub(r_exp), r_visit),
                     (l_split, r_split)), 'eq') for (l_exp, r_exp) in eqs
             if inst(l_exp) and inst(r_exp)]
    return hyps
示例#14
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 ()
示例#15
0
def adjust_ret_ptr (ptr):
	"""this is a bit of a hack.

	the return slots are named based on r0_input, which will be unchanged,
	which is handy, but we really want to be talking about r0, which will
	produce meaningful offsets against the pointers actually used in the
	program."""

	return logic.var_subst (ptr, {('r0_input', syntax.word32T):
		syntax.mk_var ('r0', syntax.word32T)}, must_subst = False)
示例#16
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
示例#17
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
示例#18
0
def compute_loop_var_analysis (nodes, var_deps, n, loop, preds):
	upd_vs = set ([v for n2 in loop
		if not nodes[n2].is_noop ()
		for v in nodes[n2].get_lvals ()])
	const_vs = set ([v for n2 in loop
		for v in var_deps[n2] if v not in upd_vs])

	vca = compute_var_cycle_analysis (nodes, n, loop, preds,
		const_vs, set (var_deps[n]))
	vca = [(syntax.mk_var (nm, typ), data)
		for ((nm, typ), data) in vca.items ()]
	return vca
示例#19
0
def get_asm_calling_convention_inner(num_c_args, num_c_rets, const_mem):
    key = ('Inner', num_c_args, num_c_rets, const_mem)
    if key in asm_cc_cache:
        return asm_cc_cache[key]

    from logic import mk_var_list, mk_stack_sequence
    from syntax import mk_var, word32T, builtinTs

    arg_regs = mk_var_list(['r0', 'r1', 'r2', 'r3'], word32T)
    r0 = arg_regs[0]
    sp = mk_var('r13', word32T)
    st = mk_var('stack', builtinTs['Mem'])
    r0_input = mk_var('ret_addr_input', word32T)

    mem = mk_var('mem', builtinTs['Mem'])
    dom = mk_var('dom', builtinTs['Dom'])
    dom_stack = mk_var('dom_stack', builtinTs['Dom'])

    global_args = [mem, dom, st, dom_stack, sp, mk_var('ret', word32T)]

    sregs = mk_stack_sequence(sp, 4, st, word32T, num_c_args + 1)

    arg_seq = [r for r in arg_regs] + [s for (s, _) in sregs]
    if num_c_rets > 1:
        # the 'return-too-much' issue.
        # instead r0 is a save-returns-here pointer
        arg_seq.pop(0)
        rets = mk_stack_sequence(r0_input, 4, st, word32T, num_c_rets)
        rets = [r for (r, _) in rets]
    else:
        rets = [r0]

    callee_saved_vars = (
        [mk_var(v, word32T)
         for v in 'r4 r5 r6 r7 r8 r9 r10 r11 r13'.split()] + [dom, dom_stack])

    if const_mem:
        callee_saved_vars += [mem]
    else:
        rets += [mem]
    rets += [st]

    cc = {
        'args': arg_seq[:num_c_args] + global_args,
        'rets': rets,
        'callee_saved': callee_saved_vars
    }

    asm_cc_cache[key] = cc
    return cc
示例#20
0
def add_impl_fun(impl_fname, regspecs):
    l_fname = 'l_' + impl_fname
    r_fname = 'r_' + impl_fname
    if l_fname in functions:
        return
    assert r_fname not in functions

    ident_v = ("inst_ident", syntax.builtinTs['Token'])

    inps = [s for s in regspecs if s == 'I']
    inps = ['reg_val%d' % (i + 1) for (i, s) in enumerate(inps)]
    rets = [s for s in regspecs if s == 'O']
    rets = ['ret_val%d' % (i + 1) for (i, s) in enumerate(rets)]
    l_fun = mk_fun(l_fname, inps, [ident_v], rets, [], bin_globs)
    r_fun = mk_fun(r_fname, inps, [ident_v], rets, [], bin_globs)
    inp_eqs = [((mk_var(nm, typ), 'ASM_IN'), (mk_var(nm, typ), 'C_IN'))
               for (nm, typ) in l_fun.inputs]
    inp_eqs += [((logic.mk_rodata(mk_var(nm, typ)), 'ASM_IN'),
                 (syntax.true_term, 'C_IN')) for (nm, typ) in bin_globs]
    out_eqs = [((mk_var(nm, typ), 'ASM_OUT'), (mk_var(nm, typ), 'C_OUT'))
               for (nm, typ) in l_fun.outputs]
    out_eqs += [((logic.mk_rodata(mk_var(nm, typ)), 'ASM_OUT'),
                 (syntax.true_term, 'C_OUT')) for (nm, typ) in bin_globs]
    pair = logic.Pairing(['ASM', 'C'], {
        'ASM': l_fname,
        'C': r_fname
    }, (inp_eqs, out_eqs))
    assert l_fname not in pairings
    assert r_fname not in pairings
    functions[l_fname] = l_fun
    functions[r_fname] = r_fun
    pairings[l_fname] = [pair]
    pairings[r_fname] = [pair]
示例#21
0
def adjust_ret_ptr(ptr):
    """this is a bit of a hack.

	the return slots are named based on r0_input, which will be unchanged,
	which is handy, but we really want to be talking about r0, which will
	produce meaningful offsets against the pointers actually used in the
	program."""

    return logic.var_subst(ptr, {
        ('ret_addr_input', syntax.word32T):
        syntax.mk_var('r0', syntax.word32T)
    },
                           must_subst=False)
示例#22
0
def pseudo_node_lvals_rvals(node):
    assert node.kind == 'Call'
    cc = get_asm_calling_convention_at_node(node)
    if not cc:
        return None

    arg_vars = set(
        [var for arg in cc['args'] for var in syntax.get_expr_var_set(arg)])

    callee_saved_set = set(cc['callee_saved'])
    rets = [(nm, typ) for (nm, typ) in node.rets
            if mk_var(nm, typ) not in callee_saved_set]

    return (rets, arg_vars)
示例#23
0
def pseudo_node_lvals_rvals (node):
	assert node.kind == 'Call'
	cc = get_asm_calling_convention_at_node (node)
	if not cc:
		return None
	
	arg_vars = set ([var for arg in cc['args']
		for var in syntax.get_expr_var_set (arg)])

	callee_saved_set = set (cc['callee_saved'])
	rets = [(nm, typ) for (nm, typ) in node.rets
		if mk_var (nm, typ) not in callee_saved_set]

	return (rets, arg_vars)
示例#24
0
def get_asm_calling_convention_inner (num_c_args, num_c_rets, const_mem):
	key = ('Inner', num_c_args, num_c_rets, const_mem)
	if key in asm_cc_cache:
		return asm_cc_cache[key]

	from logic import mk_var_list, mk_stack_sequence
	from syntax import mk_var, word32T, builtinTs

	arg_regs = mk_var_list (['r0', 'r1', 'r2', 'r3'], word32T)
	r0 = arg_regs[0]
	sp = mk_var ('r13', word32T)
	st = mk_var ('stack', builtinTs['Mem'])
	r0_input = mk_var ('r0_input', word32T)

	mem = mk_var ('mem', builtinTs['Mem'])
	dom = mk_var ('dom', builtinTs['Dom'])
	dom_stack = mk_var ('dom_stack', builtinTs['Dom'])

	global_args = [mem, dom, st, dom_stack, sp, mk_var ('ret', word32T)]

	sregs = mk_stack_sequence (sp, 4, st, word32T, num_c_args + 1)

	arg_seq = [r for r in arg_regs] + [s for (s, _) in sregs]
	if num_c_rets > 1:
		# the 'return-too-much' issue.
		# instead r0 is a save-returns-here pointer
		arg_seq.pop (0)
		rets = mk_stack_sequence (r0_input, 4, st, word32T, num_c_rets)
		rets = [r for (r, _) in rets]
	else:
		rets = [r0]

	callee_saved_vars = ([mk_var (v, word32T)
			for v in 'r4 r5 r6 r7 r8 r9 r10 r11 r13'.split ()]
		+ [dom, dom_stack])

	if const_mem:
		callee_saved_vars += [mem]
	else:
		rets += [mem]
	rets += [st]

	cc = {'args': arg_seq[: num_c_args] + global_args,
		'rets': rets, 'callee_saved': callee_saved_vars}

	asm_cc_cache[key] = cc
	return cc
示例#25
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]
示例#26
0
def candidate_additional_eqs(p, split):
    eq_vals = set()

    def visitor(expr):
        if expr.is_op('Equals') and expr.vals[0].typ.kind == 'Word':
            [x, y] = expr.vals
            eq_vals.update([(x, y), (y, x)])

    for n in p.loop_body(split):
        p.nodes[n].visit(lambda x: (), visitor)
    for (x, y) in list(eq_vals):
        if is_zero(x) and y.is_op('Plus'):
            [x, y] = y.vals
            eq_vals.add((x, syntax.mk_uminus(y)))
            eq_vals.add((y, syntax.mk_uminus(x)))
        elif is_zero(x) and y.is_op('Minus'):
            [x, y] = y.vals
            eq_vals.add((x, y))
            eq_vals.add((y, x))

    loop = syntax.mk_var('%i', syntax.word32T)
    minus_loop_step = syntax.mk_uminus(loop)

    vas = search.get_loop_var_analysis_at(p, split)
    ls_vas = dict([(var, [data]) for (var, data) in vas
                   if data[0] == 'LoopLinearSeries'])
    cmp_series = [(x, y, rew, offs) for (x, y) in eq_vals
                  for (_, rew, offs) in ls_vas.get(x, [])]
    odd_eqs = []
    for (x, y, rew, offs) in cmp_series:
        x_init_cmp1 = syntax.mk_less_eq(x, rew(x, minus_loop_step))
        x_init_cmp2 = syntax.mk_less_eq(rew(x, minus_loop_step), x)
        fin_cmp1 = syntax.mk_less(x, y)
        fin_cmp2 = syntax.mk_less(y, x)
        odd_eqs.append(syntax.mk_eq(x_init_cmp1, fin_cmp1))
        odd_eqs.append(syntax.mk_eq(x_init_cmp2, fin_cmp1))
        odd_eqs.append(syntax.mk_eq(x_init_cmp1, fin_cmp2))
        odd_eqs.append(syntax.mk_eq(x_init_cmp2, fin_cmp2))

    ass_eqs = []
    var_deps = p.compute_var_dependencies()
    for hook in target_objects.hooks('extra_wcet_assertions'):
        for assn in hook(var_deps[split]):
            ass_eqs.append(assn)

    return odd_eqs + ass_eqs
示例#27
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
示例#28
0
def get_extra_sp_defs (rep, tag):
	"""all functions will keep the stack pointer equal, whether they have
	pairing partners or not. add these extra defs/equalities for the
	purposes of stack depth analysis."""
	# FIXME how to parametrise this?
	sp = mk_var ('r13', syntax.word32T)
	defs = {}
	items = [(n_vc, x) for (n_vc, x) in rep.funcs.iteritems ()
		if logic.is_int (n_vc[0])]
	for ((n, vc), (inputs, outputs, _)) in items:
		if rep.p.node_tags[n][0] == tag:
			inp_sp = solver.smt_expr (sp, inputs, rep.solv)
			inp_sp = solver.parse_s_expression (inp_sp)
			out_sp = solver.smt_expr (sp, outputs, rep.solv)
			out_sp = solver.parse_s_expression (out_sp)
			if inp_sp != out_sp:
				defs[out_sp] = inp_sp
	return defs
示例#29
0
def candidate_additional_eqs(p, split):
    eq_vals = set()

    def visitor(expr):
        if expr.is_op("Equals") and expr.vals[0].typ.kind == "Word":
            [x, y] = expr.vals
            eq_vals.update([(x, y), (y, x)])

    for n in p.loop_body(split):
        p.nodes[n].visit(lambda x: (), visitor)
    for (x, y) in list(eq_vals):
        if is_zero(x) and y.is_op("Plus"):
            [x, y] = y.vals
            eq_vals.add((x, syntax.mk_uminus(y)))
            eq_vals.add((y, syntax.mk_uminus(x)))
        elif is_zero(x) and y.is_op("Minus"):
            [x, y] = y.vals
            eq_vals.add((x, y))
            eq_vals.add((y, x))

    loop = syntax.mk_var("%i", syntax.word32T)
    minus_loop_step = syntax.mk_uminus(loop)

    vas = search.get_loop_var_analysis_at(p, split)
    ls_vas = dict([(var, [data]) for (var, data) in vas if data[0] == "LoopLinearSeries"])
    cmp_series = [(x, y, rew, offs) for (x, y) in eq_vals for (_, rew, offs) in ls_vas.get(x, [])]
    odd_eqs = []
    for (x, y, rew, offs) in cmp_series:
        x_init_cmp1 = syntax.mk_less_eq(x, rew(x, minus_loop_step))
        x_init_cmp2 = syntax.mk_less_eq(rew(x, minus_loop_step), x)
        fin_cmp1 = syntax.mk_less(x, y)
        fin_cmp2 = syntax.mk_less(y, x)
        odd_eqs.append(syntax.mk_eq(x_init_cmp1, fin_cmp1))
        odd_eqs.append(syntax.mk_eq(x_init_cmp2, fin_cmp1))
        odd_eqs.append(syntax.mk_eq(x_init_cmp1, fin_cmp2))
        odd_eqs.append(syntax.mk_eq(x_init_cmp2, fin_cmp2))

    ass_eqs = []
    var_deps = p.compute_var_dependencies()
    for hook in target_objects.hooks("extra_wcet_assertions"):
        for assn in hook(var_deps[split]):
            ass_eqs.append(assn)

    return odd_eqs + ass_eqs
示例#30
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}
示例#31
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
    ]
示例#32
0
def stack_virtualise_expr (expr, sp_offs):
	if expr.is_op ('MemAcc') and is_stack (expr.vals[0]):
		[m, p] = expr.vals
		assert expr.typ == syntax.word32T
		ptrs = [(p, 'MemAcc')]
		if sp_offs == None:
			return (ptrs, None)
		else:
			if p not in sp_offs:
				return (ptrs, expr)
			(k, offs) = sp_offs[p]
			return (ptrs, mk_var (('Fake', k, offs),
					syntax.word32T))
	elif expr.kind == 'Op':
		vs = [stack_virtualise_expr (v, sp_offs) for v in expr.vals]
		return ([p for (ptrs, _) in vs for p in ptrs],
			syntax.Expr ('Op', expr.typ, name = expr.name,
				vals = [v for (_, v) in vs]))
	else:
		return ([], expr)
示例#33
0
def loop_eq_hyps_at_visit(tag, split, eqs, restrs, visit_num, use_if_at=False):
    details = (split, (0, 1), eqs)
    visit = split_visit_one_visit(tag, details, restrs, visit_num)
    start = split_visit_one_visit(tag, details, restrs, vc_num(0))

    def mksub(v):
        return lambda exp: logic.var_subst(exp, {('%i', word32T): v},
                                           must_subst=False)

    zsub = mksub(mk_word32(0))
    if visit_num.kind == 'Number':
        isub = mksub(mk_word32(visit_num.n))
    else:
        isub = mksub(mk_plus(mk_var('%n', word32T), mk_word32(visit_num.n)))

    hyps = [(Hyp('PCImp', visit, start), '%s pc imp' % tag)]
    hyps += [(eq_hyp((zsub(exp), start), (isub(exp), visit), (split, 0),
                     use_if_at=use_if_at), '%s const' % tag) for exp in eqs
             if logic.inst_eq_at_visit(exp, visit_num)]

    return hyps
示例#34
0
def linear_eq_hyps_at_visit (tag, split, eqs, restrs, visit_num):
    details = (split, (0, 1), eqs)
    visit = split_visit_one_visit (tag, details, restrs, visit_num)
    start = split_visit_one_visit (tag, details, restrs, vc_num (0))
    from syntax import mk_word32, mk_plus, mk_var, word32T

    def mksub (v):
            return lambda exp: logic.var_subst (exp, {('%i', word32T) : v},
                    must_subst = False)
    zsub = mksub (mk_word32 (0))
    if visit_num.kind == 'Number':
            isub = mksub (mk_word32 (visit_num.n))
    else:
            isub = mksub (mk_plus (mk_var ('%n', word32T),
                    mk_word32 (visit_num.n)))

    hyps = [(Hyp ('PCImp', visit, start), '%s pc imp' % tag)]
    hyps += [(eq_hyp ((zsub (exp), start), (isub (exp), visit),
                            (split, 0)), '%s const' % tag)
                    for exp in eqs if logic.inst_eq_at_visit (exp, visit_num)]

    return hyps
示例#35
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
    }
示例#36
0
def get_extra_sp_defs(rep, tag):
    """add extra defs/equalities about stack pointer for the
	purposes of stack depth analysis."""
    # FIXME how to parametrise this?
    sp = mk_var('r13', syntax.word32T)
    defs = {}

    fcalls = [
        n_vc for n_vc in rep.funcs if logic.is_int(n_vc[0])
        if rep.p.node_tags[n_vc[0]][0] == tag
        if preserves_sp(rep.p.nodes[n_vc[0]].fname)
    ]
    for (n, vc) in fcalls:
        (inputs, outputs, _) = rep.funcs[(n, vc)]
        if (sp.name, sp.typ) not in outputs:
            continue
        inp_sp = solver.smt_expr(sp, inputs, rep.solv)
        inp_sp = solver.parse_s_expression(inp_sp)
        out_sp = solver.smt_expr(sp, outputs, rep.solv)
        out_sp = solver.parse_s_expression(out_sp)
        if inp_sp != out_sp:
            defs[out_sp] = inp_sp
    return defs
示例#37
0
def add_impl_fun (impl_fname, regspecs):
	if impl_fname in functions:
		return
	ident_v = ("inst_ident", syntax.builtinTs['Token'])

	inps = [s for s in regspecs if s == 'I']
	inps = ['reg_val%d' % (i + 1) for (i, s) in enumerate (inps)]
	rets = [s for s in regspecs if s == 'O']
	rets = ['ret_val%d' % (i + 1) for (i, s) in enumerate (rets)]
	fun = mk_fun (impl_fname, inps, [ident_v], rets, [], bin_globs)
	inp_eqs = [((mk_var (nm, typ), 'ASM_IN'), (mk_var (nm, typ), 'C_IN'))
		for (nm, typ) in fun.inputs]
	inp_eqs += [((logic.mk_rodata (mk_var (nm, typ)), 'ASM_IN'),
		(syntax.true_term, 'C_IN')) for (nm, typ) in bin_globs]
	out_eqs = [((mk_var (nm, typ), 'ASM_OUT'), (mk_var (nm, typ), 'C_OUT'))
		for (nm, typ) in fun.outputs]
	out_eqs += [((logic.mk_rodata (mk_var (nm, typ)), 'ASM_OUT'),
		(syntax.true_term, 'C_OUT')) for (nm, typ) in bin_globs]
	pair = logic.Pairing (['ASM', 'C'],
		{'C': impl_fname, 'ASM': impl_fname},
		(inp_eqs, out_eqs))
	assert impl_fname not in pairings
	functions[impl_fname] = fun
	pairings[impl_fname] = [pair]
示例#38
0
def add_recursion_ident(f, group, idents, extra_unfolds):
    from syntax import mk_eq, mk_implies, mk_var
    p = problem.Problem(None, name='Recursion Test')
    chain = []
    tag = 'fun0'
    p.add_entry_function(functions[f], tag)
    p.do_analysis()
    assns = []
    recursion_last_assns[0] = assns

    while True:
        res = find_unknown_recursion(p, group, idents, tag, assns,
                                     extra_unfolds)
        if res == None:
            break
        if p.nodes[res].fname not in group:
            problem.inline_at_point(p, res)
            continue
        fname = p.nodes[res].fname
        chain.append(fname)
        tag = 'fun%d' % len(chain)
        (args, _, entry) = p.add_entry_function(functions[fname], tag)
        p.do_analysis()
        assns += function_link_assns(p, res, tag)
    if chain == []:
        return None
    recursion_trace.append('  created fun chain %s' % chain)
    word_args = [(i, mk_var(s, typ)) for (i, (s, typ)) in enumerate(args)
                 if typ.kind == 'Word']
    rep = rep_graph.mk_graph_slice(p, fast=True)
    (_, env) = rep.get_node_pc_env((entry, ()))

    m = {}
    res = rep.test_hyp_whyps(syntax.false_term, assns, model=m)
    assert m

    if find_unknown_recursion(p, group, idents, tag, [], []) == None:
        idents.setdefault(fname, [])
        idents[fname].append(syntax.true_term)
        recursion_trace.append('      found final ident for %s' % fname)
        return syntax.true_term
    assert word_args
    recursion_trace.append('      scanning for ident for %s' % fname)
    for (i, arg) in word_args:
        (nm, typ) = functions[fname].inputs[i]
        arg_smt = solver.to_smt_expr(arg, env, rep.solv)
        val = search.eval_model_expr(m, rep.solv, arg_smt)
        if not rep.test_hyp_whyps(mk_eq(arg_smt, val), assns):
            recursion_trace.append('      discarded %s = 0x%x, not stable' %
                                   (nm, val.val))
            continue
        entry_vis = ((entry, ()), tag)
        ass = rep_graph.eq_hyp((arg, entry_vis), (val, entry_vis))
        res = find_unknown_recursion(p, group, idents, tag, assns + [ass], [])
        if res:
            fname2 = p.nodes[res].fname
            recursion_trace.append(
                '      discarded %s, allows recursion to %s' % (nm, fname2))
            continue
        eq = syntax.mk_eq(mk_var(nm, typ), val)
        idents.setdefault(fname, [])
        idents[fname].append(eq)
        recursion_trace.append('    found ident for %s: %s' % (fname, eq))
        return eq
    assert not "identifying assertion found"
示例#39
0
def pretty_lambda (t):
	v = syntax.mk_var ('#seq-visits', word32T)
	t = logic.var_subst (t, {('%i', word32T) : v}, must_subst = False)
	return syntax.pretty_expr (t, print_type = True)
示例#40
0
 def fresh_var(self, name, typ):
     name = fresh_name(name, self.vs, typ)
     return mk_var(name, typ)
示例#41
0
def avail_val(vs, typ):
    for (nm, typ2) in vs:
        if typ2 == typ:
            return mk_var(nm, typ2)
    return logic.default_val(typ)
示例#42
0
def mk_var_list (vs, typ):
	return [syntax.mk_var (v, typ) for v in vs]
示例#43
0
def avail_val (vs, typ):
	for (nm, typ2) in vs:
		if typ2 == typ:
			return mk_var (nm, typ2)
	return logic.default_val (typ)
示例#44
0
def const_ret_hook(node, nm, typ):
    consts = node_const_rets(node)
    return consts and mk_var(nm, typ) in consts
示例#45
0
	def fresh_var (self, name, typ):
		name = fresh_name (name, self.vs, typ)
		return mk_var (name, typ)
示例#46
0
def mk_loop_counter_eq_hyp(p, split, restrs, n):
    details = (split, (0, 1), [])
    (tag, _) = p.node_tags[split]
    visit = split_visit_one_visit(tag, details, restrs, vc_offs(0))
    return eq_hyp((mk_var('%n', word32T), visit), (mk_word32(n), visit),
                  (split, 0))
示例#47
0
def pretty_lambda(t):
    v = syntax.mk_var('#seq-visits', word32T)
    t = logic.var_subst(t, {('%i', word32T): v}, must_subst=False)
    return syntax.pretty_expr(t, print_type=True)
示例#48
0
def const_ret_hook (node, nm, typ):
	consts = node_const_rets (node)
	return consts and mk_var (nm, typ) in consts
示例#49
0
def add_recursion_ident (f, group, idents, extra_unfolds):
	from syntax import mk_eq, mk_implies, mk_var
	p = problem.Problem (None, name = 'Recursion Test')
	chain = []
	tag = 'fun0'
	p.add_entry_function (functions[f], tag)
	p.do_analysis ()
	assns = []
	recursion_last_assns[0] = assns

	while True:
		res = find_unknown_recursion (p, group, idents, tag, assns,
			extra_unfolds)
		if res == None:
			break
		if p.nodes[res].fname not in group:
			problem.inline_at_point (p, res)
			continue
		fname = p.nodes[res].fname
		chain.append (fname)
		tag = 'fun%d' % len (chain)
		(args, _, entry) = p.add_entry_function (functions[fname], tag)
		p.do_analysis ()
		assns += function_link_assns (p, res, tag)
	if chain == []:
		return None
	recursion_trace.append ('  created fun chain %s' % chain)
	word_args = [(i, mk_var (s, typ))
		for (i, (s, typ)) in enumerate (args)
		if typ.kind == 'Word']
	rep = rep_graph.mk_graph_slice (p, fast = True)
	(_, env) = rep.get_node_pc_env ((entry, ()))

	m = {}
	res = rep.test_hyp_whyps (syntax.false_term, assns, model = m)
	assert m

	if find_unknown_recursion (p, group, idents, tag, [], []) == None:
		idents.setdefault (fname, [])
		idents[fname].append (syntax.true_term)
		recursion_trace.append ('      found final ident for %s' % fname)
		return syntax.true_term
	assert word_args
	recursion_trace.append ('      scanning for ident for %s' % fname)
	for (i, arg) in word_args:
		(nm, typ) = functions[fname].inputs[i]
		arg_smt = solver.to_smt_expr (arg, env, rep.solv)
		val = search.eval_model_expr (m, rep.solv, arg_smt)
		if not rep.test_hyp_whyps (mk_eq (arg_smt, val), assns):
			recursion_trace.append ('      discarded %s = 0x%x, not stable' % (nm, val.val))
			continue
		entry_vis = ((entry, ()), tag)
		ass = rep_graph.eq_hyp ((arg, entry_vis), (val, entry_vis))
		res = find_unknown_recursion (p, group, idents, tag,
				assns + [ass], [])
		if res:
			fname2 = p.nodes[res].fname
			recursion_trace.append ('      discarded %s, allows recursion to %s' % (nm, fname2))
			continue
		eq = syntax.mk_eq (mk_var (nm, typ), val)
		idents.setdefault (fname, [])
		idents[fname].append (eq)
		recursion_trace.append ('    found ident for %s: %s' % (fname, eq))
		return eq
	assert not "identifying assertion found"