diff --git a/src/librustc_trans/trans/abi.rs b/src/librustc_trans/trans/abi.rs
index 46a76b60989..192522214e6 100644
--- a/src/librustc_trans/trans/abi.rs
+++ b/src/librustc_trans/trans/abi.rs
@@ -10,9 +10,8 @@
 
 use llvm::{self, ValueRef};
 use trans::base;
-use trans::build::B;
 use trans::builder::Builder;
-use trans::common::{type_is_fat_ptr, Block};
+use trans::common::{type_is_fat_ptr, BlockAndBuilder};
 use trans::context::CrateContext;
 use trans::cabi_x86;
 use trans::cabi_x86_64;
@@ -169,18 +168,16 @@ impl ArgType {
         }
     }
 
-    pub fn store_fn_arg(&self, bcx: Block, idx: &mut usize, dst: ValueRef) {
+    pub fn store_fn_arg(&self, bcx: &BlockAndBuilder, idx: &mut usize, dst: ValueRef) {
         if self.pad.is_some() {
             *idx += 1;
         }
         if self.is_ignore() {
             return;
         }
-        let val = llvm::get_param(bcx.fcx.llfn, *idx as c_uint);
+        let val = llvm::get_param(bcx.fcx().llfn, *idx as c_uint);
         *idx += 1;
-        if !bcx.unreachable.get() {
-            self.store(&B(bcx), val, dst);
-        }
+        self.store(bcx, val, dst);
     }
 }
 
diff --git a/src/librustc_trans/trans/adt.rs b/src/librustc_trans/trans/adt.rs
index 436963ec26d..45a1236647e 100644
--- a/src/librustc_trans/trans/adt.rs
+++ b/src/librustc_trans/trans/adt.rs
@@ -1065,6 +1065,15 @@ pub fn num_args(r: &Repr, discr: Disr) -> usize {
 /// Access a field, at a point when the value's case is known.
 pub fn trans_field_ptr<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, r: &Repr<'tcx>,
                                    val: MaybeSizedValue, discr: Disr, ix: usize) -> ValueRef {
+    trans_field_ptr_builder(&bcx.build(), r, val, discr, ix)
+}
+
+/// Access a field, at a point when the value's case is known.
+pub fn trans_field_ptr_builder<'blk, 'tcx>(bcx: &BlockAndBuilder<'blk, 'tcx>,
+                                           r: &Repr<'tcx>,
+                                           val: MaybeSizedValue,
+                                           discr: Disr, ix: usize)
+                                           -> ValueRef {
     // Note: if this ever needs to generate conditionals (e.g., if we
     // decide to do some kind of cdr-coding-like non-unique repr
     // someday), it will need to return a possibly-new bcx as well.
@@ -1087,13 +1096,15 @@ pub fn trans_field_ptr<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, r: &Repr<'tcx>,
             assert_eq!(machine::llsize_of_alloc(bcx.ccx(), ty), 0);
             // The contents of memory at this pointer can't matter, but use
             // the value that's "reasonable" in case of pointer comparison.
-            PointerCast(bcx, val.value, ty.ptr_to())
+            if bcx.is_unreachable() { return C_undef(ty.ptr_to()); }
+            bcx.pointercast(val.value, ty.ptr_to())
         }
         RawNullablePointer { nndiscr, nnty, .. } => {
             assert_eq!(ix, 0);
             assert_eq!(discr, nndiscr);
             let ty = type_of::type_of(bcx.ccx(), nnty);
-            PointerCast(bcx, val.value, ty.ptr_to())
+            if bcx.is_unreachable() { return C_undef(ty.ptr_to()); }
+            bcx.pointercast(val.value, ty.ptr_to())
         }
         StructWrappedNullablePointer { ref nonnull, nndiscr, .. } => {
             assert_eq!(discr, nndiscr);
@@ -1102,33 +1113,39 @@ pub fn trans_field_ptr<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, r: &Repr<'tcx>,
     }
 }
 
