diff --git a/hercules_opt/src/lib.rs b/hercules_opt/src/lib.rs
index b25449e7bd143e82c6d8b2fb39f2d8e238bd5cfa..e9550cd4e143ae161a3dffed071d9a152e727f17 100644
--- a/hercules_opt/src/lib.rs
+++ b/hercules_opt/src/lib.rs
@@ -20,6 +20,7 @@ pub mod loop_bound_canon;
 pub mod outline;
 pub mod phi_elim;
 pub mod pred;
+pub mod reassociate;
 pub mod reuse_products;
 pub mod rewrite_math_expressions;
 pub mod schedule;
@@ -49,6 +50,7 @@ pub use crate::loop_bound_canon::*;
 pub use crate::outline::*;
 pub use crate::phi_elim::*;
 pub use crate::pred::*;
+pub use crate::reassociate::*;
 pub use crate::reuse_products::*;
 pub use crate::rewrite_math_expressions::*;
 pub use crate::schedule::*;
diff --git a/hercules_opt/src/reassociate.rs b/hercules_opt/src/reassociate.rs
new file mode 100644
index 0000000000000000000000000000000000000000..f876c55a854d9d6ab1b183145e3f997f47be56d3
--- /dev/null
+++ b/hercules_opt/src/reassociate.rs
@@ -0,0 +1,37 @@
+use hercules_ir::def_use::*;
+use hercules_ir::ir::*;
+
+use crate::*;
+
+/*
+ * Top level function to run dead code elimination.
+ */
+pub fn reassociate(editor: &mut FunctionEditor) {
+    panic!("Reassociate was called");
+    // Create worklist (starts as all nodes).
+    let mut worklist: Vec<NodeID> = editor.node_ids().collect();
+
+    while let Some(work) = worklist.pop() {
+        // If a node on the worklist is a start node, it is either *the* start
+        // node (which we shouldn't delete), or is a gravestone for an already
+        // deleted node earlier in the worklist. If a node is a return node, it
+        // shouldn't be removed.
+        if editor.func().nodes[work.idx()].is_start() || editor.func().nodes[work.idx()].is_return()
+        {
+            continue;
+        }
+
+        // If a node on the worklist has 0 users, delete it. Add its uses onto
+        // the worklist.
+        if editor.get_users(work).len() == 0 {
+            let uses = get_uses(&editor.func().nodes[work.idx()]);
+            let success = editor.edit(|edit| edit.delete_node(work));
+            if success {
+                // If the edit was performed, then its uses may now be dead.
+                for u in uses.as_ref() {
+                    worklist.push(*u);
+                }
+            }
+        }
+    }
+}
diff --git a/juno_samples/grape_reduction/src/grape.sch b/juno_samples/grape_reduction/src/grape.sch
index 2f4aba679fbbc3471e69bf5918fa3748cefb93b6..3be751171c40343a0992bb4b7d01bf700261123d 100644
--- a/juno_samples/grape_reduction/src/grape.sch
+++ b/juno_samples/grape_reduction/src/grape.sch
@@ -10,10 +10,10 @@ delete-uncalled(*);
 forkify(*);
 fork-guard-elim(*);
 dce(*);
-xdot[true](*);
+// xdot[true](*);
 // fork-tile[8, 0, false, true](*);
 let a = fork-split(*);
-xdot[true](*);
+// xdot[true](*);
 
 
 fixpoint stop after 10 {
@@ -28,12 +28,15 @@ fixpoint stop after 10 {
   dce(entry@inner);
   lift-dc-math(entry@inner);
 }
-xdot[true](*);
+// xdot[true](*);
 
 a2p(*);
 sroa(*);
 xdot[true](*);
 
+// reassociate go brr
+reassociate(*);
+
 gvn(*);
 phi-elim(*);
 ccp(*);
diff --git a/juno_scheduler/src/compile.rs b/juno_scheduler/src/compile.rs
index 361f08a448780bd1c376fe3128ff704488734afc..2c941b795b02a8c2454432fc1e9725f9df81680a 100644
--- a/juno_scheduler/src/compile.rs
+++ b/juno_scheduler/src/compile.rs
@@ -152,6 +152,7 @@ impl FromStr for Appliable {
             "outline" => Ok(Appliable::Pass(ir::Pass::Outline)),
             "phi-elim" => Ok(Appliable::Pass(ir::Pass::PhiElim)),
             "predication" => Ok(Appliable::Pass(ir::Pass::Predication)),
+            "reassociate" => Ok(Appliable::Pass(ir::Pass::Reassociate)),
             "reduce-slf" => Ok(Appliable::Pass(ir::Pass::ReduceSLF)),
             "rename" => Ok(Appliable::Pass(ir::Pass::Rename)),
             "reuse-products" => Ok(Appliable::Pass(ir::Pass::ReuseProducts)),
diff --git a/juno_scheduler/src/ir.rs b/juno_scheduler/src/ir.rs
index aa5926cb93548684664a41bf48d1783597abe888..bee0cf0621939c96edfb4c109703f13d0c7c4527 100644
--- a/juno_scheduler/src/ir.rs
+++ b/juno_scheduler/src/ir.rs
@@ -37,6 +37,7 @@ pub enum Pass {
     PhiElim,
     Predication,
     Print,
+    Reassociate,
     ReduceSLF,
     Rename,
     ReuseProducts,
diff --git a/juno_scheduler/src/pm.rs b/juno_scheduler/src/pm.rs
index 204130573c1a91cb80b71dbf85e0cb596a785ac5..3627c0a02012f492ce7697e9360a03c116c7cb7f 100644
--- a/juno_scheduler/src/pm.rs
+++ b/juno_scheduler/src/pm.rs
@@ -2572,6 +2572,18 @@ fn run_pass(
             pm.delete_gravestones();
             pm.clear_analyses();
         }
+        Pass::Reassociate => {
+            assert!(args.is_empty());
+            for func in build_selection(pm, selection, false) {
+                let Some(mut func) = func else {
+                    continue;
+                };
+                reassociate(&mut func);
+                changed |= func.modified();
+            }
+            pm.delete_gravestones();
+            pm.clear_analyses();
+        }
         Pass::ReduceSLF => {
             assert!(args.is_empty());
             pm.make_fork_join_maps();