rust/src/comp/middle/tstate/bitvectors.rs

278 lines
8.8 KiB
Rust

import syntax::ast::*;
import syntax::walk;
import std::ivec;
import std::option::*;
import aux::constr_arg_use;
import aux::local_node_id_to_def;
import aux::fn_ctxt;
import aux::fn_info;
import aux::log_tritv;
import aux::log_tritv_err;
import aux::num_constraints;
import aux::cinit;
import aux::cpred;
import aux::ninit;
import aux::npred;
import aux::pred_desc;
import aux::match_args;
import aux::constr_;
import aux::block_precond;
import aux::stmt_precond;
import aux::expr_precond;
import aux::block_prestate;
import aux::expr_prestate;
import aux::stmt_prestate;
import tstate::aux::node_id_to_ts_ann;
import tstate::ann::pre_and_post;
import tstate::ann::precond;
import tstate::ann::postcond;
import tstate::ann::prestate;
import tstate::ann::poststate;
import tstate::ann::relax_prestate;
import tstate::ann::relax_precond;
import tstate::ann::relax_poststate;
import tstate::ann::pps_len;
import tstate::ann::true_precond;
import tstate::ann::empty_prestate;
import tstate::ann::difference;
import tstate::ann::union;
import tstate::ann::intersect;
import tstate::ann::clone;
import tstate::ann::set_in_postcond;
import tstate::ann::set_in_poststate;
import tstate::ann::set_in_poststate_;
import tstate::ann::clear_in_poststate;
import tstate::ann::clear_in_prestate;
import tstate::ann::clear_in_poststate_;
import tritv::*;
fn bit_num(&fn_ctxt fcx, &constr_ c) -> uint {
assert (fcx.enclosing.constrs.contains_key(c.id));
auto rslt = fcx.enclosing.constrs.get(c.id);
alt (c.c) {
case (ninit(_)) {
alt (rslt) {
case (cinit(?n, _, _)) { ret n; }
case (_) {
fcx.ccx.tcx.sess.bug("bit_num: asked for init constraint,"
+ " found a pred constraint");
}
}
}
case (npred(_, ?args)) {
alt (rslt) {
case (cpred(_, ?descs)) {
auto d = *descs;
ret match_args(fcx, d, args);
}
case (_) {
fcx.ccx.tcx.sess.bug("bit_num: asked for pred constraint,"
+ " found an init constraint");
}
}
}
}
}
fn promises(&fn_ctxt fcx, &poststate p, &constr_ c) -> bool {
ret promises_(bit_num(fcx, c), p);
}
fn promises_(uint n, &poststate p) -> bool {
ret tritv_get(p, n) == ttrue;
}
// v "happens after" u
fn seq_trit(trit u, trit v) -> trit {
alt (v) {
case (ttrue) { ttrue }
case (tfalse) { tfalse }
case (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(&postcond p, &postcond q) {
auto 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(&fn_ctxt fcx, &postcond[] ps) -> postcond {
auto sz = ivec::len(ps);
if (sz >= 1u) {
auto prev = tritv_clone(ps.(0));
for (postcond p in ivec::slice(ps, 1u, sz)) {
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(&fn_ctxt fcx, &pre_and_post[] pps) -> precond {
let uint sz = ivec::len(pps);
let uint num_vars = num_constraints(fcx.enclosing);
fn seq_preconds_go(&fn_ctxt fcx, &pre_and_post[] pps,
&pre_and_post first)
-> precond {
let uint sz = ivec::len(pps);
if (sz >= 1u) {
auto second = pps.(0);
assert (pps_len(second) == num_constraints(fcx.enclosing));
auto second_pre = clone(second.precondition);
difference(second_pre, first.postcondition);
auto next_first = clone(first.precondition);
union(next_first, second_pre);
auto next_first_post = clone(first.postcondition);
seq_tritv(next_first_post, second.postcondition);
ret seq_preconds_go(fcx, ivec::slice(pps, 1u, sz),
@rec(precondition=next_first,
postcondition=next_first_post));
}
else {
ret first.precondition;
}
}
if (sz >= 1u) {
auto first = pps.(0);
assert (pps_len(first) == num_vars);
ret seq_preconds_go(fcx, ivec::slice(pps, 1u, sz), first);
} else { ret true_precond(num_vars); }
}
fn intersect_states(&prestate p, &prestate q) -> prestate {
auto rslt = tritv_clone(p);
tritv_intersect(rslt, q);
ret rslt;
}
fn gen(&fn_ctxt fcx, node_id id, &constr_ c) -> bool {
ret set_in_postcond(bit_num(fcx, c),
node_id_to_ts_ann(fcx.ccx, id).conditions);
}
fn declare_var(&fn_ctxt fcx, &constr_ c, prestate pre) -> prestate {
auto 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_block_non_recursive(&fn_ctxt fcx, node_id i, &block b) {
relax_precond(i as uint, block_precond(fcx.ccx, b));
}
fn relax_precond_expr(&fn_ctxt fcx, node_id i, &@expr e) {
relax_precond(i as uint, expr_precond(fcx.ccx, e));
}
fn relax_precond_stmt(&fn_ctxt fcx, node_id i, &@stmt s) {
relax_precond(i as uint, stmt_precond(fcx.ccx, *s));
}
fn relax_precond_block(&fn_ctxt fcx, node_id i, &block b) {
relax_precond_block_non_recursive(fcx, i, b);
// FIXME: should use visit instead
// could at least generalize this pattern
// (also seen in ck::check_states_against_conditions)
let @mutable bool keepgoing = @mutable true;
fn quit(@mutable bool keepgoing, &@item i) {
*keepgoing = false;
}
fn kg(@mutable bool keepgoing) -> bool { ret *keepgoing; }
auto v = rec(visit_block_pre = bind
relax_precond_block_non_recursive(fcx, i, _),
visit_expr_pre = bind relax_precond_expr(fcx, i, _),
visit_stmt_pre = bind relax_precond_stmt(fcx, i, _),
visit_item_pre=bind quit(keepgoing, _),
keep_going=bind kg(keepgoing)
with walk::default_visitor());
walk::walk_block(v, b);
}
fn gen_poststate(&fn_ctxt fcx, node_id id, &constr_ c) -> bool {
log "gen_poststate";
ret set_in_poststate(bit_num(fcx, c),
node_id_to_ts_ann(fcx.ccx, id).states);
}
fn kill_prestate(&fn_ctxt fcx, node_id id, &constr_ c) -> bool {
ret clear_in_prestate(bit_num(fcx, c),
node_id_to_ts_ann(fcx.ccx, id).states);
}
fn kill_poststate(&fn_ctxt fcx, node_id id, &constr_ c) -> bool {
log "kill_poststate";
ret clear_in_poststate(bit_num(fcx, c),
node_id_to_ts_ann(fcx.ccx, id).states);
}
fn clear_in_poststate_expr(&fn_ctxt fcx, &@expr e, &poststate t) {
alt (e.node) {
case (expr_path(?p)) {
alt (ivec::last(p.node.idents)) {
case (some(?i)) {
alt (local_node_id_to_def(fcx, e.id)) {
case (some(def_local(?d_id))) {
clear_in_poststate_(bit_num(fcx,
rec(id=d_id._1,
c=ninit(i))), t);
}
case (some(_)) { /* ignore args (for now...) */ }
case (_) {
fcx.ccx.tcx.sess.bug("clear_in_poststate_expr: \
unbound var"); }
}
}
case (_) { fcx.ccx.tcx.sess.bug("clear_in_poststate_expr"); }
}
}
case (_) { /* do nothing */ }
}
}
fn set_in_poststate_ident(&fn_ctxt fcx, &node_id id, &ident ident,
&poststate t) -> bool {
ret set_in_poststate_(bit_num(fcx, rec(id=id, c=ninit(ident))), t);
}
fn clear_in_poststate_ident(&fn_ctxt fcx, &node_id id, &ident ident,
&node_id parent) -> bool {
ret kill_poststate(fcx, parent, rec(id=id, c=ninit(ident)));
}
fn clear_in_prestate_ident(&fn_ctxt fcx, &node_id id, &ident ident,
&node_id parent) -> bool {
ret kill_prestate(fcx, parent, rec(id=id, c=ninit(ident)));
}
//
// Local Variables:
// mode: rust
// fill-column: 78;
// indent-tabs-mode: nil
// c-basic-offset: 4
// buffer-file-coding-system: utf-8-unix
// compile-command: "make -k -C $RBUILD 2>&1 | sed -e 's/\\/x\\//x:\\//g'";
// End:
//