diff --git a/hercules_ir/src/dot.rs b/hercules_ir/src/dot.rs
index 8efabd7a99157b9bb8b40e5abe76d2d42513bb79..5ccda9dc6bf39c016ba44b6eb1085679288d5c54 100644
--- a/hercules_ir/src/dot.rs
+++ b/hercules_ir/src/dot.rs
@@ -16,6 +16,7 @@ use crate::*;
 pub fn xdot_module(
     module: &ir::Module,
     reverse_postorders: &Vec<Vec<NodeID>>,
+    typing: Option<&ModuleTyping>,
     doms: Option<&Vec<DomTree>>,
     fork_join_maps: Option<&Vec<HashMap<NodeID, NodeID>>>,
     devices: Option<&Vec<Device>>,
@@ -30,6 +31,7 @@ pub fn xdot_module(
     write_dot(
         &module,
         &reverse_postorders,
+        typing,
         doms,
         fork_join_maps,
         devices,
@@ -53,6 +55,7 @@ pub fn xdot_module(
 pub fn write_dot<W: Write>(
     module: &ir::Module,
     reverse_postorders: &Vec<Vec<NodeID>>,
+    typing: Option<&ModuleTyping>,
     doms: Option<&Vec<DomTree>>,
     fork_join_maps: Option<&Vec<HashMap<NodeID, NodeID>>>,
     devices: Option<&Vec<Device>>,
@@ -89,6 +92,7 @@ pub fn write_dot<W: Write>(
                 function_id,
                 color,
                 module,
+                typing,
                 &function.schedules[node_id.idx()],
                 w,
             )?;
@@ -249,6 +253,7 @@ fn write_node<W: Write>(
     function_id: FunctionID,
     color: &str,
     module: &Module,
+    typing: Option<&ModuleTyping>,
     schedules: &Vec<Schedule>,
     w: &mut W,
 ) -> std::fmt::Result {
@@ -331,30 +336,37 @@ fn write_node<W: Write>(
     } else {
         format!("{} ({})", node.upper_case_name(), suffix)
     };
+    let xlabel = format!("{}", node_id.idx());
+    let mut tylabel = String::new();
+    if let Some(ty) = typing.map(|typing| typing[function_id.idx()][node_id.idx()]) {
+        module.write_type(ty, &mut tylabel)?;
+    }
 
     let mut iter = schedules.into_iter();
     if let Some(first) = iter.next() {
-        let subtitle = iter.fold(format!("{:?}", first), |b, i| format!("{}, {:?}", b, i));
+        let schedules = iter.fold(format!("{:?}", first), |b, i| format!("{}, {:?}", b, i));
         write!(
             w,
-            "{}_{}_{} [xlabel={}, label=<{}<BR /><FONT POINT-SIZE=\"8\">{}</FONT>>, color={}];\n",
+            "{}_{}_{} [xlabel={}, label=<{}<BR /><FONT POINT-SIZE=\"8\">{}</FONT><BR /><FONT POINT-SIZE=\"8\">{}</FONT>>, color={}];\n",
             node.lower_case_name(),
             function_id.idx(),
             node_id.idx(),
-            node_id.idx(),
+            xlabel,
             label,
-            subtitle,
+            tylabel,
+            schedules,
             color
         )?;
     } else {
         write!(
             w,
-            "{}_{}_{} [xlabel={}, label=\"{}\", color={}];\n",
+            "{}_{}_{} [xlabel={}, label=<{}<BR /><FONT POINT-SIZE=\"8\">{}</FONT>>, color={}];\n",
             node.lower_case_name(),
             function_id.idx(),
             node_id.idx(),
-            node_id.idx(),
+            xlabel,
             label,
+            tylabel,
             color
         )?;
     }
diff --git a/hercules_ir/src/ir.rs b/hercules_ir/src/ir.rs
index f62c00c15f9e8715254c515834d8fe63c2715539..bf7806dcc371112419bbf7e21ef3b206df3a2e32 100644
--- a/hercules_ir/src/ir.rs
+++ b/hercules_ir/src/ir.rs
@@ -628,6 +628,7 @@ pub fn dynamic_constants_bottom_up(
     dynamic_constants: &Vec<DynamicConstant>,
 ) -> impl Iterator<Item = DynamicConstantID> + '_ {
     let mut visited = bitvec![u8, Lsb0; 0; dynamic_constants.len()];
+    let mut invalid = bitvec![u8, Lsb0; 0; dynamic_constants.len()];
     let mut stack = (0..dynamic_constants.len())
         .map(DynamicConstantID::new)
         .collect::<Vec<DynamicConstantID>>();
@@ -647,13 +648,16 @@ pub fn dynamic_constants_bottom_up(
                     // We have to yield the children of this node before
                     // this node itself. We keep track of which nodes have
                     // yielded using visited.
-                    if left.idx() >= visited.len() || right.idx() >= visited.len() {
+                    if left.idx() >= visited.len()
+                        || right.idx() >= visited.len()
+                        || invalid[left.idx()]
+                        || invalid[right.idx()]
+                    {
                         // This is an invalid dynamic constant and should be
                         // skipped.
+                        invalid.set(id.idx(), true);
                         continue;
-                    }
-                    let can_yield = visited[left.idx()] && visited[right.idx()];
-                    if can_yield {
+                    } else if visited[left.idx()] && visited[right.idx()] {
                         visited.set(id.idx(), true);
                         yield id;
                     } else {
diff --git a/hercules_opt/src/device_placement.rs b/hercules_opt/src/device_placement.rs
deleted file mode 100644
index 2badd69df428db12a0f3a46ac4aee05f8154d171..0000000000000000000000000000000000000000
--- a/hercules_opt/src/device_placement.rs
+++ /dev/null
@@ -1,3 +0,0 @@
-use hercules_ir::ir::*;
-
-use crate::*;
diff --git a/hercules_opt/src/gcm.rs b/hercules_opt/src/gcm.rs
index f919acc7caa822d5693e940a3a4fae05d7900d4a..462d10871565bfed9b351d2627c44af8ca778ffc 100644
--- a/hercules_opt/src/gcm.rs
+++ b/hercules_opt/src/gcm.rs
@@ -1163,11 +1163,12 @@ fn object_allocation(
                 Node::Call {
                     control: _,
                     function: callee,
-                    dynamic_constants: _,
+                    ref dynamic_constants,
                     args: _,
                 } => {
+                    let dynamic_constants = dynamic_constants.clone();
                     for device in BACKED_DEVICES {
-                        if let Some(callee_backing_size) = backing_allocations[&callee]
+                        if let Some(mut callee_backing_size) = backing_allocations[&callee]
                             .get(&device)
                             .map(|(callee_total, _)| *callee_total)
                         {
@@ -1177,6 +1178,27 @@ fn object_allocation(
                             // in the callee, so just assume the largest alignment.
                             *total = align(&mut edit, *total, LARGEST_ALIGNMENT);
                             offsets.insert(id, *total);
+                            // Substitute the dynamic constant parameters in the
+                            // callee's backing size.
+                            let first_dc = edit.num_dynamic_constants() + 10000;
+                            for (p_idx, dc_n) in zip(0..dynamic_constants.len(), first_dc..) {
+                                let dc_a =
+                                    edit.add_dynamic_constant(DynamicConstant::Parameter(p_idx));
+                                callee_backing_size = substitute_dynamic_constants(
+                                    dc_a,
+                                    DynamicConstantID::new(dc_n),
+                                    callee_backing_size,
+                                    &mut edit,
+                                );
+                            }
+                            for (dc_n, dc_b) in zip(first_dc.., dynamic_constants.iter()) {
+                                callee_backing_size = substitute_dynamic_constants(
+                                    DynamicConstantID::new(dc_n),
+                                    *dc_b,
+                                    callee_backing_size,
+                                    &mut edit,
+                                );
+                            }
                             *total = edit.add_dynamic_constant(DynamicConstant::Add(
                                 *total,
                                 callee_backing_size,
diff --git a/hercules_opt/src/inline.rs b/hercules_opt/src/inline.rs
index 064e3d73a1d9604ca5b284fe52b8c2e8c5a0339e..1d2bac97d848ace910d614a42743c6ea5fe3aa9e 100644
--- a/hercules_opt/src/inline.rs
+++ b/hercules_opt/src/inline.rs
@@ -179,7 +179,7 @@ fn inline_func(
                     // as the new references we just made in the first step. We
                     // actually want to institute all the updates
                     // *simultaneously*, hence the two step maneuver.
-                    let first_dc = edit.num_dynamic_constants() + 100;
+                    let first_dc = edit.num_dynamic_constants() + 10000;
                     for (dc_a, dc_n) in zip(dcs_a, first_dc..) {
                         substitute_dynamic_constants_in_node(
                             *dc_a,
diff --git a/hercules_opt/src/interprocedural_sroa.rs b/hercules_opt/src/interprocedural_sroa.rs
index 49fbcbbd712fad2977c64fd2ca1d9643bd95d74c..f597cd80347d94a7c927d6fe085d80f843e280eb 100644
--- a/hercules_opt/src/interprocedural_sroa.rs
+++ b/hercules_opt/src/interprocedural_sroa.rs
@@ -320,7 +320,7 @@ fn compress_return_products(editors: &mut Vec<FunctionEditor>, all_callsites_edi
                 let mut substituted = old_return_type_ids[function_id.idx()];
 
                 assert_eq!(old_dcs.len(), new_dcs.len());
-                let first_dc = edit.num_dynamic_constants() + 100;
+                let first_dc = edit.num_dynamic_constants() + 10000;
                 for (dc_a, dc_n) in zip(old_dcs, first_dc..) {
                     substituted = substitute_dynamic_constants_in_type(
                         dc_a,
@@ -424,7 +424,7 @@ fn remove_return_singletons(editors: &mut Vec<FunctionEditor>, all_callsites_edi
             if singleton_removed[function.idx()] {
                 let edit_successful = editor.edit(|mut edit| {
                     let mut substituted = old_return_type_ids[function.idx()];
-                    let first_dc = edit.num_dynamic_constants() + 100;
+                    let first_dc = edit.num_dynamic_constants() + 10000;
                     let dc_params: Vec<_> = (0..dc_args.len())
                         .map(|param_idx| {
                             edit.add_dynamic_constant(DynamicConstant::Parameter(param_idx))
diff --git a/hercules_opt/src/lib.rs b/hercules_opt/src/lib.rs
index 01ae1c99ad3613e826801afebdb0e15376ae1377..e3cca1612354fee6b5544264b97a37f1352bbafd 100644
--- a/hercules_opt/src/lib.rs
+++ b/hercules_opt/src/lib.rs
@@ -4,7 +4,6 @@ pub mod ccp;
 pub mod crc;
 pub mod dce;
 pub mod delete_uncalled;
-pub mod device_placement;
 pub mod editor;
 pub mod float_collections;
 pub mod fork_concat_split;
@@ -30,7 +29,6 @@ pub use crate::ccp::*;
 pub use crate::crc::*;
 pub use crate::dce::*;
 pub use crate::delete_uncalled::*;
-pub use crate::device_placement::*;
 pub use crate::editor::*;
 pub use crate::float_collections::*;
 pub use crate::fork_concat_split::*;
diff --git a/juno_scheduler/src/pm.rs b/juno_scheduler/src/pm.rs
index 76e81ee9f0147caed9db3714515bd0362bbb3ae4..8b3e90502128df6fb8962692fffd5dc67e1aabb8 100644
--- a/juno_scheduler/src/pm.rs
+++ b/juno_scheduler/src/pm.rs
@@ -1761,12 +1761,14 @@ fn run_pass(
 
             pm.make_reverse_postorders();
             if force_analyses {
+                pm.make_typing();
                 pm.make_doms();
                 pm.make_fork_join_maps();
                 pm.make_devices();
             }
 
             let reverse_postorders = pm.reverse_postorders.take().unwrap();
+            let typing = pm.typing.take();
             let doms = pm.doms.take();
             let fork_join_maps = pm.fork_join_maps.take();
             let devices = pm.devices.take();
@@ -1775,6 +1777,7 @@ fn run_pass(
                 xdot_module(
                     module,
                     &reverse_postorders,
+                    typing.as_ref(),
                     doms.as_ref(),
                     fork_join_maps.as_ref(),
                     devices.as_ref(),