import syntax::ast::*; import syntax::visit; import option::*; import aux::*; import tstate::ann::{pre_and_post, precond, postcond, prestate, poststate, relax_prestate, relax_precond, relax_poststate, pps_len, true_precond, difference, union, clone, set_in_postcond, set_in_poststate, set_in_poststate_, clear_in_poststate, clear_in_prestate, clear_in_poststate_}; import tritv::*; import driver::session::session; import std::map::hashmap; fn bit_num(fcx: fn_ctxt, c: tsconstr) -> uint { let d = c.def_id; assert (fcx.enclosing.constrs.contains_key(d)); let rslt = fcx.enclosing.constrs.get(d); match_args(fcx, rslt.descs, c.args) } fn promises(fcx: fn_ctxt, p: poststate, c: tsconstr) -> bool { ret promises_(bit_num(fcx, c), p); } fn promises_(n: uint, p: poststate) -> bool { ret tritv_get(p, n) == ttrue; } // v "happens after" u fn seq_trit(u: trit, v: trit) -> trit { alt v { ttrue { ttrue } tfalse { tfalse } dont_care { u } } } // idea: q "happens after" p -- so if something is // 1 in q and 0 in p, it's 1 in the result; however, // if it's 0 in q and 1 in p, it's 0 in the result fn seq_tritv(p: postcond, q: postcond) { let mut i = 0u; assert (p.nbits == q.nbits); while i < p.nbits { tritv_set(i, p, seq_trit(tritv_get(p, i), tritv_get(q, i))); i += 1u; } } fn seq_postconds(fcx: fn_ctxt, ps: ~[postcond]) -> postcond { let sz = vec::len(ps); if sz >= 1u { let prev = tritv_clone(ps[0]); vec::iter_between(ps, 1u, sz, |p| seq_tritv(prev, p) ); ret prev; } else { ret ann::empty_poststate(num_constraints(fcx.enclosing)); } } // Given a list of pres and posts for exprs e0 ... en, // return the precondition for evaluating each expr in order. // So, if e0's post is {x} and e1's pre is {x, y, z}, the entire // precondition shouldn't include x. fn seq_preconds(fcx: fn_ctxt, pps: ~[pre_and_post]) -> precond { let sz: uint = vec::len(pps); let num_vars: uint = num_constraints(fcx.enclosing); fn seq_preconds_go(fcx: fn_ctxt, pps: ~[pre_and_post], idx: uint, first: pre_and_post) -> precond { let mut idx = idx; let mut first = first; loop { let sz: uint = vec::len(pps) - idx; if sz >= 1u { let second = pps[0]; assert (pps_len(second) == num_constraints(fcx.enclosing)); let second_pre = clone(second.precondition); difference(second_pre, first.postcondition); let next_first = clone(first.precondition); union(next_first, second_pre); let next_first_post = clone(first.postcondition); seq_tritv(next_first_post, second.postcondition); idx += 1u; first = {precondition: next_first, postcondition: next_first_post}; } else { ret first.precondition; } } } if sz >= 1u { let first = pps[0]; assert (pps_len(first) == num_vars); ret seq_preconds_go(fcx, pps, 1u, first); } else { ret true_precond(num_vars); } } fn intersect_states(p: prestate, q: prestate) -> prestate { let rslt = tritv_clone(p); tritv_intersect(rslt, q); ret rslt; } fn gen(fcx: fn_ctxt, id: node_id, c: tsconstr) -> bool { ret set_in_postcond(bit_num(fcx, c), node_id_to_ts_ann(fcx.ccx, id).conditions); } fn declare_var(fcx: fn_ctxt, c: tsconstr, pre: prestate) -> prestate { let rslt = clone(pre); relax_prestate(bit_num(fcx, c), rslt); // idea is this is scoped relax_poststate(bit_num(fcx, c), rslt); ret rslt; } fn relax_precond_expr(e: @expr, cx: relax_ctxt, vt: visit::vt) { relax_precond(cx.i as uint, expr_precond(cx.fcx.ccx, e)); visit::visit_expr(e, cx, vt); } fn relax_precond_stmt(s: @stmt, cx: relax_ctxt, vt: visit::vt) { relax_precond(cx.i as uint, stmt_precond(cx.fcx.ccx, *s)); visit::visit_stmt(s, cx, vt); } type relax_ctxt = {fcx: fn_ctxt, i: node_id}; fn relax_precond_block_inner(b: blk, cx: relax_ctxt, vt: visit::vt) { relax_precond(cx.i as uint, block_precond(cx.fcx.ccx, b)); visit::visit_block(b, cx, vt); } fn relax_precond_block(fcx: fn_ctxt, i: node_id, b: blk) { let cx = {fcx: fcx, i: i}; let visitor = visit::default_visitor::(); let visitor = @{visit_block: relax_precond_block_inner, visit_expr: relax_precond_expr, visit_stmt: relax_precond_stmt, visit_item: fn@(_i: @item, _cx: relax_ctxt, _vt: visit::vt) { }, visit_fn: do_nothing with *visitor}; let v1 = visit::mk_vt(visitor); v1.visit_block(b, cx, v1); } fn gen_poststate(fcx: fn_ctxt, id: node_id, c: tsconstr) -> bool { #debug("gen_poststate"); ret set_in_poststate(bit_num(fcx, c), node_id_to_ts_ann(fcx.ccx, id).states); } fn kill_prestate(fcx: fn_ctxt, id: node_id, c: tsconstr) -> bool { ret clear_in_prestate(bit_num(fcx, c), node_id_to_ts_ann(fcx.ccx, id).states); } fn kill_all_prestate(fcx: fn_ctxt, id: node_id) { tritv::tritv_kill(node_id_to_ts_ann(fcx.ccx, id).states.prestate); } fn kill_poststate(fcx: fn_ctxt, id: node_id, c: tsconstr) -> bool { #debug("kill_poststate"); ret clear_in_poststate(bit_num(fcx, c), node_id_to_ts_ann(fcx.ccx, id).states); } fn kill_poststate_(fcx: fn_ctxt, c: tsconstr, post: poststate) -> bool { #debug("kill_poststate_"); ret clear_in_poststate_(bit_num(fcx, c), post); } fn set_in_prestate_constr(fcx: fn_ctxt, c: tsconstr, t: prestate) -> bool { ret set_in_poststate_(bit_num(fcx, c), t); } // // Local Variables: // mode: rust // fill-column: 78; // indent-tabs-mode: nil // c-basic-offset: 4 // buffer-file-coding-system: utf-8-unix // End: //