diff --git a/hercules_opt/src/outline.rs b/hercules_opt/src/outline.rs
index 7a3348707770b9acdadc8c430f8ab945d62c1c4e..ee240846d9ea8df356e2ffe27dcf827636df9366 100644
--- a/hercules_opt/src/outline.rs
+++ b/hercules_opt/src/outline.rs
@@ -228,27 +228,27 @@ pub fn outline(
             outlined.nodes.push(Node::Parameter { index });
         }
 
+        let convert_id = |old| {
+            if let Some(new) = old_to_new_id.get(&old) {
+                // Map a use inside the partition to its new ID in the
+                // outlined function.
+                *new
+            } else if let Some(idx) = outside_id_to_param_idx.get(&old) {
+                // Map a data use outside the partition to the ID of the
+                // corresponding parameter node.
+                NodeID::new(idx + 1)
+            } else {
+                // Map a control use outside the partition to the start
+                // node. This corresponds to the outside predecessors of the
+                // top node and the use of the old start by constant,
+                // dynamic constant, parameter, and undef nodes.
+                NodeID::new(0)
+            }
+        };
+
         // Add the nodes from the partition.
         let mut select_top_phi_inputs = vec![];
         for id in partition.iter() {
-            let convert_id = |old| {
-                if let Some(new) = old_to_new_id.get(&old) {
-                    // Map a use inside the partition to its new ID in the
-                    // outlined function.
-                    *new
-                } else if let Some(idx) = outside_id_to_param_idx.get(&old) {
-                    // Map a data use outside the partition to the ID of the
-                    // corresponding parameter node.
-                    NodeID::new(idx + 1)
-                } else {
-                    // Map a control use outside the partition to the start
-                    // node. This corresponds to the outside predecessors of the
-                    // top node and the use of the old start by constant,
-                    // dynamic constant, parameter, and undef nodes.
-                    NodeID::new(0)
-                }
-            };
-
             let mut node = edit.get_node(*id).clone();
             if let Node::Phi { control, data } = &mut node
                 && *control == top_node
@@ -372,7 +372,7 @@ pub fn outline(
                     if dom_return_values.contains(inside_id) {
                         // If this outside used value dominates this return,
                         // then return the value itself.
-                        *inside_id
+                        convert_id(*inside_id)
                     } else {
                         // If not, then return an Undef. Since this value
                         // doesn't dominate this return, it can't be used on
@@ -408,7 +408,7 @@ pub fn outline(
 
             // Return the return product.
             outlined.nodes.push(Node::Return {
-                control: *exit,
+                control: convert_id(*exit),
                 data: construct_id,
             });
         }
@@ -558,7 +558,7 @@ pub fn outline(
 }
 
 /*
- * Just outlines all of a function accept the entry and return. Minimum work
+ * Just outlines all of a function except the entry and return. Minimum work
  * needed to cause runtime Rust code to be generated as necessary.
  */
 pub fn dumb_outline(
@@ -568,7 +568,9 @@ pub fn dumb_outline(
     dom: &DomTree,
     to_be_function_id: FunctionID,
 ) -> Option<Function> {
-    collapse_returns(editor);
+    if !contains_between_control_flow(editor.func()) {
+        return None;
+    }
     let partition = editor
         .node_ids()
         .filter(|id| {
diff --git a/hercules_opt/src/pass.rs b/hercules_opt/src/pass.rs
index 2d69b5f7e195acd324ca7931592cdfca6e1f2e5f..ccba355aa936cfb5629187e039d480178b6ba005 100644
--- a/hercules_opt/src/pass.rs
+++ b/hercules_opt/src/pass.rs
@@ -659,6 +659,39 @@ impl PassManager {
                     self.clear_analyses();
                 }
                 Pass::Outline => {
+                    self.make_def_uses();
+                    let def_uses = self.def_uses.as_ref().unwrap();
+                    let constants_ref = RefCell::new(std::mem::take(&mut self.module.constants));
+                    let dynamic_constants_ref =
+                        RefCell::new(std::mem::take(&mut self.module.dynamic_constants));
+                    let types_ref = RefCell::new(std::mem::take(&mut self.module.types));
+                    let old_num_funcs = self.module.functions.len();
+                    let mut editors: Vec<_> =
+                        zip(self.module.functions.iter_mut(), def_uses.iter())
+                            .map(|(func, def_use)| {
+                                FunctionEditor::new(
+                                    func,
+                                    &constants_ref,
+                                    &dynamic_constants_ref,
+                                    &types_ref,
+                                    def_use,
+                                )
+                            })
+                            .collect();
+                    for editor in editors.iter_mut() {
+                        collapse_returns(editor);
+                        ensure_between_control_flow(editor);
+                    }
+                    let mut edits: Vec<_> = editors
+                        .into_iter()
+                        .enumerate()
+                        .map(|(idx, editor)| (idx, editor.edits()))
+                        .collect();
+                    self.module.constants = constants_ref.take();
+                    self.module.dynamic_constants = dynamic_constants_ref.take();
+                    self.module.types = types_ref.take();
+                    self.clear_analyses();
+
                     self.make_def_uses();
                     self.make_typing();
                     self.make_control_subgraphs();
@@ -671,7 +704,6 @@ impl PassManager {
                     let dynamic_constants_ref =
                         RefCell::new(std::mem::take(&mut self.module.dynamic_constants));
                     let types_ref = RefCell::new(std::mem::take(&mut self.module.types));
-                    let old_num_funcs = self.module.functions.len();
                     let mut editors: Vec<_> =
                         zip(self.module.functions.iter_mut(), def_uses.iter())
                             .map(|(func, def_use)| {
@@ -701,11 +733,23 @@ impl PassManager {
                     self.module.constants = constants_ref.take();
                     self.module.dynamic_constants = dynamic_constants_ref.take();
                     self.module.types = types_ref.take();
-                    let edits: Vec<_> = editors.into_iter().map(|editor| editor.edits()).collect();
-                    for idx in 0..edits.len() {
+                    edits.extend(
+                        editors
+                            .into_iter()
+                            .enumerate()
+                            .map(|(idx, editor)| (idx, editor.edits())),
+                    );
+
+                    for (func_idx, edit) in edits {
                         if let Some(plans) = self.plans.as_mut() {
-                            repair_plan(&mut plans[idx], &self.module.functions[idx], &edits[idx]);
+                            repair_plan(
+                                &mut plans[func_idx],
+                                &self.module.functions[func_idx],
+                                &edit,
+                            );
                         }
+                    }
+                    for idx in 0..self.module.functions.len() {
                         let grave_mapping = self.module.functions[idx].delete_gravestones();
                         if let Some(plans) = self.plans.as_mut() {
                             plans[idx].fix_gravestones(&grave_mapping);
diff --git a/hercules_opt/src/utils.rs b/hercules_opt/src/utils.rs
index 7c89b9d7f238f9c59be70fc0b6293cb21f95d18c..c32225b50bd1d02500ad210171cde0a58d67b17e 100644
--- a/hercules_opt/src/utils.rs
+++ b/hercules_opt/src/utils.rs
@@ -264,3 +264,49 @@ pub fn collapse_returns(editor: &mut FunctionEditor) -> Option<NodeID> {
     });
     new_return
 }
+
+pub fn contains_between_control_flow(func: &Function) -> bool {
+    let num_control = func.nodes.iter().filter(|node| node.is_control()).count();
+    assert!(num_control >= 2, "PANIC: A Hercules function must have at least two control nodes: a start node and at least one return node.");
+    num_control > 2
+}
+
+/*
+ * Top level function to ensure a Hercules function contains at least one
+ * control node that isn't the start or return nodes.
+ */
+pub fn ensure_between_control_flow(editor: &mut FunctionEditor) -> Option<NodeID> {
+    if !contains_between_control_flow(editor.func()) {
+        let ret = editor
+            .node_ids()
+            .skip(1)
+            .filter(|id| editor.func().nodes[id.idx()].is_control())
+            .next()
+            .unwrap();
+        let Node::Return { control, data } = editor.func().nodes[ret.idx()] else {
+            panic!("PANIC: A Hercules function with only two control nodes must have a return node be the other control node, other than the start node.")
+        };
+        assert_eq!(control, NodeID::new(0), "PANIC: The only other control node in a Hercules function, the return node, is not using the start node.");
+        let mut region_id = None;
+        editor.edit(|mut edit| {
+            edit = edit.delete_node(ret)?;
+            region_id = Some(edit.add_node(Node::Region {
+                preds: Box::new([NodeID::new(0)]),
+            }));
+            edit.add_node(Node::Return {
+                control: region_id.unwrap(),
+                data,
+            });
+            Ok(edit)
+        });
+        region_id
+    } else {
+        Some(
+            editor
+                .get_users(NodeID::new(0))
+                .filter(|id| editor.func().nodes[id.idx()].is_control())
+                .next()
+                .unwrap(),
+        )
+    }
+}