about summary refs log tree commit diff
path: root/src/libsyntax
diff options
context:
space:
mode:
authorEric Holk <eric.holk@gmail.com>2012-07-17 17:03:27 -0700
committerEric Holk <eric.holk@gmail.com>2012-07-17 17:46:31 -0700
commit7b8171ef2d03e4a2235b4bf0af255dab1b53bc25 (patch)
tree54194e622a33eacd1c3e04db66304a7c1e60fad0 /src/libsyntax
parentc858eb06546ce2be77fd284f707f76cb820c6211 (diff)
downloadrust-7b8171ef2d03e4a2235b4bf0af255dab1b53bc25.tar.gz
rust-7b8171ef2d03e4a2235b4bf0af255dab1b53bc25.zip
Added liveness analysis for protocols, and removed warnings about empty states.
Diffstat (limited to 'src/libsyntax')
-rw-r--r--src/libsyntax/ext/pipes.rs3
-rw-r--r--src/libsyntax/ext/pipes/liveness.rs91
-rw-r--r--src/libsyntax/ext/pipes/proto.rs20
-rw-r--r--src/libsyntax/syntax.rc1
4 files changed, 115 insertions, 0 deletions
diff --git a/src/libsyntax/ext/pipes.rs b/src/libsyntax/ext/pipes.rs
index bea1c8cae0c..5a1462cea30 100644
--- a/src/libsyntax/ext/pipes.rs
+++ b/src/libsyntax/ext/pipes.rs
@@ -27,6 +27,9 @@ fn expand_proto(cx: ext_ctxt, _sp: span, id: ast::ident,
     // check for errors
     visit(proto, cx);
 
+    // do analysis
+    liveness::analyze(proto, cx);
+
     // compile
     base::mr_item(proto.compile(cx))
 }
diff --git a/src/libsyntax/ext/pipes/liveness.rs b/src/libsyntax/ext/pipes/liveness.rs
new file mode 100644
index 00000000000..4f803992520
--- /dev/null
+++ b/src/libsyntax/ext/pipes/liveness.rs
@@ -0,0 +1,91 @@
+/*
+
+Liveness analysis for protocols. This is useful for a lot of possible
+optimizations.
+
+This analysis computes the "co-live" relationship between
+states. Co-live is defined inductively as follows.
+
+1. u is co-live with v if u can transition to v in one message.
+
+2. u is co-live with v if there exists a w such that u and w are
+co-live, w and v are co-live, and u and w have the same direction.
+
+This relationship approximates when it is safe to store two states in
+the same memory location. If there is no u such u is co-live with
+itself, then the protocol is bounded.
+
+(These assertions could use proofs)
+
+In addition, this analysis does reachability, to warn when we have
+useless states.
+
+The algorithm is a fixpoint computation. For each state, we initialize
+a bitvector containing whether it is co-live with each other state. At
+first we use rule (1) above to set each vector. Then we iterate
+updating the states using rule (2) until there are no changes.
+
+*/
+
+import dvec::extensions;
+
+import std::bitv::{bitv, methods};
+
+import proto::methods;
+import ast_builder::empty_span;
+
+fn analyze(proto: protocol, _cx: ext_ctxt) {
+    #debug("initializing colive analysis");
+    let num_states = proto.num_states();
+    let colive = do (copy proto.states).map_to_vec |state| {
+        let bv = bitv(num_states, false);
+        for state.reachable |s| {
+            bv.set(s.id, true);
+        }
+        bv
+    };
+
+    let mut i = 0;
+    let mut changed = true;
+    while changed {
+        changed = false;
+        #debug("colive iteration %?", i);
+        for colive.eachi |i, this_colive| {
+            let this = proto.get_state_by_id(i);
+            for this_colive.ones |j| {
+                let next = proto.get_state_by_id(j);
+                if this.dir == next.dir {
+                    changed = changed || this_colive.union(colive[j]);
+                }
+            }
+        }
+        i += 1;
+    }
+
+    #debug("colive analysis complete");
+
+    // Determine if we're bounded
+    let mut self_live = ~[];
+    for colive.eachi |i, bv| {
+        if bv.get(i) {
+            vec::push(self_live, proto.get_state_by_id(i))
+        }
+    }
+
+    if self_live.len() > 0 {
+        let states = str::connect(self_live.map(|s| *s.name), ~" ");
+
+        #debug("protocol %s is unbounded due to loops involving: %s",
+               *proto.name, states);
+
+        // Someday this will be configurable with a warning
+        //cx.span_warn(empty_span(),
+        //              #fmt("protocol %s is unbounded due to loops \
+        //                    involving these states: %s",
+        //                   *proto.name,
+        //                   states));
+    }
+    else {
+        #debug("protocol %s is bounded. yay!", *proto.name);
+    }
+}
\ No newline at end of file
diff --git a/src/libsyntax/ext/pipes/proto.rs b/src/libsyntax/ext/pipes/proto.rs
index 1c88732adb0..e9070c79b55 100644
--- a/src/libsyntax/ext/pipes/proto.rs
+++ b/src/libsyntax/ext/pipes/proto.rs
@@ -55,6 +55,7 @@ impl methods for message {
 
 enum state {
     state_(@{
+        id: uint,
         name: ident,
         dir: direction,
         ty_params: ~[ast::ty_param],
@@ -81,6 +82,20 @@ impl methods for state {
         cx.ty_path_ast_builder
             (path(self.name).add_tys(cx.ty_vars(self.ty_params)))
     }
+
+    /// Iterate over the states that can be reached in one message
+    /// from this state.
+    fn reachable(f: fn(state) -> bool) {
+        for self.messages.each |m| {
+            alt m {
+              message(_, _, _, some({state: id, _})) {
+                let state = self.proto.get_state(id);
+                if !f(state) { break }
+              }
+              _ { }
+            }
+        }
+    }
 }
 
 enum protocol {
@@ -104,6 +119,8 @@ impl methods for protocol {
         self.states.find(|i| i.name == name).get()
     }
 
+    fn get_state_by_id(id: uint) -> state { self.states[id] }
+
     fn has_state(name: ident) -> bool {
         self.states.find(|i| i.name == name) != none
     }
@@ -113,6 +130,7 @@ impl methods for protocol {
         let messages = dvec();
 
         let state = state_(@{
+            id: self.states.len(),
             name: name,
             dir: dir,
             ty_params: ty_params,
@@ -127,6 +145,8 @@ impl methods for protocol {
     fn filename() -> ~str {
         ~"proto://" + *self.name
     }
+
+    fn num_states() -> uint { self.states.len() }
 }
 
 trait visitor<Tproto, Tstate, Tmessage> {
diff --git a/src/libsyntax/syntax.rc b/src/libsyntax/syntax.rc
index 9750f2d5bd1..10ff0d336c2 100644
--- a/src/libsyntax/syntax.rc
+++ b/src/libsyntax/syntax.rc
@@ -87,5 +87,6 @@ mod ext {
         mod pipec;
         mod proto;
         mod check;
+        mod liveness;
     }
 }