diff --git a/lib/llvm-backend/src/code.rs b/lib/llvm-backend/src/code.rs
index 7a24f9fbf..e177cc375 100644
--- a/lib/llvm-backend/src/code.rs
+++ b/lib/llvm-backend/src/code.rs
@@ -2,21 +2,22 @@ use inkwell::{
     builder::Builder,
     context::Context,
     module::Module,
+    passes::PassManager,
     types::{BasicType, BasicTypeEnum, FunctionType},
-    values::{BasicValue, FunctionValue},
+    values::{BasicValue, FunctionValue, PhiValue},
     FloatPredicate, IntPredicate,
 };
 use smallvec::SmallVec;
 use wasmer_runtime_core::{
     module::ModuleInfo,
     structures::{Map, SliceMap, TypedIndex},
-    types::{FuncIndex, FuncSig, LocalFuncIndex, LocalOrImport, SigIndex, Type},
+    types::{FuncIndex, MemoryIndex, FuncSig, LocalFuncIndex, LocalOrImport, SigIndex, Type, MemoryType},
 };
 use wasmparser::{BinaryReaderError, CodeSectionReader, LocalsReader, Operator, OperatorsReader};
 
 use crate::intrinsics::Intrinsics;
 use crate::read_info::type_to_type;
-use crate::state::State;
+use crate::state::{ControlFrame, IfElseState, State};
 
 fn func_sig_to_llvm(context: &Context, intrinsics: &Intrinsics, sig: &FuncSig) -> FunctionType {
     let user_param_types = sig.params().iter().map(|&ty| type_to_llvm(intrinsics, ty));
@@ -116,10 +117,37 @@ fn parse_function(
     let llvm_sig = &signatures[sig_index];
 
     let function = functions[func_index];
-    let entry_block = context.append_basic_block(&function, "entry");
-    builder.position_at_end(&entry_block);
-
     let mut state = State::new();
+    let entry_block = context.append_basic_block(&function, "entry");
+
+    let return_block = context.append_basic_block(&function, "return");
+    builder.position_at_end(&return_block);
+
+    let phis: SmallVec<[PhiValue; 1]> = func_sig
+        .returns()
+        .iter()
+        .map(|&wasmer_ty| type_to_llvm(intrinsics, wasmer_ty))
+        .map(|ty| builder.build_phi(ty, &state.var_name()))
+        .collect();
+
+    match phis.as_slice() {
+        // No returns.
+        &[] => {
+            builder.build_return(None);
+        }
+        &[one_value] => {
+            let value = one_value.as_basic_value();
+            builder.build_return(Some(&value));
+        }
+        returns @ _ => {
+            // let struct_ty = llvm_sig.get_return_type().as_struct_type();
+            // let ret_struct = struct_ty.const_zero();
+            unimplemented!("multi-value returns not yet implemented")
+        }
+    }
+
+    state.push_block(return_block, phis);
+    builder.position_at_end(&entry_block);
 
     let mut locals = Vec::with_capacity(locals_reader.get_count() as usize);
     locals.extend(function.get_param_iter().enumerate().map(|(index, param)| {
@@ -163,7 +191,7 @@ fn parse_function(
                     offset: -1isize as usize,
                 })?;
 
-                let end_block = context.append_basic_block(&function, &state.block_name());
+                let end_block = context.append_basic_block(&function, "end");
                 builder.position_at_end(&end_block);
 
                 let phis = if let Ok(wasmer_ty) = type_to_type(ty) {
@@ -180,12 +208,24 @@ fn parse_function(
                 builder.position_at_end(&current_block);
             }
             Operator::Loop { ty } => {
+                let loop_body = context.append_basic_block(&function, "loop_body");
+                let loop_next = context.append_basic_block(&function, "loop_outer");
 
-                // let loop_body = context.append_basic_block(&function, &state.block_name());
-                // let next = context.append_basic_block(&function, &state.block_name());
-                // builder.build_unconditional_branch(&body);
-                // let num_return_values = if ty == wasmparser::Type::EmptyBlockType { 0 } else { 1 };
-                // state.push_loop(loop_body, next, num_return_values);
+                builder.build_unconditional_branch(&loop_body);
+
+                builder.position_at_end(&loop_next);
+                let phis = if let Ok(wasmer_ty) = type_to_type(ty) {
+                    let llvm_ty = type_to_llvm(intrinsics, wasmer_ty);
+                    [llvm_ty]
+                        .iter()
+                        .map(|&ty| builder.build_phi(ty, &state.var_name()))
+                        .collect()
+                } else {
+                    SmallVec::new()
+                };
+
+                builder.position_at_end(&loop_body);
+                state.push_loop(loop_body, loop_next, phis);
             }
             Operator::Br { relative_depth } => {
                 let frame = state.frame_at_depth(relative_depth)?;
@@ -195,7 +235,13 @@ fn parse_function(
                     offset: -1isize as usize,
                 })?;
 
-                let values = state.peekn(frame.phis().len())?;
+                let value_len = if frame.is_loop() {
+                    0
+                } else {
+                    frame.phis().len()
+                };
+
+                let values = state.peekn(value_len)?;
 
                 // For each result of the block we're branching to,
                 // pop a value off the value stack and load it into
@@ -204,11 +250,10 @@ fn parse_function(
                     phi.add_incoming(&[(value, &current_block)]);
                 }
 
-                builder.build_unconditional_branch(frame.dest());
+                builder.build_unconditional_branch(frame.br_dest());
 
-                state.popn(frame.phis().len())?;
-
-                builder.build_unreachable();
+                state.popn(value_len)?;
+                state.reachable = false;
             }
             Operator::BrIf { relative_depth } => {
                 let cond = state.pop1()?;
@@ -219,13 +264,19 @@ fn parse_function(
                     offset: -1isize as usize,
                 })?;
 
-                let param_stack = state.peekn(frame.phis().len())?;
+                let value_len = if frame.is_loop() {
+                    0
+                } else {
+                    frame.phis().len()
+                };
+
+                let param_stack = state.peekn(value_len)?;
 
                 for (phi, value) in frame.phis().iter().zip(param_stack.iter()) {
                     phi.add_incoming(&[(value, &current_block)]);
                 }
 
-                let false_block = context.append_basic_block(&function, &state.block_name());
+                let else_block = context.append_basic_block(&function, "else");
 
                 let cond_value = builder.build_int_compare(
                     IntPredicate::NE,
@@ -233,8 +284,8 @@ fn parse_function(
                     intrinsics.i32_zero,
                     &state.var_name(),
                 );
-                builder.build_conditional_branch(cond_value, frame.dest(), &false_block);
-                builder.position_at_end(&false_block);
+                builder.build_conditional_branch(cond_value, frame.br_dest(), &else_block);
+                builder.position_at_end(&else_block);
             }
             Operator::BrTable { ref table } => {
                 let current_block = builder.get_insert_block().ok_or(BinaryReaderError {
@@ -268,25 +319,131 @@ fn parse_function(
                             phi.add_incoming(&[(value, &current_block)]);
                         }
 
-                        Ok((case_index_literal, frame.dest()))
+                        Ok((case_index_literal, frame.br_dest()))
                     })
                     .collect::<Result<_, _>>()?;
 
-                builder.build_switch(index.into_int_value(), default_frame.dest(), &cases[..]);
+                builder.build_switch(index.into_int_value(), default_frame.br_dest(), &cases[..]);
 
                 state.popn(res_len)?;
                 builder.build_unreachable();
             }
+            Operator::If { ty } => {
+                let current_block = builder.get_insert_block().ok_or(BinaryReaderError {
+                    message: "not currently in a block",
+                    offset: -1isize as usize,
+                })?;
+                let if_then_block = context.append_basic_block(&function, "if_then");
+                let if_else_block = context.append_basic_block(&function, "if_else");
+                let end_block = context.append_basic_block(&function, "if_end");
+
+                let end_phis = {
+                    builder.position_at_end(&end_block);
+
+                    let phis = if let Ok(wasmer_ty) = type_to_type(ty) {
+                        let llvm_ty = type_to_llvm(intrinsics, wasmer_ty);
+                        [llvm_ty]
+                            .iter()
+                            .map(|&ty| builder.build_phi(ty, &state.var_name()))
+                            .collect()
+                    } else {
+                        SmallVec::new()
+                    };
+
+                    builder.position_at_end(&current_block);
+                    phis
+                };
+
+                let cond = state.pop1()?;
+
+                let cond_value = builder.build_int_compare(
+                    IntPredicate::NE,
+                    cond.into_int_value(),
+                    intrinsics.i32_zero,
+                    &state.var_name(),
+                );
+
+                builder.build_conditional_branch(cond_value, &if_then_block, &if_else_block);
+                builder.position_at_end(&if_then_block);
+                state.push_if(if_then_block, if_else_block, end_block, end_phis);
+            }
+            Operator::Else => {
+                if state.reachable {
+                    let frame = state.frame_at_depth(0)?;
+                    builder.build_unconditional_branch(frame.code_after());
+                    let current_block = builder.get_insert_block().ok_or(BinaryReaderError {
+                        message: "not currently in a block",
+                        offset: -1isize as usize,
+                    })?;
+
+                    for phi in frame.phis().to_vec().iter().rev() {
+                        let value = state.pop1()?;
+                        phi.add_incoming(&[(&value, &current_block)])
+                    }
+                }
+
+                let (if_else_block, if_else_state) = if let ControlFrame::IfElse {
+                    if_else,
+                    if_else_state,
+                    ..
+                } = state.frame_at_depth_mut(0)?
+                {
+                    (if_else, if_else_state)
+                } else {
+                    unreachable!()
+                };
+
+                *if_else_state = IfElseState::Else;
+
+                builder.position_at_end(if_else_block);
+                state.reachable = true;
+            }
 
             Operator::End => {
                 let frame = state.pop_frame()?;
+                let current_block = builder.get_insert_block().ok_or(BinaryReaderError {
+                    message: "not currently in a block",
+                    offset: -1isize as usize,
+                })?;
+
+                if state.reachable {
+                    builder.build_unconditional_branch(frame.code_after());
+
+                    for phi in frame.phis().iter().rev() {
+                        let value = state.pop1()?;
+                        phi.add_incoming(&[(&value, &current_block)])
+                    }
+                }
+
+                if let ControlFrame::IfElse {
+                    if_else,
+                    next,
+                    phis,
+                    if_else_state,
+                    ..
+                } = &frame
+                {
+                    if let IfElseState::If = if_else_state {
+                        builder.position_at_end(if_else);
+                        builder.build_unconditional_branch(next);
+                    }
+                }
+
+                builder.position_at_end(frame.code_after());
+                state.reset_stack(&frame);
+
+                state.reachable = true;
 
                 // Push each phi value to the value stack.
                 for phi in frame.phis() {
                     state.push1(phi.as_basic_value());
                 }
+            }
+            Operator::Return => {
+                let frame = state.outermost_frame()?;
 
-                state.reset_stack(&frame);
+                builder.build_unconditional_branch(frame.br_dest());
+                state.reachable = false;
             }
 
             Operator::Unreachable => {
@@ -294,6 +451,7 @@ fn parse_function(
                 // If llvm cannot prove that this is never touched,
                 // it will emit a `ud2` instruction on x86_64 arches.
                 builder.build_unreachable();
+                state.reachable = false;
             }
 
             /***************************
@@ -1021,6 +1179,26 @@ fn parse_function(
                 unimplemented!("waiting on better bitcasting support in inkwell")
             }
 
+            Operator::MemoryGrow { reserved } => {
+
+                let memory_grow_const = intrinsics.i32_ty.const_int(reserved as u64, false);
+
+                let memory_index = MemoryIndex::new(reserved);
+                match memory_index.local_or_import(info) {
+                    LocalOrImport::Local(local_mem_index) => {
+                        let mem_desc = &info.memories[local_mem_index];
+                        match mem_desc.memory_type() {
+                            MemoryType::Dynamic => {
+
+                            }
+                        }
+                    },
+                    LocalOrImport::Import(import_mem_index) => {
+
+                    },
+                }
+            }
+
             op @ _ => {
                 println!("{}", module.print_to_string().to_string());
                 unimplemented!("{:?}", op);
@@ -1028,5 +1206,12 @@ fn parse_function(
         }
     }
 
+    let pass_manager = PassManager::create_for_module();
+    pass_manager.add_promote_memory_to_register_pass();
+    pass_manager.add_cfg_simplification_pass();
+    pass_manager.run_on_module(module);
+
+    println!("{}", module.print_to_string().to_string());
+
     Ok(())
 }
diff --git a/lib/llvm-backend/src/intrinsics.rs b/lib/llvm-backend/src/intrinsics.rs
index 8eab37071..ff6847b3b 100644
--- a/lib/llvm-backend/src/intrinsics.rs
+++ b/lib/llvm-backend/src/intrinsics.rs
@@ -54,6 +54,22 @@ pub struct Intrinsics {
     pub i64_zero: IntValue,
     pub f32_zero: FloatValue,
     pub f64_zero: FloatValue,
+
+    // VM intrinsics.
+    pub memory_grow_dynamic_local: FunctionValue,
+    pub memory_grow_static_local: FunctionValue,
+    pub memory_grow_shared_local: FunctionValue,
+    pub memory_grow_dynamic_import: FunctionValue,
+    pub memory_grow_static_import: FunctionValue,
+    pub memory_grow_shared_import: FunctionValue,
+
+    pub memory_size_dynamic_local: FunctionValue,
+    pub memory_size_static_local: FunctionValue,
+    pub memory_size_shared_local: FunctionValue,
+    pub memory_size_dynamic_import: FunctionValue,
+    pub memory_size_static_import: FunctionValue,
+    pub memory_size_shared_import: FunctionValue,
+    // pub ctx_ty: StructType,
 }
 
 impl Intrinsics {
@@ -64,6 +80,7 @@ impl Intrinsics {
         let i64_ty = context.i64_type();
         let f32_ty = context.f32_type();
         let f64_ty = context.f64_type();
+        // let ctx_ty = context.struct_type(&[], false);
 
         let i1_zero = i1_ty.const_int(0, false);
         let i32_zero = i32_ty.const_int(0, false);
@@ -89,6 +106,9 @@ impl Intrinsics {
         let ret_f32_take_f32_f32 = f32_ty.fn_type(&[f32_ty_basic, f32_ty_basic], false);
         let ret_f64_take_f64_f64 = f64_ty.fn_type(&[f64_ty_basic, f64_ty_basic], false);
 
+        let ret_i32_take_i64_i32_i32 = i32_ty.fn_type(&[i64_ty, i32_ty, i32_ty], false);
+        let ret_i32_take_i64_i32 = i32_ty.fn_type(&[i64_ty, i32_ty], false);
+
         Self {
             ctlz_i32: module.add_function("llvm.ctlz.i32", ret_i32_take_i32_i1, None),
             ctlz_i64: module.add_function("llvm.ctlz.i64", ret_i64_take_i64_i1, None),
@@ -138,6 +158,25 @@ impl Intrinsics {
             i64_zero,
             f32_zero,
             f64_zero,
+
+            // VM intrinsics.
+            memory_grow_dynamic_local: module.add_function("vm.memory.grow.dynamic.local", ret_i32_take_i64_i32_i32, None),
+            memory_grow_static_local: module.add_function("vm.memory.grow.static.local", ret_i32_take_i64_i32_i32, None),
+            memory_grow_shared_local: module.add_function("vm.memory.grow.shared.local", ret_i32_take_i64_i32_i32, None),
+            memory_grow_dynamic_import: module.add_function("vm.memory.grow.dynamic.import", ret_i32_take_i64_i32_i32, None),
+            memory_grow_static_import: module.add_function("vm.memory.grow.static.import", ret_i32_take_i64_i32_i32, None),
+            memory_grow_shared_import: module.add_function("vm.memory.grow.shared.import", ret_i32_take_i64_i32_i32, None),
+
+            memory_size_dynamic_local: module.add_function("vm.memory.size.dynamic.local", ret_i32_take_i64_i32, None),
+            memory_size_static_local: module.add_function("vm.memory.size.static.local", ret_i32_take_i64_i32, None),
+            memory_size_shared_local: module.add_function("vm.memory.size.shared.local", ret_i32_take_i64_i32, None),
+            memory_size_dynamic_import: module.add_function("vm.memory.size.dynamic.import", ret_i32_take_i64_i32, None),
+            memory_size_static_import: module.add_function("vm.memory.size.static.import", ret_i32_take_i64_i32, None),
+            memory_size_shared_import: module.add_function("vm.memory.size.shared.import", ret_i32_take_i64_i32, None),
         }
     }
 }
+
+// pub struct CtxType {
+//     ctx_ty: StructType,
+// }
diff --git a/lib/llvm-backend/src/lib.rs b/lib/llvm-backend/src/lib.rs
index 69ed0fa0d..b02b39cbf 100644
--- a/lib/llvm-backend/src/lib.rs
+++ b/lib/llvm-backend/src/lib.rs
@@ -30,21 +30,26 @@ impl Compiler for LLVMCompiler {
 #[test]
 fn test_read_module() {
     use wabt::wat2wasm;
-    let WAT: &'static str = r#"
+    let wat = r#"
         (module
         (type $t0 (func (param i32) (result i32)))
-        (import "env" "memory" (memory 1 1))
-        (import "env" "table" (table 10 anyfunc))
-        (import "env" "global" (global i32))
-        (import "env" "print_i32" (func $print_i32 (type $t0)))
-        (func $identity (type $t0) (param $p0 i32) (result i32)
-            get_local $p0)
-        (func $print_num (export "print_num") (type $t0) (param $p0 i32) (result i32)
-            get_global 0
-            call $identity
-            call $print_i32))
+        (type $t1 (func (result i32)))
+        (func $foo (type $t0) (param i32) (result i32)
+            get_local 0
+            (if
+                (then
+                    i32.const 42
+                    set_local 0
+                )
+                (else 
+                    i32.const 24
+                    set_local 0
+                )
+            )
+            get_local 0
+        ))
     "#;
-    let wasm = wat2wasm(WAT).unwrap();
+    let wasm = wat2wasm(wat).unwrap();
 
     let (info, code_reader) = read_info::read_module(&wasm).unwrap();
 
diff --git a/lib/llvm-backend/src/read_info.rs b/lib/llvm-backend/src/read_info.rs
index c1ac2cf6b..bed91aa90 100644
--- a/lib/llvm-backend/src/read_info.rs
+++ b/lib/llvm-backend/src/read_info.rs
@@ -285,7 +285,12 @@ pub fn type_to_type(ty: WpType) -> Result<Type, BinaryReaderError> {
                 offset: -1isize as usize,
             });
         }
-        _ => panic!("broken invariant, invalid type"),
+        _ => {
+            return Err(BinaryReaderError {
+                message: "that type is not supported as a wasmer type",
+                offset: -1isize as usize,
+            });
+        }
     })
 }
 
diff --git a/lib/llvm-backend/src/state.rs b/lib/llvm-backend/src/state.rs
index e85c7a23c..674eee04c 100644
--- a/lib/llvm-backend/src/state.rs
+++ b/lib/llvm-backend/src/state.rs
@@ -6,33 +6,73 @@ use smallvec::SmallVec;
 use std::cell::Cell;
 use wasmparser::BinaryReaderError;
 
+#[derive(Debug)]
 pub enum ControlFrame {
     Block {
-        end_label: BasicBlock,
+        next: BasicBlock,
         phis: SmallVec<[PhiValue; 1]>,
         stack_size_snapshot: usize,
     },
+    Loop {
+        body: BasicBlock,
+        next: BasicBlock,
+        phis: SmallVec<[PhiValue; 1]>,
+        stack_size_snapshot: usize,
+    },
+    IfElse {
+        if_then: BasicBlock,
+        if_else: BasicBlock,
+        next: BasicBlock,
+        phis: SmallVec<[PhiValue; 1]>,
+        stack_size_snapshot: usize,
+        if_else_state: IfElseState,
+    },
+}
+
+#[derive(Debug)]
+pub enum IfElseState {
+    If,
+    Else,
 }
 
 impl ControlFrame {
-    pub fn dest(&self) -> &BasicBlock {
+    pub fn code_after(&self) -> &BasicBlock {
         match self {
-            ControlFrame::Block { ref end_label, .. } => end_label,
+            ControlFrame::Block { ref next, .. }
+            | ControlFrame::Loop { ref next, .. }
+            | ControlFrame::IfElse { ref next, .. } => next,
+        }
+    }
+
+    pub fn br_dest(&self) -> &BasicBlock {
+        match self {
+            ControlFrame::Block { ref next, .. } | ControlFrame::IfElse { ref next, .. } => next,
+            ControlFrame::Loop { ref body, .. } => body,
         }
     }
 
     pub fn phis(&self) -> &[PhiValue] {
         match self {
-            ControlFrame::Block { ref phis, .. } => phis.as_slice(),
+            ControlFrame::Block { ref phis, .. }
+            | ControlFrame::Loop { ref phis, .. }
+            | ControlFrame::IfElse { ref phis, .. } => phis.as_slice(),
+        }
+    }
+
+    pub fn is_loop(&self) -> bool {
+        match self {
+            ControlFrame::Loop { .. } => true,
+            _ => false,
         }
     }
 }
 
+#[derive(Debug)]
 pub struct State {
     stack: Vec<BasicValueEnum>,
     control_stack: Vec<ControlFrame>,
     value_counter: Cell<usize>,
-    block_counter: Cell<usize>,
+    pub reachable: bool,
 }
 
 impl State {
@@ -41,7 +81,7 @@ impl State {
             stack: vec![],
             control_stack: vec![],
             value_counter: Cell::new(0),
-            block_counter: Cell::new(0),
+            reachable: true,
         }
     }
 
@@ -50,11 +90,26 @@ impl State {
             ControlFrame::Block {
                 stack_size_snapshot,
                 ..
+            }
+            | ControlFrame::Loop {
+                stack_size_snapshot,
+                ..
+            }
+            | ControlFrame::IfElse {
+                stack_size_snapshot,
+                ..
             } => *stack_size_snapshot,
         };
         self.stack.truncate(stack_size_snapshot);
     }
 
+    pub fn outermost_frame(&self) -> Result<&ControlFrame, BinaryReaderError> {
+        self.control_stack.get(0).ok_or(BinaryReaderError {
+            message: "invalid control stack depth",
+            offset: -1isize as usize,
+        })
+    }
+
     pub fn frame_at_depth(&self, depth: u32) -> Result<&ControlFrame, BinaryReaderError> {
         let index = self.control_stack.len() - 1 - (depth as usize);
         self.control_stack.get(index).ok_or(BinaryReaderError {
@@ -63,6 +118,17 @@ impl State {
         })
     }
 
+    pub fn frame_at_depth_mut(
+        &mut self,
+        depth: u32,
+    ) -> Result<&mut ControlFrame, BinaryReaderError> {
+        let index = self.control_stack.len() - 1 - (depth as usize);
+        self.control_stack.get_mut(index).ok_or(BinaryReaderError {
+            message: "invalid control stack depth",
+            offset: -1isize as usize,
+        })
+    }
+
     pub fn pop_frame(&mut self) -> Result<ControlFrame, BinaryReaderError> {
         self.control_stack.pop().ok_or(BinaryReaderError {
             message: "cannot pop from control stack",
@@ -70,13 +136,6 @@ impl State {
         })
     }
 
-    pub fn block_name(&self) -> String {
-        let counter = self.block_counter.get();
-        let s = format!("block{}", counter);
-        self.block_counter.set(counter + 1);
-        s
-    }
-
     pub fn var_name(&self) -> String {
         let counter = self.value_counter.get();
         let s = format!("s{}", counter);
@@ -129,6 +188,12 @@ impl State {
             })
     }
 
+    pub fn popn_save(&mut self, n: usize) -> Result<Vec<BasicValueEnum>, BinaryReaderError> {
+        let v = self.peekn(n)?.to_vec();
+        self.popn(n)?;
+        Ok(v)
+    }
+
     pub fn popn(&mut self, n: usize) -> Result<(), BinaryReaderError> {
         if self.stack.len() < n {
             return Err(BinaryReaderError {
@@ -142,11 +207,37 @@ impl State {
         Ok(())
     }
 
-    pub fn push_block(&mut self, end_label: BasicBlock, phis: SmallVec<[PhiValue; 1]>) {
+    pub fn push_block(&mut self, next: BasicBlock, phis: SmallVec<[PhiValue; 1]>) {
         self.control_stack.push(ControlFrame::Block {
-            end_label,
+            next,
             phis,
             stack_size_snapshot: self.stack.len(),
         });
     }
+
+    pub fn push_loop(&mut self, body: BasicBlock, next: BasicBlock, phis: SmallVec<[PhiValue; 1]>) {
+        self.control_stack.push(ControlFrame::Loop {
+            body,
+            next,
+            phis,
+            stack_size_snapshot: self.stack.len(),
+        });
+    }
+
+    pub fn push_if(
+        &mut self,
+        if_then: BasicBlock,
+        if_else: BasicBlock,
+        next: BasicBlock,
+        phis: SmallVec<[PhiValue; 1]>,
+    ) {
+        self.control_stack.push(ControlFrame::IfElse {
+            if_then,
+            if_else,
+            next,
+            phis,
+            stack_size_snapshot: self.stack.len(),
+            if_else_state: IfElseState::If,
+        });
+    }
 }