-pub fn struct_field_ptr<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, st: &Struct<'tcx>, val: MaybeSizedValue,
-                                    ix: usize, needs_cast: bool) -> ValueRef {
+fn struct_field_ptr<'blk, 'tcx>(bcx: &BlockAndBuilder<'blk, 'tcx>,
+                                st: &Struct<'tcx>, val: MaybeSizedValue,
+                                ix: usize, needs_cast: bool) -> ValueRef {
     let ccx = bcx.ccx();
+    let fty = st.fields[ix];
+    let ll_fty = type_of::in_memory_type_of(bcx.ccx(), fty);
+    if bcx.is_unreachable() {
+        return C_undef(ll_fty.ptr_to());
+    }
+
     let ptr_val = if needs_cast {
         let fields = st.fields.iter().map(|&ty| {
             type_of::in_memory_type_of(ccx, ty)
         }).collect::<Vec<_>>();
         let real_ty = Type::struct_(ccx, &fields[..], st.packed);
-        PointerCast(bcx, val.value, real_ty.ptr_to())
+        bcx.pointercast(val.value, real_ty.ptr_to())
     } else {
         val.value
     };
 
-    let fty = st.fields[ix];
     // Simple case - we can just GEP the field
     //   * First field - Always aligned properly
     //   * Packed struct - There is no alignment padding
     //   * Field is sized - pointer is properly aligned already
     if ix == 0 || st.packed || type_is_sized(bcx.tcx(), fty) {
-        return StructGEP(bcx, ptr_val, ix);
+        return bcx.struct_gep(ptr_val, ix);
     }
 
     // If the type of the last field is [T] or str, then we don't need to do
     // any adjusments
     match fty.sty {
         ty::TySlice(..) | ty::TyStr => {
-            return StructGEP(bcx, ptr_val, ix);
+            return bcx.struct_gep(ptr_val, ix);
         }
         _ => ()
     }
@@ -1137,7 +1154,7 @@ pub fn struct_field_ptr<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, st: &Struct<'tcx>, v
     if !val.has_meta() {
         debug!("Unsized field `{}`, of `{:?}` has no metadata for adjustment",
                ix, Value(ptr_val));
-        return StructGEP(bcx, ptr_val, ix);
+        return bcx.struct_gep(ptr_val, ix);
     }
 
     let dbloc = DebugLoc::None;
@@ -1178,22 +1195,21 @@ pub fn struct_field_ptr<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, st: &Struct<'tcx>, v
     //   (unaligned offset + (align - 1)) & -align
 
     // Calculate offset
-    let align_sub_1 = Sub(bcx, align, C_uint(bcx.ccx(), 1u64), dbloc);
-    let offset = And(bcx,
-                     Add(bcx, unaligned_offset, align_sub_1, dbloc),
-                     Neg(bcx, align, dbloc),
-                     dbloc);
+    dbloc.apply(bcx.fcx());
+    let align_sub_1 = bcx.sub(align, C_uint(bcx.ccx(), 1u64));
+    let offset = bcx.and(bcx.add(unaligned_offset, align_sub_1),
+                         bcx.neg(align));
 
     debug!("struct_field_ptr: DST field offset: {:?}", Value(offset));
 
     // Cast and adjust pointer
-    let byte_ptr = PointerCast(bcx, ptr_val, Type::i8p(bcx.ccx()));
-    let byte_ptr = GEP(bcx, byte_ptr, &[offset]);
+    let byte_ptr = bcx.pointercast(ptr_val, Type::i8p(bcx.ccx()));
+    let byte_ptr = bcx.gep(byte_ptr, &[offset]);
 
     // Finally, cast back to the type expected
     let ll_fty = type_of::in_memory_type_of(bcx.ccx(), fty);
     debug!("struct_field_ptr: Field type is {:?}", ll_fty);
-    PointerCast(bcx, byte_ptr, ll_fty.ptr_to())
+    bcx.pointercast(byte_ptr, ll_fty.ptr_to())
 }
 
 pub fn fold_variants<'blk, 'tcx, F>(bcx: Block<'blk, 'tcx>,
@@ -1284,7 +1300,8 @@ pub fn trans_drop_flag_ptr<'blk, 'tcx>(mut bcx: Block<'blk, 'tcx>,
                 }
             ));
             bcx = fold_variants(bcx, r, val, |variant_cx, st, value| {
-                let ptr = struct_field_ptr(variant_cx, st, MaybeSizedValue::sized(value),
+                let ptr = struct_field_ptr(&variant_cx.build(), st,
+                                           MaybeSizedValue::sized(value),
                                            (st.fields.len() - 1), false);
                 datum::Datum::new(ptr, ptr_ty, datum::Lvalue::new("adt::trans_drop_flag_ptr"))
                     .store_to(variant_cx, scratch.val)
diff --git a/src/librustc_trans/trans/base.rs b/src/librustc_trans/trans/base.rs
index 76085b394c1..6add4fee567 100644
--- a/src/librustc_trans/trans/base.rs
+++ b/src/librustc_trans/trans/base.rs
@@ -911,33 +911,43 @@ pub fn load_if_immediate<'blk, 'tcx>(cx: Block<'blk, 'tcx>, v: ValueRef, t: Ty<'
 /// differs from the type used for SSA values. Also handles various special cases where the type
 /// gives us better information about what we are loading.
 pub fn load_ty<'blk, 'tcx>(cx: Block<'blk, 'tcx>, ptr: ValueRef, t: Ty<'tcx>) -> ValueRef {
-    if cx.unreachable.get() || type_is_zero_size(cx.ccx(), t) {
+    if cx.unreachable.get() {
         return C_undef(type_of::type_of(cx.ccx(), t));
     }
+    load_ty_builder(&B(cx), ptr, t)
+}
+
+pub fn load_ty_builder<'a, 'tcx>(b: &Builder<'a, 'tcx>, ptr: ValueRef, t: Ty<'tcx>) -> ValueRef {
+    let ccx = b.ccx;
+    if type_is_zero_size(ccx, t) {
+        return C_undef(type_of::type_of(ccx, t));
+    }
 
     unsafe {
         let global = llvm::LLVMIsAGlobalVariable(ptr);
         if !global.is_null() && llvm::LLVMIsGlobalConstant(global) == llvm::True {
             let val = llvm::LLVMGetInitializer(global);
             if !val.is_null() {
-                return to_immediate(cx, val, t);
+                if t.is_bool() {
+                    return llvm::LLVMConstTrunc(val, Type::i1(ccx).to_ref());
+                }
+                return val;
             }
         }
     }
 
-    let val = if t.is_bool() {
-        LoadRangeAssert(cx, ptr, 0, 2, llvm::False)
+    if t.is_bool() {
+        b.trunc(b.load_range_assert(ptr, 0, 2, llvm::False), Type::i1(ccx))
     } else if t.is_char() {
         // a char is a Unicode codepoint, and so takes values from 0
         // to 0x10FFFF inclusive only.
-        LoadRangeAssert(cx, ptr, 0, 0x10FFFF + 1, llvm::False)
-    } else if (t.is_region_ptr() || t.is_unique()) && !common::type_is_fat_ptr(cx.tcx(), t) {
-        LoadNonNull(cx, ptr)
+        b.load_range_assert(ptr, 0, 0x10FFFF + 1, llvm::False)
+    } else if (t.is_region_ptr() || t.is_unique()) &&
+              !common::type_is_fat_ptr(ccx.tcx(), t) {
+        b.load_nonnull(ptr)
     } else {
-        Load(cx, ptr)
-    };
-
-    to_immediate(cx, val, t)
+        b.load(ptr)
+    }
 }
 
 /// Helper for storing values in memory. Does the necessary conversion if the in-memory type
@@ -1644,13 +1654,14 @@ impl<'blk, 'tcx> FunctionContext<'blk, 'tcx> {
                                                                    uninit_reason,
                                                                    arg_scope_id, |bcx, dst| {
                         debug!("FunctionContext::bind_args: {:?}: {:?}", hir_arg, arg_ty);
+                        let b = &bcx.build();
                         if common::type_is_fat_ptr(bcx.tcx(), arg_ty) {
                             let meta = &self.fn_ty.args[idx];
                             idx += 1;
-                            arg.store_fn_arg(bcx, &mut llarg_idx, expr::get_dataptr(bcx, dst));
-                            meta.store_fn_arg(bcx, &mut llarg_idx, expr::get_meta(bcx, dst));
+                            arg.store_fn_arg(b, &mut llarg_idx, expr::get_dataptr(bcx, dst));
+                            meta.store_fn_arg(b, &mut llarg_idx, expr::get_meta(bcx, dst));
                         } else {
-                            arg.store_fn_arg(bcx, &mut llarg_idx, dst);
+                            arg.store_fn_arg(b, &mut llarg_idx, dst);
                         }
                         bcx
                     }))
@@ -1672,13 +1683,14 @@ impl<'blk, 'tcx> FunctionContext<'blk, 'tcx> {
                     for (j, &tupled_arg_ty) in tupled_arg_tys.iter().enumerate() {
                         let dst = StructGEP(bcx, llval, j);
                         let arg = &self.fn_ty.args[idx];
+                        let b = &bcx.build();
                         if common::type_is_fat_ptr(bcx.tcx(), tupled_arg_ty) {
                             let meta = &self.fn_ty.args[idx];
                             idx += 1;
-                            arg.store_fn_arg(bcx, &mut llarg_idx, expr::get_dataptr(bcx, dst));
-                            meta.store_fn_arg(bcx, &mut llarg_idx, expr::get_meta(bcx, dst));
+                            arg.store_fn_arg(b, &mut llarg_idx, expr::get_dataptr(bcx, dst));
+                            meta.store_fn_arg(b, &mut llarg_idx, expr::get_meta(bcx, dst));
                         } else {
-                            arg.store_fn_arg(bcx, &mut llarg_idx, dst);
+                            arg.store_fn_arg(b, &mut llarg_idx, dst);
                         }
                     }
                     bcx
@@ -2024,13 +2036,14 @@ pub fn trans_ctor_shim<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
             let lldestptr = adt::trans_field_ptr(bcx, &repr, dest_val, Disr::from(disr), i);
             let arg = &fcx.fn_ty.args[arg_idx];
             arg_idx += 1;
+            let b = &bcx.build();
             if common::type_is_fat_ptr(bcx.tcx(), arg_ty) {
                 let meta = &fcx.fn_ty.args[arg_idx];
                 arg_idx += 1;
-                arg.store_fn_arg(bcx, &mut llarg_idx, expr::get_dataptr(bcx, lldestptr));
-                meta.store_fn_arg(bcx, &mut llarg_idx, expr::get_meta(bcx, lldestptr));
+                arg.store_fn_arg(b, &mut llarg_idx, expr::get_dataptr(bcx, lldestptr));
+                meta.store_fn_arg(b, &mut llarg_idx, expr::get_meta(bcx, lldestptr));
             } else {
-                arg.store_fn_arg(bcx, &mut llarg_idx, lldestptr);
+                arg.store_fn_arg(b, &mut llarg_idx, lldestptr);
             }
         }
         adt::trans_set_discr(bcx, &repr, dest, disr);
diff --git a/src/librustc_trans/trans/closure.rs b/src/librustc_trans/trans/closure.rs
index 24ce44b076f..2036feb31a2 100644
--- a/src/librustc_trans/trans/closure.rs
+++ b/src/librustc_trans/trans/closure.rs
@@ -53,7 +53,7 @@ fn load_closure_environment<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
     let llenv = if kind == ty::ClosureKind::FnOnce && !env_arg.is_indirect() {
         let closure_ty = node_id_type(bcx, id);
         let llenv = rvalue_scratch_datum(bcx, closure_ty, "closure_env").val;
-        env_arg.store_fn_arg(bcx, &mut env_idx, llenv);
+        env_arg.store_fn_arg(&bcx.build(), &mut env_idx, llenv);
         llenv
     } else {
         get_param(bcx.fcx.llfn, env_idx as c_uint)
@@ -410,7 +410,7 @@ fn trans_fn_once_adapter_shim<'a, 'tcx>(
                                                 InitAlloca::Dropped,
                                                 self_scope_id, |bcx, llval| {
             let mut llarg_idx = self_idx;
-            env_arg.store_fn_arg(bcx, &mut llarg_idx, llval);
+            env_arg.store_fn_arg(&bcx.build(), &mut llarg_idx, llval);
             bcx.fcx.schedule_lifetime_end(self_scope_id, llval);
             bcx
         })).val
diff --git a/src/librustc_trans/trans/common.rs b/src/librustc_trans/trans/common.rs
index 7872da58ae2..db06b2352fd 100644
--- a/src/librustc_trans/trans/common.rs
+++ b/src/librustc_trans/trans/common.rs
@@ -688,6 +688,10 @@ impl<'blk, 'tcx> BlockAndBuilder<'blk, 'tcx> {
 
     // Methods delegated to bcx
 
+    pub fn is_unreachable(&self) -> bool {
+        self.bcx.unreachable.get()
+    }
+
     pub fn ccx(&self) -> &'blk CrateContext<'blk, 'tcx> {
         self.bcx.ccx()
     }
diff --git a/src/librustc_trans/trans/glue.rs b/src/librustc_trans/trans/glue.rs
index a2bf4d3f753..4ca5fb07c98 100644
--- a/src/librustc_trans/trans/glue.rs
+++ b/src/librustc_trans/trans/glue.rs
@@ -371,7 +371,8 @@ fn trans_struct_drop<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
     bcx.fcx.pop_and_trans_custom_cleanup_scope(bcx, contents_scope)
 }
 
-pub fn size_and_align_of_dst<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, t: Ty<'tcx>, info: ValueRef)
+pub fn size_and_align_of_dst<'blk, 'tcx>(bcx: &BlockAndBuilder<'blk, 'tcx>,
+                                         t: Ty<'tcx>, info: ValueRef)
                                          -> (ValueRef, ValueRef) {
     debug!("calculate size of DST: {}; with lost info: {:?}",
            t, Value(info));
@@ -385,6 +386,10 @@ pub fn size_and_align_of_dst<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, t: Ty<'tcx>, in
         let align = C_uint(bcx.ccx(), align);
         return (size, align);
     }
+    if bcx.is_unreachable() {
+        let llty = Type::int(bcx.ccx());
+        return (C_undef(llty), C_undef(llty));
+    }
     match t.sty {
         ty::TyStruct(def, substs) => {
             let ccx = bcx.ccx();
@@ -407,8 +412,6 @@ pub fn size_and_align_of_dst<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, t: Ty<'tcx>, in
             let field_ty = monomorphize::field_ty(bcx.tcx(), substs, last_field);
             let (unsized_size, unsized_align) = size_and_align_of_dst(bcx, field_ty, info);
 
-            let dbloc = DebugLoc::None;
-
             // FIXME (#26403, #27023): We should be adding padding
             // to `sized_size` (to accommodate the `unsized_align`
             // required of the unsized field that follows) before
@@ -417,14 +420,14 @@ pub fn size_and_align_of_dst<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, t: Ty<'tcx>, in
             // here. But this is where the add would go.)
 
             // Return the sum of sizes and max of aligns.
-            let mut size = Add(bcx, sized_size, unsized_size, dbloc);
+            let mut size = bcx.add(sized_size, unsized_size);
 
             // Issue #27023: If there is a drop flag, *now* we add 1
             // to the size.  (We can do this without adding any
             // padding because drop flags do not have any alignment
             // constraints.)
             if sizing_type.needs_drop_flag() {
-                size = Add(bcx, size, C_uint(bcx.ccx(), 1_u64), dbloc);
+                size = bcx.add(size, C_uint(bcx.ccx(), 1_u64));
             }
 
             // Choose max of two known alignments (combined value must
@@ -435,14 +438,9 @@ pub fn size_and_align_of_dst<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, t: Ty<'tcx>, in
                     // pick the correct alignment statically.
                     C_uint(ccx, std::cmp::max(sized_align, unsized_align))
                 }
-                _ => Select(bcx,
-                            ICmp(bcx,
-                                 llvm::IntUGT,
-                                 sized_align,
-                                 unsized_align,
-                                 dbloc),
-                            sized_align,
-                            unsized_align)
+                _ => bcx.select(bcx.icmp(llvm::IntUGT, sized_align, unsized_align),
+                                sized_align,
+                                unsized_align)
             };
 
             // Issue #27023: must add any necessary padding to `size`
@@ -456,19 +454,18 @@ pub fn size_and_align_of_dst<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, t: Ty<'tcx>, in
             //
             //   `(size + (align-1)) & -align`
 
-            let addend = Sub(bcx, align, C_uint(bcx.ccx(), 1_u64), dbloc);
-            let size = And(
-                bcx, Add(bcx, size, addend, dbloc), Neg(bcx, align, dbloc), dbloc);
+            let addend = bcx.sub(align, C_uint(bcx.ccx(), 1_u64));
+            let size = bcx.and(bcx.add(size, addend), bcx.neg(align));
 
             (size, align)
         }
         ty::TyTrait(..) => {
             // info points to the vtable and the second entry in the vtable is the
             // dynamic size of the object.
-            let info = PointerCast(bcx, info, Type::int(bcx.ccx()).ptr_to());
-            let size_ptr = GEPi(bcx, info, &[1]);
-            let align_ptr = GEPi(bcx, info, &[2]);
-            (Load(bcx, size_ptr), Load(bcx, align_ptr))
+            let info = bcx.pointercast(info, Type::int(bcx.ccx()).ptr_to());
+            let size_ptr = bcx.gepi(info, &[1]);
+            let align_ptr = bcx.gepi(info, &[2]);
+            (bcx.load(size_ptr), bcx.load(align_ptr))
         }
         ty::TySlice(_) | ty::TyStr => {
             let unit_ty = t.sequence_element_type(bcx.tcx());
@@ -477,7 +474,7 @@ pub fn size_and_align_of_dst<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, t: Ty<'tcx>, in
             let llunit_ty = sizing_type_of(bcx.ccx(), unit_ty);
             let unit_align = llalign_of_min(bcx.ccx(), llunit_ty);
             let unit_size = llsize_of_alloc(bcx.ccx(), llunit_ty);
-            (Mul(bcx, info, C_uint(bcx.ccx(), unit_size), DebugLoc::None),
+            (bcx.mul(info, C_uint(bcx.ccx(), unit_size)),
              C_uint(bcx.ccx(), unit_align))
         }
         _ => bcx.sess().bug(&format!("Unexpected unsized type, found {}", t))
@@ -522,7 +519,8 @@ fn make_drop_glue<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, v0: ValueRef, g: DropGlueK
                     let bcx = drop_ty(bcx, v0, content_ty, DebugLoc::None);
                     let info = expr::get_meta(bcx, v0);
                     let info = Load(bcx, info);
-                    let (llsize, llalign) = size_and_align_of_dst(bcx, content_ty, info);
+                    let (llsize, llalign) =
+                        size_and_align_of_dst(&bcx.build(), content_ty, info);
 
                     // `Box<ZeroSizeType>` does not allocate.
                     let needs_free = ICmp(bcx,
diff --git a/src/librustc_trans/trans/intrinsic.rs b/src/librustc_trans/trans/intrinsic.rs
index b99cb2b6331..736803c573e 100644
--- a/src/librustc_trans/trans/intrinsic.rs
+++ b/src/librustc_trans/trans/intrinsic.rs
@@ -430,7 +430,8 @@ pub fn trans_intrinsic_call<'a, 'blk, 'tcx>(mut bcx: Block<'blk, 'tcx>,
         (_, "size_of_val") => {
             let tp_ty = *substs.types.get(FnSpace, 0);
             if !type_is_sized(tcx, tp_ty) {
-                let (llsize, _) = glue::size_and_align_of_dst(bcx, tp_ty, llargs[1]);
+                let (llsize, _) =
+                    glue::size_and_align_of_dst(&bcx.build(), tp_ty, llargs[1]);
                 llsize
             } else {
                 let lltp_ty = type_of::type_of(ccx, tp_ty);
@@ -444,7 +445,8 @@ pub fn trans_intrinsic_call<'a, 'blk, 'tcx>(mut bcx: Block<'blk, 'tcx>,
         (_, "min_align_of_val") => {
             let tp_ty = *substs.types.get(FnSpace, 0);
             if !type_is_sized(tcx, tp_ty) {
-                let (_, llalign) = glue::size_and_align_of_dst(bcx, tp_ty, llargs[1]);
+                let (_, llalign) =
+                    glue::size_and_align_of_dst(&bcx.build(), tp_ty, llargs[1]);
                 llalign
             } else {
                 C_uint(ccx, type_of::align_of(ccx, tp_ty))
diff --git a/src/librustc_trans/trans/mir/block.rs b/src/librustc_trans/trans/mir/block.rs
index 547382daab3..0128cceab1e 100644
--- a/src/librustc_trans/trans/mir/block.rs
+++ b/src/librustc_trans/trans/mir/block.rs
@@ -26,7 +26,7 @@ use trans::glue;
 use trans::type_::Type;
 
 use super::{MirContext, drop};
-use super::lvalue::LvalueRef;
+use super::lvalue::{LvalueRef, load_fat_ptr};
 use super::operand::OperandRef;
 use super::operand::OperandValue::{self, FatPtr, Immediate, Ref};
 
@@ -478,13 +478,9 @@ impl<'bcx, 'tcx> MirContext<'bcx, 'tcx> {
         let base_repr = adt::represent_type(bcx.ccx(), lv_ty);
         let base = adt::MaybeSizedValue::sized(lv.llval);
         for (n, &ty) in result_types.iter().enumerate() {
-            let ptr = bcx.with_block(|bcx| {
-                adt::trans_field_ptr(bcx, &base_repr, base, Disr(0), n)
-            });
+            let ptr = adt::trans_field_ptr_builder(bcx, &base_repr, base, Disr(0), n);
             let val = if common::type_is_fat_ptr(bcx.tcx(), ty) {
-                let (lldata, llextra) = bcx.with_block(|bcx| {
-                    base::load_fat_ptr(bcx, ptr, ty)
-                });
+                let (lldata, llextra) = load_fat_ptr(bcx, ptr);
                 FatPtr(lldata, llextra)
             } else {
                 // Don't bother loading the value, trans_argument will.
diff --git a/src/librustc_trans/trans/mir/lvalue.rs b/src/librustc_trans/trans/mir/lvalue.rs
index f109bf07f20..b6f942c4637 100644
--- a/src/librustc_trans/trans/mir/lvalue.rs
+++ b/src/librustc_trans/trans/mir/lvalue.rs
@@ -12,8 +12,10 @@ use llvm::ValueRef;
 use rustc::middle::ty::{self, Ty, TypeFoldable};
 use rustc::mir::repr as mir;
 use rustc::mir::tcx::LvalueTy;
+use trans::abi;
 use trans::adt;
 use trans::base;
+use trans::builder::Builder;
 use trans::common::{self, BlockAndBuilder};
 use trans::consts;
 use trans::machine;
@@ -54,6 +56,18 @@ impl<'tcx> LvalueRef<'tcx> {
     }
 }
 
+pub fn get_meta(b: &Builder, fat_ptr: ValueRef) -> ValueRef {
+    b.struct_gep(fat_ptr, abi::FAT_PTR_EXTRA)
+}
+
+pub fn get_dataptr(b: &Builder, fat_ptr: ValueRef) -> ValueRef {
+    b.struct_gep(fat_ptr, abi::FAT_PTR_ADDR)
+}
+
+pub fn load_fat_ptr(b: &Builder, fat_ptr: ValueRef) -> (ValueRef, ValueRef) {
+    (b.load(get_dataptr(b, fat_ptr)), b.load(get_meta(b, fat_ptr)))
+}
+
 impl<'bcx, 'tcx> MirContext<'bcx, 'tcx> {
     pub fn lvalue_len(&mut self,
                       bcx: &BlockAndBuilder<'bcx, 'tcx>,
@@ -130,14 +144,12 @@ impl<'bcx, 'tcx> MirContext<'bcx, 'tcx> {
                 let (llprojected, llextra) = match projection.elem {
                     mir::ProjectionElem::Deref => {
                         let base_ty = tr_base.ty.to_ty(tcx);
-                        bcx.with_block(|bcx| {
-                            if common::type_is_sized(tcx, projected_ty.to_ty(tcx)) {
-                                (base::load_ty(bcx, tr_base.llval, base_ty),
-                                 ptr::null_mut())
-                            } else {
-                                base::load_fat_ptr(bcx, tr_base.llval, base_ty)
-                            }
-                        })
+                        if common::type_is_sized(tcx, projected_ty.to_ty(tcx)) {
+                            (base::load_ty_builder(bcx, tr_base.llval, base_ty),
+                             ptr::null_mut())
+                        } else {
+                            load_fat_ptr(bcx, tr_base.llval)
+                        }
                     }
                     mir::ProjectionElem::Field(ref field, _) => {
                         let base_ty = tr_base.ty.to_ty(tcx);
@@ -153,9 +165,8 @@ impl<'bcx, 'tcx> MirContext<'bcx, 'tcx> {
                         } else {
                             adt::MaybeSizedValue::unsized_(tr_base.llval, tr_base.llextra)
                         };
-                        let llprojected = bcx.with_block(|bcx| {
-                            adt::trans_field_ptr(bcx, &base_repr, base, Disr(discr), field.index())
-                        });
+                        let llprojected = adt::trans_field_ptr_builder(bcx, &base_repr, base,
+                                                                       Disr(discr), field.index());
                         let llextra = if is_sized {
                             ptr::null_mut()
                         } else {
diff --git a/src/librustc_trans/trans/mir/mod.rs b/src/librustc_trans/trans/mir/mod.rs
index b7364b30f06..9df2cb712b1 100644
--- a/src/librustc_trans/trans/mir/mod.rs
+++ b/src/librustc_trans/trans/mir/mod.rs
@@ -14,14 +14,12 @@ use middle::ty;
 use rustc::mir::repr as mir;
 use rustc::mir::tcx::LvalueTy;
 use trans::base;
-use trans::build;
 use trans::common::{self, Block, BlockAndBuilder, FunctionContext};
-use trans::expr;
 
 use std::ops::Deref;
 use std::rc::Rc;
 
-use self::lvalue::LvalueRef;
+use self::lvalue::{LvalueRef, get_dataptr, get_meta};
 use self::operand::OperandRef;
 
 #[derive(Clone)]
@@ -185,26 +183,25 @@ fn arg_value_refs<'bcx, 'tcx>(bcx: &BlockAndBuilder<'bcx, 'tcx>,
                 _ => unreachable!("spread argument isn't a tuple?!")
             };
 
-            let llval = bcx.with_block(|bcx| {
-                let lltemp = base::alloc_ty(bcx, arg_ty, &format!("arg{}", arg_index));
-                for (i, &tupled_arg_ty) in tupled_arg_tys.iter().enumerate() {
-                    let dst = build::StructGEP(bcx, lltemp, i);
-                    let arg = &fcx.fn_ty.args[idx];
+            let lltemp = bcx.with_block(|bcx| {
+                base::alloc_ty(bcx, arg_ty, &format!("arg{}", arg_index))
+            });
+            for (i, &tupled_arg_ty) in tupled_arg_tys.iter().enumerate() {
+                let dst = bcx.struct_gep(lltemp, i);
+                let arg = &fcx.fn_ty.args[idx];
                     idx += 1;
-                    if common::type_is_fat_ptr(tcx, tupled_arg_ty) {
+                if common::type_is_fat_ptr(tcx, tupled_arg_ty) {
                         // We pass fat pointers as two words, but inside the tuple
                         // they are the two sub-fields of a single aggregate field.
-                        let meta = &fcx.fn_ty.args[idx];
-                        idx += 1;
-                        arg.store_fn_arg(bcx, &mut llarg_idx, expr::get_dataptr(bcx, dst));
-                        meta.store_fn_arg(bcx, &mut llarg_idx, expr::get_meta(bcx, dst));
-                    } else {
-                        arg.store_fn_arg(bcx, &mut llarg_idx, dst);
-                    }
+                    let meta = &fcx.fn_ty.args[idx];
+                    idx += 1;
+                    arg.store_fn_arg(bcx, &mut llarg_idx, get_dataptr(bcx, dst));
+                    meta.store_fn_arg(bcx, &mut llarg_idx, get_meta(bcx, dst));
+                } else {
+                    arg.store_fn_arg(bcx, &mut llarg_idx, dst);
                 }
-                lltemp
-            });
-            return LvalueRef::new_sized(llval, LvalueTy::from_ty(arg_ty));
+            }
+            return LvalueRef::new_sized(lltemp, LvalueTy::from_ty(arg_ty));
         }
 
         let arg = &fcx.fn_ty.args[idx];
@@ -218,23 +215,23 @@ fn arg_value_refs<'bcx, 'tcx>(bcx: &BlockAndBuilder<'bcx, 'tcx>,
             llarg_idx += 1;
             llarg
         } else {
-            bcx.with_block(|bcx| {
-                let lltemp = base::alloc_ty(bcx, arg_ty, &format!("arg{}", arg_index));
-                if common::type_is_fat_ptr(tcx, arg_ty) {
-                    // we pass fat pointers as two words, but we want to
-                    // represent them internally as a pointer to two words,
-                    // so make an alloca to store them in.
-                    let meta = &fcx.fn_ty.args[idx];
-                    idx += 1;
-                    arg.store_fn_arg(bcx, &mut llarg_idx, expr::get_dataptr(bcx, lltemp));
-                    meta.store_fn_arg(bcx, &mut llarg_idx, expr::get_meta(bcx, lltemp));
-                } else  {
-                    // otherwise, arg is passed by value, so make a
-                    // temporary and store it there
-                    arg.store_fn_arg(bcx, &mut llarg_idx, lltemp);
-                }
-                lltemp
-            })
+            let lltemp = bcx.with_block(|bcx| {
+                base::alloc_ty(bcx, arg_ty, &format!("arg{}", arg_index))
+            });
+            if common::type_is_fat_ptr(tcx, arg_ty) {
+                // we pass fat pointers as two words, but we want to
+                // represent them internally as a pointer to two words,
+                // so make an alloca to store them in.
+                let meta = &fcx.fn_ty.args[idx];
+                idx += 1;
+                arg.store_fn_arg(bcx, &mut llarg_idx, get_dataptr(bcx, lltemp));
+                meta.store_fn_arg(bcx, &mut llarg_idx, get_meta(bcx, lltemp));
+            } else  {
+                // otherwise, arg is passed by value, so make a
+                // temporary and store it there
+                arg.store_fn_arg(bcx, &mut llarg_idx, lltemp);
+            }
+            lltemp
         };
         LvalueRef::new_sized(llval, LvalueTy::from_ty(arg_ty))
     }).collect()
diff --git a/src/librustc_trans/trans/mir/operand.rs b/src/librustc_trans/trans/mir/operand.rs
index d1b2025fd4c..6df4502fbc8 100644
--- a/src/librustc_trans/trans/mir/operand.rs
+++ b/src/librustc_trans/trans/mir/operand.rs
@@ -19,6 +19,7 @@ use trans::glue;
 
 use std::fmt;
 
+use super::lvalue::load_fat_ptr;
 use super::{MirContext, TempRef, drop};
 
 /// The representation of a Rust value. The enum variant is in fact
@@ -94,14 +95,10 @@ impl<'bcx, 'tcx> MirContext<'bcx, 'tcx> {
 
         let val = match datum::appropriate_rvalue_mode(bcx.ccx(), ty) {
             datum::ByValue => {
-                bcx.with_block(|bcx| {
-                    OperandValue::Immediate(base::load_ty(bcx, llval, ty))
-                })
+                OperandValue::Immediate(base::load_ty_builder(bcx, llval, ty))
             }
             datum::ByRef if common::type_is_fat_ptr(bcx.tcx(), ty) => {
-                let (lldata, llextra) = bcx.with_block(|bcx| {
-                    base::load_fat_ptr(bcx, llval, ty)
-                });
+                let (lldata, llextra) = load_fat_ptr(bcx, llval);
                 OperandValue::FatPtr(lldata, llextra)
             }
             datum::ByRef => OperandValue::Ref(llval)
diff --git a/src/librustc_trans/trans/mir/rvalue.rs b/src/librustc_trans/trans/mir/rvalue.rs
index e31083f05e1..b63af3489b3 100644
--- a/src/librustc_trans/trans/mir/rvalue.rs
+++ b/src/librustc_trans/trans/mir/rvalue.rs
@@ -21,7 +21,6 @@ use trans::callee::Callee;
 use trans::common::{self, BlockAndBuilder, Result};
 use trans::debuginfo::DebugLoc;
 use trans::declare;
-use trans::expr;
 use trans::adt;
 use trans::machine;
 use trans::type_::Type;
@@ -32,7 +31,7 @@ use trans::Disr;
 
 use super::MirContext;
 use super::operand::{OperandRef, OperandValue};
-use super::lvalue::LvalueRef;
+use super::lvalue::{LvalueRef, get_dataptr, get_meta};
 
 impl<'bcx, 'tcx> MirContext<'bcx, 'tcx> {
     pub fn trans_rvalue(&mut self,
@@ -100,8 +99,8 @@ impl<'bcx, 'tcx> MirContext<'bcx, 'tcx> {
                 let tr_elem = self.trans_operand(&bcx, elem);
                 let count = ConstVal::Integral(ConstInt::Usize(count.value));
                 let size = self.trans_constval(&bcx, &count, bcx.tcx().types.usize).immediate();
+                let base = get_dataptr(&bcx, dest.llval);
                 let bcx = bcx.map_block(|block| {
-                    let base = expr::get_dataptr(block, dest.llval);
                     tvec::iter_vec_raw(block, base, tr_elem.ty, size, |block, llslot, _| {
                         self.store_operand_direct(block, llslot, tr_elem);
                         block
@@ -124,9 +123,8 @@ impl<'bcx, 'tcx> MirContext<'bcx, 'tcx> {
                             // Do not generate stores and GEPis for zero-sized fields.
                             if !common::type_is_zero_size(bcx.ccx(), op.ty) {
                                 let val = adt::MaybeSizedValue::sized(dest.llval);
-                                let lldest_i = bcx.with_block(|bcx| {
-                                    adt::trans_field_ptr(bcx, &repr, val, disr, i)
-                                });
+                                let lldest_i = adt::trans_field_ptr_builder(&bcx, &repr,
+                                                                            val, disr, i);
                                 self.store_operand(&bcx, lldest_i, op);
                             }
                             self.set_operand_dropped(&bcx, operand);
@@ -186,11 +184,8 @@ impl<'bcx, 'tcx> MirContext<'bcx, 'tcx> {
                 let llbase1 = bcx.gepi(llbase, &[from_start]);
                 let adj = common::C_uint(ccx, from_start + from_end);
                 let lllen1 = bcx.sub(lllen, adj);
-                let (lladdrdest, llmetadest) = bcx.with_block(|bcx| {
-                    (expr::get_dataptr(bcx, dest.llval), expr::get_meta(bcx, dest.llval))
-                });
-                bcx.store(llbase1, lladdrdest);
-                bcx.store(lllen1, llmetadest);
+                bcx.store(llbase1, get_dataptr(&bcx, dest.llval));
+                bcx.store(lllen1, get_meta(&bcx, dest.llval));
                 bcx
             }