diff --git a/Cargo.lock b/Cargo.lock
index 73ab201c405dd39e11fb32dc014cde9a8e44fc12..13cadc9592c8e1d95e21c013f465919ffcf6c5ec 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -697,6 +697,15 @@ dependencies = [
  "wasm-bindgen",
 ]
 
+[[package]]
+name = "juno_antideps"
+version = "0.1.0"
+dependencies = [
+ "async-std",
+ "juno_build",
+ "with_builtin_macros",
+]
+
 [[package]]
 name = "juno_build"
 version = "0.1.0"
diff --git a/Cargo.toml b/Cargo.toml
index badc4260d3f2e1dae31d0d8e294c97aeee4b4fc8..1db806f41befe6b20d89b8484e069a4674276d6d 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -24,5 +24,6 @@ members = [
 	"juno_samples/matmul",
 	"juno_samples/casts_and_intrinsics",
 	"juno_samples/nested_ccp",
+	"juno_samples/antideps",
 	#"juno_samples/implicit_clone",
 ]
diff --git a/hercules_cg/src/cpu.rs b/hercules_cg/src/cpu.rs
index fb7f653b9eb9dc9d39846210a4de5547b398c991..a09eacfa621876a570d37bd96e1d1f534e94fa4e 100644
--- a/hercules_cg/src/cpu.rs
+++ b/hercules_cg/src/cpu.rs
@@ -1,13 +1,10 @@
-extern crate bitvec;
 extern crate hercules_ir;
 
-use std::collections::{BTreeMap, VecDeque};
+use std::collections::BTreeMap;
 use std::fmt::{Error, Write};
-use std::iter::{zip, FromIterator};
+use std::iter::zip;
 use std::sync::atomic::{AtomicUsize, Ordering};
 
-use self::bitvec::prelude::*;
-
 use self::hercules_ir::*;
 
 use crate::*;
