def v_id_eq_hyps (v_ids): groups = logic.dict_list ([(k, v) for (v, k) in v_ids.iteritems ()]) hyps = [] for vs in groups.itervalues (): for v in vs[1:]: hyps.append (mk_eq (v, vs[0])) return hyps
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
def add_local_def (self, n, vname, name, val, env): if self.local_defs_unsat: smt_name = self.solv.add_var (name, val.typ) eq = mk_eq (mk_smt_expr (smt_name, val.typ), val) self.solv.assert_fact (eq, env, unsat_tag = ('Def', n, vname)) else: smt_name = self.solv.add_def (name, val, env) return smt_name
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
def convert_recursion_idents (idents): asm_idents = {} for f in idents: if f not in pre_pairings: continue f2 = pre_pairings[f]['ASM'] assert f2 != f asm_idents[f2] = [] for ident in idents[f]: if ident.is_op ('True'): asm_idents[f2].append (ident) elif ident.is_op ('Equals'): [x, y] = ident.vals # this is a bit hacky [i] = [i for (i, (nm, typ)) in enumerate (functions[f].inputs) if x.is_var ((nm, typ))] cc = get_asm_calling_convention (f2) x = cc['args'][i] asm_idents[f2].append (syntax.mk_eq (x, y)) else: assert not 'ident kind convertible' return asm_idents
def convert_recursion_idents(idents): asm_idents = {} for f in idents: if f not in pre_pairings: continue f2 = pre_pairings[f]['ASM'] assert f2 != f asm_idents[f2] = [] for ident in idents[f]: if ident.is_op('True'): asm_idents[f2].append(ident) elif ident.is_op('Equals'): [x, y] = ident.vals # this is a bit hacky [i] = [ i for (i, (nm, typ)) in enumerate(functions[f].inputs) if x.is_var((nm, typ)) ] cc = get_asm_calling_convention(f2) x = cc['args'][i] asm_idents[f2].append(syntax.mk_eq(x, y)) else: assert not 'ident kind convertible' return asm_idents
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"
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"
def to_smt_expr_under_op (expr, env, solv): if expr.kind == 'Op': vals = [to_smt_expr (v, env, solv) for v in expr.vals] return syntax.Expr ('Op', expr.typ, name = expr.name, vals = vals) else: return to_smt_expr (expr, env, solv) def inst_eq_with_envs ((x, env1), (y, env2), solv): x = to_smt_expr_under_op (x, env1, solv) y = to_smt_expr_under_op (y, env2, solv) if x.typ == syntax.builtinTs['RelWrapper']: return logic.apply_rel_wrapper (x, y) else: return mk_eq (x, y) def inst_eqs (eqs, envs, solv): return [inst_eq_with_envs ((x, envs[x_addr]), (y, envs[y_addr]), solv) for ((x, x_addr), (y, y_addr)) in eqs] def subst_induct (expr, induct_var): substs = {('%n', word32T): induct_var} return logic.var_subst (expr, substs, must_subst = False) printed_hyps = {} def print_hyps (hyps): hyps = tuple (hyps) if hyps in printed_hyps: trace ('hyps = %s' % printed_hyps[hyps]) else:
if i != head: k += 1 restrs2 = restrs + ((head, vc_num (k)), ) (pc, env) = rep.get_node_pc_env ((i, restrs2)) return (to_smt_expr (pc, env, rep.solv), to_smt_expr (v_i, env, rep.solv)) return [get_var (i_offs + (k * i_step)) for k in [0, 1, 2]] def expand_var_eqs (knowledge, (v_i, v_j)): (rep, (restrs, _, _, _), _, _) = knowledge if v_j == 'Const': pc_vs = get_var_pc_var_list (knowledge, v_i) (_, v0) = pc_vs[0] return [mk_implies (pc, mk_eq (v, v0)) for (pc, v) in pc_vs[1:]] # sorting the vars guarantees we generate the same # mem eqs each time which is important for the solver (v_i, v_j) = sorted ([v_i, v_j]) pc_vs = zip (get_var_pc_var_list (knowledge, v_i), get_var_pc_var_list (knowledge, v_j)) return [pred for ((pc_i, v_i), (pc_j, v_j)) in pc_vs for pred in [mk_eq (pc_i, pc_j), mk_implies (pc_i, logic.mk_eq_with_cast (v_i, v_j))]] word_ops = {'bvadd':lambda x, y: x + y, 'bvsub':lambda x, y: x - y, 'bvmul':lambda x, y: x * y, 'bvurem':lambda x, y: x % y, 'bvudiv':lambda x, y: x / y, 'bvand':lambda x, y: x & y, 'bvor':lambda x, y: x | y, 'bvxor': lambda x, y: x ^ y, 'bvnot': lambda x: ~ x, 'bvneg': lambda x: - x,
def get_necessary_split_opts (p, head, restrs, hyps, tags = None, iters = None): if not tags: tags = p.pairing.tags [l_tag, r_tag] = tags assert p.node_tags[head][0] == l_tag l_seq_vs = get_interesting_linear_series_exprs (p, head) if not l_seq_vs: return None r_seq_vs = {} for n in init_loops_to_split (p, restrs): if p.node_tags[n][0] == r_tag: vs = get_interesting_linear_series_exprs (p, n) r_seq_vs.update (vs) if not r_seq_vs: return None rep = rep_graph.mk_graph_slice (p, fast = True) def vis (n, i): if n != p.loop_id (n): i = i + 1 return (n, tuple ([(p.loop_id (n), vc_num (i))]) + restrs) smt = lambda expr, n, i: rep.to_smt_expr (expr, vis (n, i)) smt_pc = lambda n, i: rep.get_pc (vis (n, i)) # remove duplicates by concretising l_seq_vs = dict ([(smt (expr, n, 2), (kind, n, expr)) for n in l_seq_vs for (kind, expr) in l_seq_vs[n]]).values () r_seq_vs = dict ([(smt (expr, n, 2), (kind, n, expr)) for n in r_seq_vs for (kind, expr) in r_seq_vs[n]]).values () if iters == None: if [n for n in p.loop_body (head) if p.nodes[n].kind == 'Call']: iters = 5 else: iters = 8 r_seq_end = 1 + 2 * iters l_seq_end = 1 + iters l_seq_ineq = 1 + max ([1 << n for n in range (iters) if 1 << n <= iters]) hyps = hyps + [rep_graph.pc_triv_hyp ((vis (n, r_seq_end), r_tag)) for n in set ([n for (_, n, _) in r_seq_vs])] hyps = hyps + [rep_graph.pc_triv_hyp ((vis (n, l_seq_end), l_tag)) for n in set ([n for (_, n, _) in l_seq_vs])] ex_restrs = [(n, rep_graph.vc_upto (r_seq_end + 1)) for n in set ([p.loop_id (n) for (_, n, _) in r_seq_vs])] hyps = hyps + [check.non_r_err_pc_hyp (tags, restr_others (p, restrs + tuple (ex_restrs), 2))] necessary_split_opts_trace[:] = [] necessary_split_opts_long_trace[:] = [] for (kind, n, expr) in sorted (l_seq_vs): rel_r_seq_vs = [v for v in r_seq_vs if v[0] == kind] if not rel_r_seq_vs: necessary_split_opts_trace.append ((n, 'NoneRelevant')) continue m = {} eq = mk_eq (smt (expr, n, 1), smt (expr, n, l_seq_ineq)) ex_hyps = [rep_graph.pc_true_hyp ((vis (n, i), l_tag)) for i in range (1, l_seq_end + 1)] res = rep.test_hyp_whyps (eq, hyps + ex_hyps, model = m) necessary_split_opts_long_trace.append ((n, eq, hyps + ex_hyps, res, m, smt, smt_pc, (kind, n, expr), r_seq_vs, iters)) if not m: necessary_split_opts_trace.append ((n, None)) continue seq_eq = get_linear_seq_eq (rep, m, smt, smt_pc, (kind, n, expr), r_seq_vs, iters) necessary_split_opts_trace.append ((n, ('Seq', seq_eq))) if not seq_eq: continue ((n2, expr2), (l_start, l_step), (r_start, r_step)) = seq_eq eqs = [rep_graph.eq_hyp ((expr, (vis (n, l_start + (i * l_step)), l_tag)), (expr2, (vis (n2, r_start + (i * r_step)), r_tag))) for i in range (10) if l_start + (i * l_step) <= l_seq_end if r_start + (i * r_step) <= r_seq_end] eq = foldr1 (mk_and, map (rep.interpret_hyp, eqs)) if rep.test_hyp_whyps (eq, hyps): mk_i = lambda i: (l_start + (i * l_step), l_step) mk_j = lambda j: (r_start + (j * r_step), r_step) return [([mk_i (0)], [mk_j (0)]), ([mk_i (0), mk_i (1)], [mk_j (0), mk_j (1)])] n_vcs = entry_path_no_loops (rep, l_tag, m, head) path_hyps = [rep_graph.pc_true_hyp ((n_vc, l_tag)) for n_vc in n_vcs] if rep.test_hyp_whyps (eq, hyps + path_hyps): # immediate case split on difference between entry paths checks = [(hyps, eq_hyp, 'eq') for eq_hyp in eqs] return derive_case_split (rep, n_vcs, checks) necessary_split_opts_trace.append ((n, 'Seq check failed')) return None