def apply_known_eqs_tm (self, n_vc, tag): eqs = self.fetch_known_eqs (n_vc, tag) if eqs == None: return lambda x: x eqs = dict ([(x, mk_smt_expr (sexpr, x.typ)) for (x, sexpr) in eqs]) return lambda tm: logic.recursive_term_subst (eqs, tm)
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 contract (self, name, n_vc, val, typ): if val in self.contractions: return self.contractions[val] name = self.local_name_before (name, n_vc) name = self.solv.add_def (name, mk_smt_expr (val, typ), {}) self.contractions[val] = name return name
def simplify_expr_whyps(sexpr, rep, hyps, cache=None, extra_defs={}, bool_hyps=None): if cache == None: cache = {} if bool_hyps == None: bool_hyps = [] if sexpr in extra_defs: sexpr = extra_defs[sexpr] if sexpr in rep.solv.defs: sexpr = rep.solv.defs[sexpr] if sexpr[0] == 'ite': (_, cond, x, y) = sexpr cond_exp = solver.mk_smt_expr(solver.flat_s_expression(cond), syntax.boolT) (mk_nimp, mk_not) = (syntax.mk_n_implies, syntax.mk_not) if rep.test_hyp_whyps(mk_nimp(bool_hyps, cond_exp), hyps, cache=cache): return x elif rep.test_hyp_whyps(mk_nimp(bool_hyps, mk_not(cond_exp)), hyps, cache=cache): return y x = simplify_expr_whyps(x, rep, hyps, cache=cache, extra_defs=extra_defs, bool_hyps=bool_hyps + [cond_exp]) y = simplify_expr_whyps(y, rep, hyps, cache=cache, extra_defs=extra_defs, bool_hyps=bool_hyps + [syntax.mk_not(cond_exp)]) if x == y: return x return ('ite', cond, x, y) return sexpr
def simplify_expr_whyps (sexpr, rep, hyps, cache = None, extra_defs = {}): if cache == None: cache = {} if sexpr in extra_defs: sexpr = extra_defs[sexpr] if sexpr[0] == 'ite': (_, cond, x, y) = sexpr cond_exp = solver.mk_smt_expr (solver.flat_s_expression (cond), syntax.boolT) if rep.test_hyp_whyps (cond_exp, hyps, cache = cache): return x elif rep.test_hyp_whyps (syntax.mk_not (cond_exp), hyps, cache = cache): return y x = simplify_expr_whyps (x, rep, hyps, cache = cache, extra_defs = extra_defs) y = simplify_expr_whyps (y, rep, hyps, cache = cache, extra_defs = extra_defs) if x == y: return x return ('ite', cond, x, y) return sexpr
def get_loop_pc_env (self, split, vcount): vcount2 = dict (vcount) vcount2[split] = vc_num (0) vcount2 = tuple (sorted (vcount2.items ())) prev_pc_env = self.get_node_pc_env ((split, vcount2)) if prev_pc_env == None: return None (_, prev_env) = prev_pc_env def av (nm, typ, mem_name = None): nm2 = '%s_loop_at_%s' % (nm, split) return self.solv.add_var (nm2, typ, mem_name = mem_name) env = {} consts = set () for (nm, typ) in prev_env: check_const = self.fast or (typ in [builtinTs['HTD'], builtinTs['Dom']]) if check_const and self.is_synt_const (nm, typ, split): env[(nm, typ)] = prev_env[(nm, typ)] consts.add ((nm, typ)) else: env[(nm, typ)] = av (nm + '_after', typ, ('Loop', prev_env[(nm, typ)])) for (nm, typ) in prev_env: if (nm, typ) in consts: continue z = self.var_rep_request ((nm, typ), 'Loop', (split, vcount), env) if z: env[(nm, typ)] = z pc = mk_smt_expr (av ('pc_of', boolT), boolT) if self.fast: imp = syntax.mk_implies (pc, prev_pc_env[0]) self.solv.assert_fact (imp, prev_env, unsat_tag = ('LoopPCImp', split)) return (pc, env)
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'
if pc_envs == []: return None if n == 'Err': # we'll never care about variable values here # and there are sometimes a LOT of arcs to Err # so we save a lot of merge effort pc_envs = [(to_smt_expr (pc, env, self.solv), {}) for (pc, env) in pc_envs] (pc, env, large) = merge_envs_pcs (pc_envs, self.solv) if large or len (smt_expr (pc, env, self.solv)) > 80: name = self.path_cond_name ((n, vcount), tag) name = self.solv.add_def (name, pc, env) pc = mk_smt_expr (name, boolT) for (nm, typ) in env: if len (env[(nm, typ)]) > 80: env[(nm, typ)] = self.contract (nm, (n, vcount), env[(nm, typ)], typ) return (pc, env) def contract (self, name, n_vc, val, typ): if val in self.contractions: return self.contractions[val] name = self.local_name_before (name, n_vc) name = self.solv.add_def (name, mk_smt_expr (val, typ), {})