@@ -28,7 +25,7 @@ pub fn cpu_codegen<W: Write>(
     typing: &Vec<TypeID>,
     control_subgraph: &Subgraph,
     antideps: &Vec<(NodeID, NodeID)>,
-    bbs: &Vec<NodeID>,
+    bbs: &BasicBlocks,
     w: &mut W,
 ) -> Result<(), Error> {
     let ctx = CPUContext {
@@ -54,7 +51,7 @@ struct CPUContext<'a> {
     typing: &'a Vec<TypeID>,
     control_subgraph: &'a Subgraph,
     antideps: &'a Vec<(NodeID, NodeID)>,
-    bbs: &'a Vec<NodeID>,
+    bbs: &'a BasicBlocks,
 }
 
 #[derive(Default, Debug)]
@@ -125,31 +122,9 @@ impl<'a> CPUContext<'a> {
         )?;
 
         // Emit data flow into basic blocks.
-        let mut worklist = VecDeque::from_iter(
-            self.reverse_postorder
-                .into_iter()
-                .filter(|id| !self.function.nodes[id.idx()].is_control()),
-        );
-        let mut visited = bitvec![u8, Lsb0; 0; self.function.nodes.len()];
-        let antideps = flip_antideps(&self.antideps);
-        while let Some(id) = worklist.pop_front() {
-            let node = &self.function.nodes[id.idx()];
-            if node.is_phi()
-                || node.is_reduce()
-                || get_uses(node)
-                    .as_ref()
-                    .into_iter()
-                    .chain(antideps.get(&id).into_iter().flatten())
-                    .all(|u| {
-                        self.function.nodes[u.idx()].is_control()
-                            || self.bbs[u.idx()] != self.bbs[id.idx()]
-                            || visited[u.idx()]
-                    })
-            {
+        for block in self.bbs.1.iter() {
+            for id in block {
                 self.codegen_data_node(*id, &mut blocks)?;
-                visited.set(id.idx(), true);
-            } else {
-                worklist.push_back(id);
             }
         }
 
@@ -240,7 +215,7 @@ impl<'a> CPUContext<'a> {
     ) -> Result<(), Error> {
         match self.function.nodes[id.idx()] {
             Node::Phi { control, ref data } => {
-                let phis = &mut blocks.get_mut(&self.bbs[id.idx()]).unwrap().phis;
+                let phis = &mut blocks.get_mut(&self.bbs.0[id.idx()]).unwrap().phis;
                 let preds = self.function.nodes[control.idx()].try_region().unwrap();
                 write!(
                     phis,
@@ -262,7 +237,7 @@ impl<'a> CPUContext<'a> {
                 write!(phis, "\n")?;
             }
             Node::Parameter { index } => {
-                let body = &mut blocks.get_mut(&self.bbs[id.idx()]).unwrap().body;
+                let body = &mut blocks.get_mut(&self.bbs.0[id.idx()]).unwrap().body;
                 let ty = self.get_type(self.typing[id.idx()]);
                 write!(
                     body,
@@ -274,7 +249,7 @@ impl<'a> CPUContext<'a> {
                 )?;
             }
             Node::Constant { id: cons_id } => {
-                let body = &mut blocks.get_mut(&self.bbs[id.idx()]).unwrap().body;
+                let body = &mut blocks.get_mut(&self.bbs.0[id.idx()]).unwrap().body;
                 write!(body, "  {} = bitcast ", self.get_value(id, false))?;
                 match self.constants[cons_id.idx()] {
                     Constant::Boolean(val) => write!(body, "i1 {} to i1\n", val)?,
@@ -304,7 +279,7 @@ impl<'a> CPUContext<'a> {
                 }
             }
             Node::DynamicConstant { id: dc_id } => {
-                let body = &mut blocks.get_mut(&self.bbs[id.idx()]).unwrap().body;
+                let body = &mut blocks.get_mut(&self.bbs.0[id.idx()]).unwrap().body;
                 // Dynamic constants are all pre-calculated at the top of the
                 // function.
                 write!(
@@ -315,7 +290,7 @@ impl<'a> CPUContext<'a> {
                 )?
             }
             Node::Unary { op, input } => {
-                let body = &mut blocks.get_mut(&self.bbs[id.idx()]).unwrap().body;
+                let body = &mut blocks.get_mut(&self.bbs.0[id.idx()]).unwrap().body;
                 match op {
                     UnaryOperator::Not => write!(
                         body,
@@ -450,7 +425,7 @@ impl<'a> CPUContext<'a> {
                     (BinaryOperator::RSh, _) => "ashr",
                 };
 
-                let body = &mut blocks.get_mut(&self.bbs[id.idx()]).unwrap().body;
+                let body = &mut blocks.get_mut(&self.bbs.0[id.idx()]).unwrap().body;
                 write!(
                     body,
                     "  {} = {} {}, {}\n",
@@ -466,7 +441,7 @@ impl<'a> CPUContext<'a> {
                 second,
                 third,
             } => {
-                let body = &mut blocks.get_mut(&self.bbs[id.idx()]).unwrap().body;
+                let body = &mut blocks.get_mut(&self.bbs.0[id.idx()]).unwrap().body;
                 match op {
                     TernaryOperator::Select => write!(
                         body,
@@ -482,7 +457,7 @@ impl<'a> CPUContext<'a> {
                 intrinsic,
                 ref args,
             } => {
-                let body = &mut blocks.get_mut(&self.bbs[id.idx()]).unwrap().body;
+                let body = &mut blocks.get_mut(&self.bbs.0[id.idx()]).unwrap().body;
                 write!(
                     body,
                     "  {} = call {} {}(",
@@ -502,7 +477,7 @@ impl<'a> CPUContext<'a> {
                 collect,
                 ref indices,
             } => {
-                let body = &mut blocks.get_mut(&self.bbs[id.idx()]).unwrap().body;
+                let body = &mut blocks.get_mut(&self.bbs.0[id.idx()]).unwrap().body;
                 let collect_name = self.get_value(collect, false);
                 let collect_ty = self.typing[collect.idx()];
                 let index_ptr_name =
@@ -534,7 +509,7 @@ impl<'a> CPUContext<'a> {
                 data,
                 ref indices,
             } => {
-                let body = &mut blocks.get_mut(&self.bbs[id.idx()]).unwrap().body;
+                let body = &mut blocks.get_mut(&self.bbs.0[id.idx()]).unwrap().body;
                 let collect_name = self.get_value(collect, false);
                 let collect_ty = self.typing[collect.idx()];
                 let index_ptr_name =
diff --git a/hercules_cg/src/rt.rs b/hercules_cg/src/rt.rs
index 44aad61d72cdc2add0d46522da5d65f32dd58348..890c898d75841c85756f3b6e2dd0011678e7789b 100644
--- a/hercules_cg/src/rt.rs
+++ b/hercules_cg/src/rt.rs
@@ -1,11 +1,8 @@
-extern crate bitvec;
 extern crate hercules_ir;
 
-use std::collections::{BTreeMap, VecDeque};
+use std::collections::BTreeMap;
 use std::fmt::{Error, Write};
-use std::iter::{zip, FromIterator};
-
-use self::bitvec::prelude::*;
+use std::iter::zip;
 
 use self::hercules_ir::*;
 
@@ -23,7 +20,7 @@ pub fn rt_codegen<W: Write>(
     typing: &Vec<TypeID>,
     control_subgraph: &Subgraph,
     antideps: &Vec<(NodeID, NodeID)>,
-    bbs: &Vec<NodeID>,
+    bbs: &BasicBlocks,
     collection_objects: &CollectionObjects,
     callgraph: &CallGraph,
     devices: &Vec<Device>,
@@ -51,7 +48,7 @@ struct RTContext<'a> {
     typing: &'a Vec<TypeID>,
     control_subgraph: &'a Subgraph,
     antideps: &'a Vec<(NodeID, NodeID)>,
-    bbs: &'a Vec<NodeID>,
+    bbs: &'a BasicBlocks,
     collection_objects: &'a CollectionObjects,
     callgraph: &'a CallGraph,
     devices: &'a Vec<Device>,
@@ -215,31 +212,9 @@ impl<'a> RTContext<'a> {
             .collect();
 
         // Emit data flow into basic blocks.
-        let mut worklist = VecDeque::from_iter(
-            self.reverse_postorder
-                .into_iter()
-                .filter(|id| !func.nodes[id.idx()].is_control()),
-        );
-        let mut visited = bitvec![u8, Lsb0; 0; func.nodes.len()];
-        let antideps = flip_antideps(&self.antideps);
-        while let Some(id) = worklist.pop_front() {
-            let node = &func.nodes[id.idx()];
-            if node.is_phi()
-                || node.is_reduce()
-                || get_uses(node)
-                    .as_ref()
-                    .into_iter()
-                    .chain(antideps.get(&id).into_iter().flatten())
-                    .all(|u| {
-                        func.nodes[u.idx()].is_control()
-                            || self.bbs[u.idx()] != self.bbs[id.idx()]
-                            || visited[u.idx()]
-                    })
-            {
+        for block in self.bbs.1.iter() {
+            for id in block {
                 self.codegen_data_node(*id, &mut blocks)?;
-                visited.set(id.idx(), true);
-            } else {
-                worklist.push_back(id);
             }
         }
 
@@ -340,7 +315,7 @@ impl<'a> RTContext<'a> {
         let func = &self.get_func();
         match func.nodes[id.idx()] {
             Node::Parameter { index } => {
-                let block = &mut blocks.get_mut(&self.bbs[id.idx()]).unwrap();
+                let block = &mut blocks.get_mut(&self.bbs.0[id.idx()]).unwrap();
                 write!(
                     block,
                     "                {} = p{};\n",
@@ -349,7 +324,7 @@ impl<'a> RTContext<'a> {
                 )?
             }
             Node::Constant { id: cons_id } => {
-                let block = &mut blocks.get_mut(&self.bbs[id.idx()]).unwrap();
+                let block = &mut blocks.get_mut(&self.bbs.0[id.idx()]).unwrap();
                 write!(block, "                {} = ", self.get_value(id))?;
                 match self.module.constants[cons_id.idx()] {
                     Constant::Boolean(val) => write!(block, "{}bool", val)?,
@@ -384,7 +359,7 @@ impl<'a> RTContext<'a> {
             } => {
                 match self.devices[callee_id.idx()] {
                     Device::LLVM => {
-                        let block = &mut blocks.get_mut(&self.bbs[id.idx()]).unwrap();
+                        let block = &mut blocks.get_mut(&self.bbs.0[id.idx()]).unwrap();
                         write!(
                             block,
                             "                {} = unsafe {{ {}(",
@@ -465,7 +440,7 @@ impl<'a> RTContext<'a> {
                         }
                     }
                     Device::AsyncRust => {
-                        let block = &mut blocks.get_mut(&self.bbs[id.idx()]).unwrap();
+                        let block = &mut blocks.get_mut(&self.bbs.0[id.idx()]).unwrap();
                         write!(
                             block,
                             "                {} = {}(",
diff --git a/hercules_ir/src/antideps.rs b/hercules_ir/src/antideps.rs
index 73ea30302d7022de7c03c0d1b3581e029cdc9ace..8aa9f7d9d38051e6516a96b07105edd17a7864d6 100644
--- a/hercules_ir/src/antideps.rs
+++ b/hercules_ir/src/antideps.rs
@@ -135,7 +135,7 @@ pub fn antideps(
     });
 
     // Second, we generate anti-dependence edges from the dataflow analysis.
-    // There are three cases where an anti-dependence edge is generated:
+    // There are four cases where an anti-dependence edge is generated:
     //
     // 1. A read node and a write node share an object and generation pair on
     //    their `collect` input.
@@ -145,6 +145,9 @@ pub fn antideps(
     // 3. A call node and a write node share an object and generation pair,
     //    where the pair is on any input of the call node and the pair is on the
     //    write's `collect` input.
+    // 4. A call node and another call node share an object and generation pair,
+    //    where the pair is on any input of both call nodes AND the second call
+    //    node is a mutator of the object.
     let mut reads_writes_calls_mut_calls_per_pair: BTreeMap<
         (CollectionObjectID, NodeID),
         (Vec<NodeID>, Vec<NodeID>, Vec<NodeID>, Vec<NodeID>),
@@ -205,28 +208,47 @@ pub fn antideps(
         }
     }
 
-    // Once we've matched reads / writes / calls by object and generation pair,
-    // the pair itself no longer matters.
+    // Once we've grouped reads / writes / calls by pairs, we create pair-wise
+    // anti-dependence edges. Due to loops, a write may technically anti-depend
+    // on a read where the read depends on the write, but we don't want to
+    // generate that anti-dependence edge, since it'll create a cycle during
+    // backend code generation. Thus, if the mutator in an anti-dependence is
+    // the same as the generation of the current pair, don't generate the edge.
     let mut antideps = vec![];
-    for (_, (reads, writes, calls, mut_calls)) in reads_writes_calls_mut_calls_per_pair {
+    for ((_, gen), (reads, writes, calls, mut_calls)) in reads_writes_calls_mut_calls_per_pair {
         // Case 1:
         for read in reads.iter() {
             for write in writes.iter() {
-                antideps.push((*read, *write));
+                if *write != gen {
+                    antideps.push((*read, *write));
+                }
             }
         }
 
         // Case 2:
         for read in reads.iter() {
             for mut_call in mut_calls.iter() {
-                antideps.push((*read, *mut_call));
+                if *mut_call != gen {
+                    antideps.push((*read, *mut_call));
+                }
             }
         }
 
         // Case 3:
         for call in calls.iter().chain(mut_calls.iter()) {
             for write in writes.iter() {
-                antideps.push((*call, *write));
+                if *write != gen {
+                    antideps.push((*call, *write));
+                }
+            }
+        }
+
+        // Case 4:
+        for call in calls.iter().chain(mut_calls.iter()) {
+            for mut_call in mut_calls.iter() {
+                if *mut_call != gen && *call != *mut_call {
+                    antideps.push((*call, *mut_call));
+                }
             }
         }
     }
@@ -247,3 +269,17 @@ pub fn flip_antideps(antideps: &Vec<(NodeID, NodeID)>) -> BTreeMap<NodeID, Vec<N
 
     result
 }
+
+/*
+ * Utility to make a map from node to anti-dependency users (map reads ->
+ * mutators).
+ */
+pub fn map_antideps(antideps: &Vec<(NodeID, NodeID)>) -> BTreeMap<NodeID, Vec<NodeID>> {
+    let mut result: BTreeMap<NodeID, Vec<NodeID>> = BTreeMap::new();
+
+    for (read, mutator) in antideps {
+        result.entry(*read).or_default().push(*mutator);
+    }
+
+    result
+}
diff --git a/hercules_ir/src/dot.rs b/hercules_ir/src/dot.rs
index a8754e78218d1b63a18bc8abd4df074fca193505..5ef16bb1c61846a36b78e308767838c03fb8ede0 100644
--- a/hercules_ir/src/dot.rs
+++ b/hercules_ir/src/dot.rs
@@ -20,7 +20,7 @@ pub fn xdot_module(
     reverse_postorders: &Vec<Vec<NodeID>>,
     doms: Option<&Vec<DomTree>>,
     fork_join_maps: Option<&Vec<HashMap<NodeID, NodeID>>>,
-    bbs: Option<&Vec<Vec<NodeID>>>,
+    bbs: Option<&Vec<BasicBlocks>>,
 ) {
     let mut tmp_path = temp_dir();
     let mut rng = rand::thread_rng();
@@ -55,7 +55,7 @@ pub fn write_dot<W: Write>(
     reverse_postorders: &Vec<Vec<NodeID>>,
     doms: Option<&Vec<DomTree>>,
     fork_join_maps: Option<&Vec<HashMap<NodeID, NodeID>>>,
-    bbs: Option<&Vec<Vec<NodeID>>>,
+    bbs: Option<&Vec<BasicBlocks>>,
     w: &mut W,
 ) -> std::fmt::Result {
     write_digraph_header(w)?;
@@ -173,9 +173,9 @@ pub fn write_dot<W: Write>(
         // Step 4: draw BB edges in olive.
         if let Some(bbs) = bbs {
             let bbs = &bbs[function_id.idx()];
-            for node_idx in 0..bbs.len() {
+            for node_idx in 0..bbs.0.len() {
                 let maybe_data = NodeID::new(node_idx);
-                let control = bbs[node_idx];
+                let control = bbs.0[node_idx];
                 if maybe_data != control {
                     write_edge(
                         maybe_data,
diff --git a/hercules_ir/src/gcm.rs b/hercules_ir/src/gcm.rs
index 35541d18534337888ee94a80134e9f3aa3b3b430..a8fd0a21d83ec1b827954a848481953b0d39ba25 100644
--- a/hercules_ir/src/gcm.rs
+++ b/hercules_ir/src/gcm.rs
@@ -7,6 +7,18 @@ use self::bitvec::prelude::*;
 
 use crate::*;
 
+/*
+ * Basic block info consists of two things:
+ *
+ * 1. A map from node to block (named by control nodes).
+ * 2. For each node, which nodes are in its own block.
+ *
+ * Note that for #2, the structure is Vec<NodeID>, meaning the nodes are ordered
+ * inside the block. This order corresponds to the traversal order of the nodes
+ * in the block needed by the backend code generators.
+ */
+pub type BasicBlocks = (Vec<NodeID>, Vec<Vec<NodeID>>);
+
 /*
  * Top level global code motion function. Assigns each data node to one of its
  * immediate control use / user nodes, forming (unordered) basic blocks. Returns
@@ -22,7 +34,7 @@ pub fn gcm(
     antideps: &Vec<(NodeID, NodeID)>,
     loops: &LoopTree,
     fork_join_map: &HashMap<NodeID, NodeID>,
-) -> Vec<NodeID> {
+) -> BasicBlocks {
     let mut bbs: Vec<Option<NodeID>> = vec![None; function.nodes.len()];
 
     // Step 1: assign the basic block locations of all nodes that must be in a
@@ -57,10 +69,6 @@ pub fn gcm(
     // Step 2: schedule early. Place nodes in the earliest position they could
     // go - use worklist to iterate nodes.
     let mut schedule_early = bbs.clone();
-    let mut antideps_uses = HashMap::<NodeID, Vec<NodeID>>::new();
-    for (read, write) in antideps {
-        antideps_uses.entry(*write).or_default().push(*read);
-    }
     let mut worklist = VecDeque::from(reverse_postorder.clone());
     while let Some(id) = worklist.pop_front() {
         if schedule_early[id.idx()].is_some() {
@@ -73,15 +81,6 @@ pub fn gcm(
             .as_ref()
             .into_iter()
             .map(|id| *id)
-            // TODO: once anti-dependence analysis is fixed, use it in GCM.
-            // Include "uses" from anti-dependencies.
-            //.chain(
-            //    antideps_uses
-            //        .get(&id)
-            //        .unwrap_or(&vec![])
-            //        .into_iter()
-            //        .map(|id| *id),
-            //)
             .map(|id| schedule_early[id.idx()])
             .collect();
         if let Some(use_places) = use_places {
@@ -103,10 +102,6 @@ pub fn gcm(
         .into_iter()
         .map(|(fork, join)| (*join, *fork))
         .collect();
-    let mut antideps_users = HashMap::<NodeID, Vec<NodeID>>::new();
-    for (read, write) in antideps {
-        antideps_users.entry(*read).or_default().push(*write);
-    }
     let mut worklist = VecDeque::from_iter(reverse_postorder.into_iter().map(|id| *id).rev());
     while let Some(id) = worklist.pop_front() {
         if bbs[id.idx()].is_some() {
@@ -128,17 +123,7 @@ pub fn gcm(
 
             // For every user, consider where we need to be to directly dominate the
             // user.
-            for user in def_use.get_users(id).as_ref().into_iter().map(|id| *id)
-            // TODO: once anti-dependence analysis is fixed, use it in GCM.
-            // Include "users" from anti-dependencies.
-            //.chain(
-            //    antideps_users
-            //        .get(&id)
-            //        .unwrap_or(&vec![])
-            //        .into_iter()
-            //        .map(|id| *id),
-            //)
-            {
+            for user in def_use.get_users(id).as_ref().into_iter().map(|id| *id) {
                 if let Node::Phi { control, data } = &function.nodes[user.idx()] {
                     // For phis, we need to dominate the block jumping to the phi in
                     // the slot that corresponds to our use.
@@ -215,8 +200,40 @@ pub fn gcm(
 
         bbs[id.idx()] = Some(location);
     }
+    let bbs: Vec<_> = bbs.into_iter().map(Option::unwrap).collect();
+
+    // Step 4: determine the order of nodes inside each block. Use worklist to
+    // add nodes to blocks in order that obeys dependencies.
+    let mut order: Vec<Vec<NodeID>> = vec![vec![]; function.nodes.len()];
+    let mut worklist = VecDeque::from_iter(
+        reverse_postorder
+            .into_iter()
+            .filter(|id| !function.nodes[id.idx()].is_control()),
+    );
+    let mut visited = bitvec![u8, Lsb0; 0; function.nodes.len()];
+    let antideps = flip_antideps(&antideps);
+    while let Some(id) = worklist.pop_front() {
+        let node = &function.nodes[id.idx()];
+        if node.is_phi()
+            || node.is_reduce()
+            || get_uses(node)
+                .as_ref()
+                .into_iter()
+                .chain(antideps.get(&id).into_iter().flatten())
+                .all(|u| {
+                    function.nodes[u.idx()].is_control()
+                        || bbs[u.idx()] != bbs[id.idx()]
+                        || visited[u.idx()]
+                })
+        {
+            order[bbs[id.idx()].idx()].push(*id);
+            visited.set(id.idx(), true);
+        } else {
+            worklist.push_back(id);
+        }
+    }
 
-    bbs.into_iter().map(Option::unwrap).collect()
+    (bbs, order)
 }
 
 /*
diff --git a/hercules_opt/src/pass.rs b/hercules_opt/src/pass.rs
index 796f8c7945be4bc66e51a9956c26ebe79f486496..c02e967e355f67da934d9e49ffccff8c04e1fc11 100644
--- a/hercules_opt/src/pass.rs
+++ b/hercules_opt/src/pass.rs
@@ -74,7 +74,7 @@ pub struct PassManager {
     pub reduce_cycles: Option<Vec<HashMap<NodeID, HashSet<NodeID>>>>,
     pub antideps: Option<Vec<Vec<(NodeID, NodeID)>>>,
     pub data_nodes_in_fork_joins: Option<Vec<HashMap<NodeID, HashSet<NodeID>>>>,
-    pub bbs: Option<Vec<Vec<NodeID>>>,
+    pub bbs: Option<Vec<BasicBlocks>>,
     pub collection_objects: Option<CollectionObjects>,
     pub callgraph: Option<CallGraph>,
 }
diff --git a/juno_samples/antideps/Cargo.toml b/juno_samples/antideps/Cargo.toml
new file mode 100644
index 0000000000000000000000000000000000000000..40b4d47c57bbe422bfe983ee73a1d140a2ab1b94
--- /dev/null
+++ b/juno_samples/antideps/Cargo.toml
@@ -0,0 +1,17 @@
+[package]
+name = "juno_antideps"
+version = "0.1.0"
+authors = ["Russel Arbore <rarbore2@illinois.edu>"]
+edition = "2021"
+
+[[bin]]
+name = "juno_antideps"
+path = "src/main.rs"
+
+[build-dependencies]
+juno_build = { path = "../../juno_build" }
+
+[dependencies]
+juno_build = { path = "../../juno_build" }
+with_builtin_macros = "0.1.0"
+async-std = "*"
diff --git a/juno_samples/antideps/build.rs b/juno_samples/antideps/build.rs
new file mode 100644
index 0000000000000000000000000000000000000000..757243b829c3f805f8d87d38676e72e2b532f072
--- /dev/null
+++ b/juno_samples/antideps/build.rs
@@ -0,0 +1,10 @@
+extern crate juno_build;
+use juno_build::JunoCompiler;
+
+fn main() {
+    JunoCompiler::new()
+        .file_in_src("antideps.jn")
+        .unwrap()
+        .build()
+        .unwrap();
+}
diff --git a/juno_samples/antideps/src/antideps.jn b/juno_samples/antideps/src/antideps.jn
new file mode 100644
index 0000000000000000000000000000000000000000..f54b8dcf4050f95a749daf336931f746a5a942d1
--- /dev/null
+++ b/juno_samples/antideps/src/antideps.jn
@@ -0,0 +1,24 @@
+#[entry]
+fn simple_antideps(a : usize, b : usize) -> i32 {
+  let arr : i32[3];
+  let r = arr[b];
+  arr[a] = 5;
+  return r + arr[b];
+}
+
+#[entry]
+fn complex_antideps(x : i32) -> i32 {
+  let arr : i32[4];
+  arr[1] = 7;
+  let r = 0;
+  while x > 6 {
+    if x > 5 {
+      r = arr[1];
+    } else {
+      arr[1] = 8;
+      r = arr[1];
+    }
+    x -= 1;
+  }
+  return r;
+}
diff --git a/juno_samples/antideps/src/main.rs b/juno_samples/antideps/src/main.rs
new file mode 100644
index 0000000000000000000000000000000000000000..e613f5ffbec5de4499b7e66279a1feca16883c0e
--- /dev/null
+++ b/juno_samples/antideps/src/main.rs
@@ -0,0 +1,23 @@
+#![feature(future_join, box_as_ptr)]
+
+extern crate async_std;
+extern crate juno_build;
+
+juno_build::juno!("antideps");
+
+fn main() {
+    async_std::task::block_on(async {
+        let output = simple_antideps(1, 1).await;
+        println!("{}", output);
+        assert_eq!(output, 5);
+
+        let output = complex_antideps(9).await;
+        println!("{}", output);
+        assert_eq!(output, 7);
+    });
+}
+
+#[test]
+fn antideps_test() {
+    main();
+}
diff --git a/juno_samples/implicit_clone/src/implicit_clone.jn b/juno_samples/implicit_clone/src/implicit_clone.jn
index 6dfaff6c69cd7d553ba8075b9507d526c3268f82..17e345e51e80db27c0d2f21854e22abf1eefcdb8 100644
--- a/juno_samples/implicit_clone/src/implicit_clone.jn
+++ b/juno_samples/implicit_clone/src/implicit_clone.jn
@@ -1,11 +1,3 @@
-#[entry]
-fn antideps(a : usize, b : usize) -> i32 {
-  let arr : i32[3];
-  let r = arr[b];
-  arr[a] = 5;
-  return r + arr[b];
-}
-
 #[entry]
 fn implicit_clone(input : i32) -> i32 {
   let arr : i32[3];
diff --git a/juno_samples/implicit_clone/src/main.rs b/juno_samples/implicit_clone/src/main.rs
index 73edc4646972bd100c10edbc7c87c930c8003b70..5ff952a36a8052cda2a0031b2551cd6452a727f3 100644
--- a/juno_samples/implicit_clone/src/main.rs
+++ b/juno_samples/implicit_clone/src/main.rs
@@ -7,10 +7,6 @@ juno_build::juno!("implicit_clone");
 
 fn main() {
     async_std::task::block_on(async {
-        let output = antideps(1, 1).await;
-        println!("{}", output);
-        assert_eq!(output, 5);
-
         let output = implicit_clone(3).await;
         println!("{}", output);
         assert_eq!(output, 9);