about summary refs log tree commit diff
path: root/src/librustc_codegen_llvm
diff options
context:
space:
mode:
authorDenis Merigoux <denis.merigoux@gmail.com>2018-09-14 17:48:57 +0200
committerEduard-Mihai Burtescu <edy.burt@gmail.com>2018-11-16 14:15:13 +0200
commitcbe31a4229c519d7af7b5d86f9295fd23adb8cd3 (patch)
tree20fa448c1fceb703bac328fa69e7a84467e43006 /src/librustc_codegen_llvm
parent78dd95f4c719797d64f988a35a6a25f2dfc7c124 (diff)
downloadrust-cbe31a4229c519d7af7b5d86f9295fd23adb8cd3.tar.gz
rust-cbe31a4229c519d7af7b5d86f9295fd23adb8cd3.zip
Generalized base::coerce_unsized_into
Diffstat (limited to 'src/librustc_codegen_llvm')
-rw-r--r--src/librustc_codegen_llvm/asm.rs6
-rw-r--r--src/librustc_codegen_llvm/base.rs26
-rw-r--r--src/librustc_codegen_llvm/builder.rs74
-rw-r--r--src/librustc_codegen_llvm/glue.rs16
-rw-r--r--src/librustc_codegen_llvm/interfaces/backend.rs7
-rw-r--r--src/librustc_codegen_llvm/interfaces/builder.rs3
-rw-r--r--src/librustc_codegen_llvm/interfaces/mod.rs5
-rw-r--r--src/librustc_codegen_llvm/interfaces/type_.rs8
-rw-r--r--src/librustc_codegen_llvm/intrinsic.rs18
-rw-r--r--src/librustc_codegen_llvm/meth.rs10
-rw-r--r--src/librustc_codegen_llvm/mir/block.rs12
-rw-r--r--src/librustc_codegen_llvm/mir/mod.rs2
-rw-r--r--src/librustc_codegen_llvm/mir/operand.rs41
-rw-r--r--src/librustc_codegen_llvm/mir/place.rs87
-rw-r--r--src/librustc_codegen_llvm/type_.rs14
15 files changed, 184 insertions, 145 deletions
diff --git a/src/librustc_codegen_llvm/asm.rs b/src/librustc_codegen_llvm/asm.rs
index 11740032664..38bdd9a79da 100644
--- a/src/librustc_codegen_llvm/asm.rs
+++ b/src/librustc_codegen_llvm/asm.rs
@@ -35,13 +35,13 @@ pub fn codegen_inline_asm(
 
     // Prepare the output operands
     let mut indirect_outputs = vec![];
-    for (i, (out, place)) in ia.outputs.iter().zip(&outputs).enumerate() {
+    for (i, (out, &place)) in ia.outputs.iter().zip(&outputs).enumerate() {
         if out.is_rw {
-            inputs.push(place.load(bx).immediate());
+            inputs.push(bx.load_operand(place).immediate());
             ext_constraints.push(i.to_string());
         }
         if out.is_indirect {
-            indirect_outputs.push(place.load(bx).immediate());
+            indirect_outputs.push(bx.load_operand(place).immediate());
         } else {
             output_types.push(place.layout.llvm_type(bx.cx()));
         }
diff --git a/src/librustc_codegen_llvm/base.rs b/src/librustc_codegen_llvm/base.rs
index 34d09acdb45..4f726741ec1 100644
--- a/src/librustc_codegen_llvm/base.rs
+++ b/src/librustc_codegen_llvm/base.rs
@@ -65,7 +65,7 @@ use monomorphize::partitioning::{CodegenUnit, CodegenUnitExt};
 use rustc_codegen_utils::symbol_names_test;
 use time_graph;
 use mono_item::{MonoItem, MonoItemExt};
-use type_of::LayoutLlvmExt;
+
 use rustc::util::nodemap::FxHashMap;
 use CrateInfo;
 use rustc_data_structures::small_c_str::SmallCStr;
@@ -208,7 +208,7 @@ pub fn unsized_info<'tcx, Cx: CodegenMethods<'tcx>>(
             let vtable_ptr = cx.layout_of(cx.tcx().mk_mut_ptr(target))
                 .field(cx, abi::FAT_PTR_EXTRA);
             cx.static_ptrcast(meth::get_vtable(cx, source, data.principal()),
-                            cx.backend_type(&vtable_ptr))
+                            cx.backend_type(vtable_ptr))
         }
         _ => bug!("unsized_info: invalid unsizing {:?} -> {:?}",
                   source,
@@ -232,13 +232,13 @@ pub fn unsize_thin_ptr<'a, 'tcx: 'a, Bx: BuilderMethods<'a, 'tcx>>(
         (&ty::RawPtr(ty::TypeAndMut { ty: a, .. }),
          &ty::RawPtr(ty::TypeAndMut { ty: b, .. })) => {
             assert!(bx.cx().type_is_sized(a));
-            let ptr_ty = bx.cx().type_ptr_to(bx.cx().backend_type(&bx.cx().layout_of(b)));
+            let ptr_ty = bx.cx().type_ptr_to(bx.cx().backend_type(bx.cx().layout_of(b)));
             (bx.pointercast(src, ptr_ty), unsized_info(bx.cx(), a, b, None))
         }
         (&ty::Adt(def_a, _), &ty::Adt(def_b, _)) if def_a.is_box() && def_b.is_box() => {
             let (a, b) = (src_ty.boxed_ty(), dst_ty.boxed_ty());
             assert!(bx.cx().type_is_sized(a));
-            let ptr_ty = bx.cx().type_ptr_to(bx.cx().backend_type(&bx.cx().layout_of(b)));
+            let ptr_ty = bx.cx().type_ptr_to(bx.cx().backend_type(bx.cx().layout_of(b)));
             (bx.pointercast(src, ptr_ty), unsized_info(bx.cx(), a, b, None))
         }
         (&ty::Adt(def_a, _), &ty::Adt(def_b, _)) => {
@@ -263,8 +263,8 @@ pub fn unsize_thin_ptr<'a, 'tcx: 'a, Bx: BuilderMethods<'a, 'tcx>>(
             }
             let (lldata, llextra) = result.unwrap();
             // HACK(eddyb) have to bitcast pointers until LLVM removes pointee types.
-            (bx.bitcast(lldata, bx.cx().scalar_pair_element_backend_type(&dst_layout, 0, true)),
-             bx.bitcast(llextra, bx.cx().scalar_pair_element_backend_type(&dst_layout, 1, true)))
+            (bx.bitcast(lldata, bx.cx().scalar_pair_element_backend_type(dst_layout, 0, true)),
+             bx.bitcast(llextra, bx.cx().scalar_pair_element_backend_type(dst_layout, 1, true)))
         }
         _ => bug!("unsize_thin_ptr: called on bad types"),
     }
@@ -272,22 +272,22 @@ pub fn unsize_thin_ptr<'a, 'tcx: 'a, Bx: BuilderMethods<'a, 'tcx>>(
 
 /// Coerce `src`, which is a reference to a value of type `src_ty`,
 /// to a value of type `dst_ty` and store the result in `dst`
-pub fn coerce_unsized_into(
-    bx: &Builder<'a, 'll, 'tcx>,
-    src: PlaceRef<'tcx, &'ll Value>,
-    dst: PlaceRef<'tcx, &'ll Value>
-) {
+pub fn coerce_unsized_into<'a, 'tcx: 'a, Bx: BuilderMethods<'a, 'tcx>>(
+    bx: &Bx,
+    src: PlaceRef<'tcx, Bx::Value>,
+    dst: PlaceRef<'tcx, Bx::Value>
+)  {
     let src_ty = src.layout.ty;
     let dst_ty = dst.layout.ty;
     let coerce_ptr = || {
-        let (base, info) = match src.load(bx).val {
+        let (base, info) = match bx.load_operand(src).val {
             OperandValue::Pair(base, info) => {
                 // fat-ptr to fat-ptr unsize preserves the vtable
                 // i.e. &'a fmt::Debug+Send => &'a fmt::Debug
                 // So we need to pointercast the base to ensure
                 // the types match up.
                 let thin_ptr = dst.layout.field(bx.cx(), abi::FAT_PTR_ADDR);
-                (bx.pointercast(base, thin_ptr.llvm_type(bx.cx())), info)
+                (bx.pointercast(base, bx.cx().backend_type(thin_ptr)), info)
             }
             OperandValue::Immediate(base) => {
                 unsize_thin_ptr(bx, base, src_ty, dst_ty)
diff --git a/src/librustc_codegen_llvm/builder.rs b/src/librustc_codegen_llvm/builder.rs
index 57e23766980..07a3616a7f8 100644
--- a/src/librustc_codegen_llvm/builder.rs
+++ b/src/librustc_codegen_llvm/builder.rs
@@ -13,15 +13,18 @@ use llvm::{self, False, OperandBundleDef, BasicBlock};
 use common::{self, *};
 use context::CodegenCx;
 use type_::Type;
+use type_of::LayoutLlvmExt;
 use value::Value;
 use libc::{c_uint, c_char};
 use rustc::ty::{self, Ty, TyCtxt};
-use rustc::ty::layout::{Align, Size, TyLayout};
+use rustc::ty::layout::{self, Align, Size, TyLayout};
 use rustc::session::{config, Session};
 use rustc_data_structures::small_c_str::SmallCStr;
 use interfaces::*;
 use syntax;
-
+use base;
+use mir::operand::{OperandValue, OperandRef};
+use mir::place::PlaceRef;
 use std::borrow::Cow;
 use std::ops::Range;
 use std::ptr;
@@ -538,6 +541,73 @@ impl BuilderMethods<'a, 'tcx> for Builder<'a, 'll, 'tcx> {
         }
     }
 
+    fn load_operand(
+        &self,
+        place: PlaceRef<'tcx, &'ll Value>
+    ) -> OperandRef<'tcx, &'ll Value> {
+        debug!("PlaceRef::load: {:?}", place);
+
+        assert_eq!(place.llextra.is_some(), place.layout.is_unsized());
+
+        if place.layout.is_zst() {
+            return OperandRef::new_zst(self.cx(), place.layout);
+        }
+
+        let scalar_load_metadata = |load, scalar: &layout::Scalar| {
+            let vr = scalar.valid_range.clone();
+            match scalar.value {
+                layout::Int(..) => {
+                    let range = scalar.valid_range_exclusive(self.cx());
+                    if range.start != range.end {
+                        self.range_metadata(load, range);
+                    }
+                }
+                layout::Pointer if vr.start() < vr.end() && !vr.contains(&0) => {
+                    self.nonnull_metadata(load);
+                }
+                _ => {}
+            }
+        };
+
+        let val = if let Some(llextra) = place.llextra {
+            OperandValue::Ref(place.llval, Some(llextra), place.align)
+        } else if place.layout.is_llvm_immediate() {
+            let mut const_llval = None;
+            unsafe {
+                if let Some(global) = llvm::LLVMIsAGlobalVariable(place.llval) {
+                    if llvm::LLVMIsGlobalConstant(global) == llvm::True {
+                        const_llval = llvm::LLVMGetInitializer(global);
+                    }
+                }
+            }
+            let llval = const_llval.unwrap_or_else(|| {
+                let load = self.load(place.llval, place.align);
+                if let layout::Abi::Scalar(ref scalar) = place.layout.abi {
+                    scalar_load_metadata(load, scalar);
+                }
+                load
+            });
+            OperandValue::Immediate(base::to_immediate(self, llval, place.layout))
+        } else if let layout::Abi::ScalarPair(ref a, ref b) = place.layout.abi {
+            let load = |i, scalar: &layout::Scalar| {
+                let llptr = self.struct_gep(place.llval, i as u64);
+                let load = self.load(llptr, place.align);
+                scalar_load_metadata(load, scalar);
+                if scalar.is_bool() {
+                    self.trunc(load, self.cx().type_i1())
+                } else {
+                    load
+                }
+            };
+            OperandValue::Pair(load(0, a), load(1, b))
+        } else {
+            OperandValue::Ref(place.llval, None, place.align)
+        };
+
+        OperandRef { val, layout: place.layout }
+    }
+
+
 
     fn range_metadata(&self, load: &'ll Value, range: Range<u128>) {
         if self.sess().target.target.arch == "amdgpu" {
diff --git a/src/librustc_codegen_llvm/glue.rs b/src/librustc_codegen_llvm/glue.rs
index dadb1390bc5..7268c2c1aac 100644
--- a/src/librustc_codegen_llvm/glue.rs
+++ b/src/librustc_codegen_llvm/glue.rs
@@ -14,23 +14,21 @@
 
 use std;
 
-use builder::Builder;
 use common::*;
 use meth;
-use rustc::ty::layout::{LayoutOf, HasTyCtxt};
+use rustc::ty::layout::LayoutOf;
 use rustc::ty::{self, Ty};
-use value::Value;
 use interfaces::*;
 
-pub fn size_and_align_of_dst(
-    bx: &Builder<'_, 'll, 'tcx>,
+pub fn size_and_align_of_dst<'a, 'tcx: 'a, Bx: BuilderMethods<'a, 'tcx>>(
+    bx: &Bx,
     t: Ty<'tcx>,
-    info: Option<&'ll Value>
-) -> (&'ll Value, &'ll Value) {
+    info: Option<Bx::Value>
+) -> (Bx::Value, Bx::Value) {
     debug!("calculate size of DST: {}; with lost info: {:?}",
            t, info);
     if bx.cx().type_is_sized(t) {
-        let (size, align) = bx.cx().size_and_align_of(t);
+        let (size, align) = bx.cx().layout_of(t).size_and_align();
         debug!("size_and_align_of_dst t={} info={:?} size: {:?} align: {:?}",
                t, info, size, align);
         let size = bx.cx().const_usize(size.bytes());
@@ -47,7 +45,7 @@ pub fn size_and_align_of_dst(
             let unit = t.sequence_element_type(bx.tcx());
             // The info in this case is the length of the str, so the size is that
             // times the unit size.
-            let (size, align) = bx.cx().size_and_align_of(unit);
+            let (size, align) = bx.cx().layout_of(unit).size_and_align();
             (bx.mul(info.unwrap(), bx.cx().const_usize(size.bytes())),
              bx.cx().const_usize(align.abi()))
         }
diff --git a/src/librustc_codegen_llvm/interfaces/backend.rs b/src/librustc_codegen_llvm/interfaces/backend.rs
index c470ad3b881..5799f5e84ef 100644
--- a/src/librustc_codegen_llvm/interfaces/backend.rs
+++ b/src/librustc_codegen_llvm/interfaces/backend.rs
@@ -10,12 +10,13 @@
 
 use rustc::ty::layout::{HasTyCtxt, LayoutOf, TyLayout};
 use rustc::ty::Ty;
-use std::fmt::Debug;
+
+use super::CodegenObject;
 
 pub trait BackendTypes {
-    type Value: Debug + PartialEq + Copy;
+    type Value: CodegenObject;
     type BasicBlock;
-    type Type: Debug + PartialEq + Copy;
+    type Type: CodegenObject;
     type Context;
 }
 
diff --git a/src/librustc_codegen_llvm/interfaces/builder.rs b/src/librustc_codegen_llvm/interfaces/builder.rs
index 2ddef097f36..ebc8aa7a4ca 100644
--- a/src/librustc_codegen_llvm/interfaces/builder.rs
+++ b/src/librustc_codegen_llvm/interfaces/builder.rs
@@ -12,6 +12,8 @@ use super::HasCodegen;
 use builder::MemFlags;
 use common::*;
 use libc::c_char;
+use mir::operand::OperandRef;
+use mir::place::PlaceRef;
 use rustc::session::Session;
 use rustc::ty::layout::{Align, Size};
 
@@ -88,6 +90,7 @@ pub trait BuilderMethods<'a, 'tcx: 'a>: HasCodegen<'tcx> {
     fn load(&self, ptr: Self::Value, align: Align) -> Self::Value;
     fn volatile_load(&self, ptr: Self::Value) -> Self::Value;
     fn atomic_load(&self, ptr: Self::Value, order: AtomicOrdering, size: Size) -> Self::Value;
+    fn load_operand(&self, place: PlaceRef<'tcx, Self::Value>) -> OperandRef<'tcx, Self::Value>;
 
     fn range_metadata(&self, load: Self::Value, range: Range<u128>);
     fn nonnull_metadata(&self, load: Self::Value);
diff --git a/src/librustc_codegen_llvm/interfaces/mod.rs b/src/librustc_codegen_llvm/interfaces/mod.rs
index a978e295967..4c5c9b164af 100644
--- a/src/librustc_codegen_llvm/interfaces/mod.rs
+++ b/src/librustc_codegen_llvm/interfaces/mod.rs
@@ -26,6 +26,8 @@ pub use self::misc::MiscMethods;
 pub use self::statics::StaticMethods;
 pub use self::type_::{BaseTypeMethods, DerivedTypeMethods, LayoutTypeMethods, TypeMethods};
 
+use std::fmt;
+
 pub trait CodegenMethods<'tcx>:
     Backend<'tcx>
     + TypeMethods<'tcx>
@@ -54,3 +56,6 @@ pub trait HasCodegen<'tcx>: Backend<'tcx> {
             Context = Self::Context,
         >;
 }
+
+pub trait CodegenObject: Copy + PartialEq + fmt::Debug {}
+impl<T: Copy + PartialEq + fmt::Debug> CodegenObject for T {}
diff --git a/src/librustc_codegen_llvm/interfaces/type_.rs b/src/librustc_codegen_llvm/interfaces/type_.rs
index 463f7970e91..7a95f49def6 100644
--- a/src/librustc_codegen_llvm/interfaces/type_.rs
+++ b/src/librustc_codegen_llvm/interfaces/type_.rs
@@ -69,12 +69,14 @@ pub trait DerivedTypeMethods<'tcx>: Backend<'tcx> {
 }
 
 pub trait LayoutTypeMethods<'tcx>: Backend<'tcx> {
-    fn backend_type(&self, ty: &TyLayout<'tcx>) -> Self::Type;
+    fn backend_type(&self, layout: TyLayout<'tcx>) -> Self::Type;
+    fn immediate_backend_type(&self, layout: TyLayout<'tcx>) -> Self::Type;
+    fn is_backend_immediate(&self, layout: TyLayout<'tcx>) -> bool;
     fn scalar_pair_element_backend_type<'a>(
         &self,
-        ty: &TyLayout<'tcx>,
+        layout: TyLayout<'tcx>,
         index: usize,
-        immediate: bool
+        immediate: bool,
     ) -> Self::Type;
 }
 
diff --git a/src/librustc_codegen_llvm/intrinsic.rs b/src/librustc_codegen_llvm/intrinsic.rs
index 60a7de477bd..fe53ecd46e0 100644
--- a/src/librustc_codegen_llvm/intrinsic.rs
+++ b/src/librustc_codegen_llvm/intrinsic.rs
@@ -154,7 +154,7 @@ impl IntrinsicCallMethods<'a, 'tcx> for Builder<'a, 'll, 'tcx> {
                 let tp_ty = substs.type_at(0);
                 if let OperandValue::Pair(_, meta) = args[0].val {
                     let (llsize, _) =
-                        glue::size_and_align_of_dst(&self, tp_ty, Some(meta));
+                        glue::size_and_align_of_dst(self, tp_ty, Some(meta));
                     llsize
                 } else {
                     cx.const_usize(cx.size_of(tp_ty).bytes())
@@ -168,7 +168,7 @@ impl IntrinsicCallMethods<'a, 'tcx> for Builder<'a, 'll, 'tcx> {
                 let tp_ty = substs.type_at(0);
                 if let OperandValue::Pair(_, meta) = args[0].val {
                     let (_, llalign) =
-                        glue::size_and_align_of_dst(&self, tp_ty, Some(meta));
+                        glue::size_and_align_of_dst(self, tp_ty, Some(meta));
                     llalign
                 } else {
                     cx.const_usize(cx.align_of(tp_ty).abi())
@@ -353,9 +353,9 @@ impl IntrinsicCallMethods<'a, 'tcx> for Builder<'a, 'll, 'tcx> {
                                     cx.type_bool()
                                 );
 
-                                let dest = result.project_field(&self, 0);
+                                let dest = result.project_field(self, 0);
                                 self.store(val, dest.llval, dest.align);
-                                let dest = result.project_field(&self, 1);
+                                let dest = result.project_field(self, 1);
                                 self.store(overflow, dest.llval, dest.align);
 
                                 return;
@@ -520,9 +520,9 @@ impl IntrinsicCallMethods<'a, 'tcx> for Builder<'a, 'll, 'tcx> {
                                 cx.type_bool()
                             );
 
-                            let dest = result.project_field(&self, 0);
+                            let dest = result.project_field(self, 0);
                             self.store(val, dest.llval, dest.align);
-                            let dest = result.project_field(&self, 1);
+                            let dest = result.project_field(self, 1);
                             self.store(success, dest.llval, dest.align);
                             return;
                         } else {
@@ -678,7 +678,7 @@ impl IntrinsicCallMethods<'a, 'tcx> for Builder<'a, 'll, 'tcx> {
                             };
                             let arg = PlaceRef::new_sized(ptr, arg.layout, align);
                             (0..contents.len()).map(|i| {
-                                arg.project_field(bx, i).load(bx).immediate()
+                                bx.load_operand(arg.project_field(bx, i)).immediate()
                             }).collect()
                         }
                         intrinsics::Type::Pointer(_, Some(ref llvm_elem), _) => {
@@ -729,7 +729,7 @@ impl IntrinsicCallMethods<'a, 'tcx> for Builder<'a, 'll, 'tcx> {
                         assert!(!flatten);
 
                         for i in 0..elems.len() {
-                            let dest = result.project_field(&self, i);
+                            let dest = result.project_field(self, i);
                             let val = self.extract_value(val, i as u64);
                             self.store(val, dest.llval, dest.align);
                         }
@@ -746,7 +746,7 @@ impl IntrinsicCallMethods<'a, 'tcx> for Builder<'a, 'll, 'tcx> {
                 self.store(llval, ptr, result.align);
             } else {
                 OperandRef::from_immediate_or_packed_pair(&self, llval, result.layout)
-                    .val.store(&self, result);
+                    .val.store(self, result);
             }
         }
     }
diff --git a/src/librustc_codegen_llvm/meth.rs b/src/librustc_codegen_llvm/meth.rs
index 798cc8c8308..77fce465f23 100644
--- a/src/librustc_codegen_llvm/meth.rs
+++ b/src/librustc_codegen_llvm/meth.rs
@@ -26,7 +26,7 @@ pub const DESTRUCTOR: VirtualIndex = VirtualIndex(0);
 pub const SIZE: VirtualIndex = VirtualIndex(1);
 pub const ALIGN: VirtualIndex = VirtualIndex(2);
 
-impl<'a, 'tcx> VirtualIndex {
+impl<'a, 'tcx: 'a> VirtualIndex {
     pub fn from_index(index: usize) -> Self {
         VirtualIndex(index as u64 + 3)
     }
@@ -52,11 +52,11 @@ impl<'a, 'tcx> VirtualIndex {
         ptr
     }
 
-    pub fn get_usize(
+    pub fn get_usize<Bx: BuilderMethods<'a, 'tcx>>(
         self,
-        bx: &Builder<'a, 'll, 'tcx>,
-        llvtable: &'ll Value
-    ) -> &'ll Value {
+        bx: &Bx,
+        llvtable: Bx::Value
+    ) -> Bx::Value {
         // Load the data pointer from the object.
         debug!("get_int({:?}, {:?})", llvtable, self);
 
diff --git a/src/librustc_codegen_llvm/mir/block.rs b/src/librustc_codegen_llvm/mir/block.rs
index 6a8a8948cc7..63073091095 100644
--- a/src/librustc_codegen_llvm/mir/block.rs
+++ b/src/librustc_codegen_llvm/mir/block.rs
@@ -165,8 +165,8 @@ impl FunctionCx<'a, 'll, 'tcx, &'ll Value> {
                     bx.cleanup_ret(cleanup_pad, None);
                 } else {
                     let slot = self.get_personality_slot(&bx);
-                    let lp0 = slot.project_field(&bx, 0).load(&bx).immediate();
-                    let lp1 = slot.project_field(&bx, 1).load(&bx).immediate();
+                    let lp0 = bx.load_operand(slot.project_field(&bx, 0)).immediate();
+                    let lp1 = bx.load_operand(slot.project_field(&bx, 1)).immediate();
                     slot.storage_dead(&bx);
 
                     if !bx.sess().target.target.options.custom_unwind_resume {
@@ -835,7 +835,7 @@ impl FunctionCx<'a, 'll, 'tcx, &'ll Value> {
             let tuple_ptr = PlaceRef::new_sized(llval, tuple.layout, align);
             for i in 0..tuple.layout.fields.count() {
                 let field_ptr = tuple_ptr.project_field(bx, i);
-                self.codegen_argument(bx, field_ptr.load(bx), llargs, &args[i]);
+                self.codegen_argument(bx, bx.load_operand(field_ptr), llargs, &args[i]);
             }
         } else if let Ref(_, Some(_), _) = tuple.val {
             bug!("closure arguments must be sized")
@@ -994,7 +994,7 @@ impl FunctionCx<'a, 'll, 'tcx, &'ll Value> {
                     let place = PlaceRef::alloca(bx, dst_layout, "transmute_temp");
                     place.storage_live(bx);
                     self.codegen_transmute_into(bx, src, place);
-                    let op = place.load(bx);
+                    let op = bx.load_operand(place);
                     place.storage_dead(bx);
                     self.locals[index] = LocalRef::Operand(Some(op));
                 }
@@ -1032,7 +1032,7 @@ impl FunctionCx<'a, 'll, 'tcx, &'ll Value> {
             Nothing => (),
             Store(dst) => ret_ty.store(bx, llval, dst),
             IndirectOperand(tmp, index) => {
-                let op = tmp.load(bx);
+                let op = bx.load_operand(tmp);
                 tmp.storage_dead(bx);
                 self.locals[index] = LocalRef::Operand(Some(op));
             }
@@ -1042,7 +1042,7 @@ impl FunctionCx<'a, 'll, 'tcx, &'ll Value> {
                     let tmp = PlaceRef::alloca(bx, ret_ty.layout, "tmp_ret");
                     tmp.storage_live(bx);
                     ret_ty.store(bx, llval, tmp);
-                    let op = tmp.load(bx);
+                    let op = bx.load_operand(tmp);
                     tmp.storage_dead(bx);
                     op
                 } else {
diff --git a/src/librustc_codegen_llvm/mir/mod.rs b/src/librustc_codegen_llvm/mir/mod.rs
index e3e3843476a..9939e0dcc45 100644
--- a/src/librustc_codegen_llvm/mir/mod.rs
+++ b/src/librustc_codegen_llvm/mir/mod.rs
@@ -567,7 +567,7 @@ fn arg_local_refs(
             let indirect_operand = OperandValue::Pair(llarg, llextra);
 
             let tmp = PlaceRef::alloca_unsized_indirect(bx, arg.layout, &name);
-            indirect_operand.store(&bx, tmp);
+            indirect_operand.store(bx, tmp);
             tmp
         } else {
             let tmp = PlaceRef::alloca(bx, arg.layout, &name);
diff --git a/src/librustc_codegen_llvm/mir/operand.rs b/src/librustc_codegen_llvm/mir/operand.rs
index 91f1b085aff..d845d6ee34b 100644
--- a/src/librustc_codegen_llvm/mir/operand.rs
+++ b/src/librustc_codegen_llvm/mir/operand.rs
@@ -20,7 +20,7 @@ use value::Value;
 use type_of::LayoutLlvmExt;
 use glue;
 
-use interfaces::{BuilderMethods, ConstMethods, BaseTypeMethods, IntrinsicDeclarationMethods};
+use interfaces::*;
 
 use std::fmt;
 
@@ -67,16 +67,20 @@ impl fmt::Debug for OperandRef<'tcx, &'ll Value> {
     }
 }
 
-impl OperandRef<'tcx, &'ll Value> {
-    pub fn new_zst(cx: &CodegenCx<'ll, 'tcx>,
-                   layout: TyLayout<'tcx>) -> OperandRef<'tcx, &'ll Value> {
+impl<'tcx, V: CodegenObject> OperandRef<'tcx, V> {
+    pub fn new_zst<Cx: CodegenMethods<'tcx, Value = V>>(
+        cx: &Cx,
+        layout: TyLayout<'tcx>
+    ) -> OperandRef<'tcx, V> {
         assert!(layout.is_zst());
         OperandRef {
-            val: OperandValue::Immediate(cx.const_undef(layout.immediate_llvm_type(cx))),
+            val: OperandValue::Immediate(cx.const_undef(cx.immediate_backend_type(layout))),
             layout
         }
     }
+}
 
+impl OperandRef<'tcx, &'ll Value> {
     pub fn from_const(bx: &Builder<'a, 'll, 'tcx>,
                       val: &'tcx ty::Const<'tcx>)
                       -> Result<OperandRef<'tcx, &'ll Value>, ErrorHandled> {
@@ -122,7 +126,7 @@ impl OperandRef<'tcx, &'ll Value> {
                 OperandValue::Pair(a_llval, b_llval)
             },
             ConstValue::ByRef(_, alloc, offset) => {
-                return Ok(PlaceRef::from_const_alloc(bx, layout, alloc, offset).load(bx));
+                return Ok(bx.load_operand(PlaceRef::from_const_alloc(bx, layout, alloc, offset)));
             },
         };
 
@@ -256,10 +260,17 @@ impl OperandRef<'tcx, &'ll Value> {
     }
 }
 
-impl OperandValue<&'ll Value> {
-    pub fn store(self, bx: &Builder<'a, 'll, 'tcx>, dest: PlaceRef<'tcx, &'ll Value>) {
+impl<'a, 'tcx: 'a, V: CodegenObject> OperandValue<V> {
+    pub fn store<Bx: BuilderMethods<'a, 'tcx, Value = V>>(
+        self,
+        bx: &Bx,
+        dest: PlaceRef<'tcx, Bx::Value>
+    ) {
         self.store_with_flags(bx, dest, MemFlags::empty());
     }
+}
+
+impl OperandValue<&'ll Value> {
 
     pub fn volatile_store(
         self,
@@ -286,11 +297,13 @@ impl<'a, 'll: 'a, 'tcx: 'll> OperandValue<&'ll Value> {
     ) {
         self.store_with_flags(bx, dest, MemFlags::NONTEMPORAL);
     }
+}
 
-    fn store_with_flags(
+impl<'a, 'tcx: 'a, V: CodegenObject> OperandValue<V> {
+    fn store_with_flags<Bx: BuilderMethods<'a, 'tcx, Value = V>>(
         self,
-        bx: &Builder<'a, 'll, 'tcx, &'ll Value>,
-        dest: PlaceRef<'tcx, &'ll Value>,
+        bx: &Bx,
+        dest: PlaceRef<'tcx, Bx::Value>,
         flags: MemFlags,
     ) {
         debug!("OperandRef::store: operand={:?}, dest={:?}", self, dest);
@@ -427,7 +440,7 @@ impl FunctionCx<'a, 'll, 'tcx, &'ll Value> {
 
         // for most places, to consume them we just load them
         // out from their home
-        self.codegen_place(bx, place).load(bx)
+        bx.load_operand(self.codegen_place(bx, place))
     }
 
     pub fn codegen_operand(&mut self,
@@ -461,11 +474,11 @@ impl FunctionCx<'a, 'll, 'tcx, &'ll Value> {
                         bx.call(fnname, &[], None);
                         // We've errored, so we don't have to produce working code.
                         let layout = bx.cx().layout_of(ty);
-                        PlaceRef::new_sized(
+                        bx.load_operand(PlaceRef::new_sized(
                             bx.cx().const_undef(bx.cx().type_ptr_to(layout.llvm_type(bx.cx()))),
                             layout,
                             layout.align,
-                        ).load(bx)
+                        ))
                     })
             }
         }
diff --git a/src/librustc_codegen_llvm/mir/place.rs b/src/librustc_codegen_llvm/mir/place.rs
index 285cbb21aa1..981e5b3fe96 100644
--- a/src/librustc_codegen_llvm/mir/place.rs
+++ b/src/librustc_codegen_llvm/mir/place.rs
@@ -8,12 +8,11 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
-use llvm::{self, LLVMConstInBoundsGEP};
+use llvm::LLVMConstInBoundsGEP;
 use rustc::ty::{self, Ty};
 use rustc::ty::layout::{self, Align, TyLayout, LayoutOf, Size, VariantIdx, HasTyCtxt};
 use rustc::mir;
 use rustc::mir::tcx::PlaceTy;
-use base;
 use builder::{Builder, MemFlags};
 use common::{CodegenCx, IntPredicate};
 use type_of::LayoutLlvmExt;
@@ -24,7 +23,7 @@ use mir::constant::const_alloc_to_llvm;
 use interfaces::*;
 
 use super::{FunctionCx, LocalRef};
-use super::operand::{OperandRef, OperandValue};
+use super::operand::OperandValue;
 
 #[derive(Copy, Clone, Debug)]
 pub struct PlaceRef<'tcx, V> {
@@ -108,75 +107,14 @@ impl PlaceRef<'tcx, &'ll Value> {
         }
     }
 
-    pub fn load(&self, bx: &Builder<'a, 'll, 'tcx>) -> OperandRef<'tcx, &'ll Value> {
-        debug!("PlaceRef::load: {:?}", self);
-
-        assert_eq!(self.llextra.is_some(), self.layout.is_unsized());
-
-        if self.layout.is_zst() {
-            return OperandRef::new_zst(bx.cx(), self.layout);
-        }
-
-        let scalar_load_metadata = |load, scalar: &layout::Scalar| {
-            let vr = scalar.valid_range.clone();
-            match scalar.value {
-                layout::Int(..) => {
-                    let range = scalar.valid_range_exclusive(bx.cx());
-                    if range.start != range.end {
-                        bx.range_metadata(load, range);
-                    }
-                }
-                layout::Pointer if vr.start() < vr.end() && !vr.contains(&0) => {
-                    bx.nonnull_metadata(load);
-                }
-                _ => {}
-            }
-        };
-
-        let val = if let Some(llextra) = self.llextra {
-            OperandValue::Ref(self.llval, Some(llextra), self.align)
-        } else if self.layout.is_llvm_immediate() {
-            let mut const_llval = None;
-            unsafe {
-                if let Some(global) = llvm::LLVMIsAGlobalVariable(self.llval) {
-                    if llvm::LLVMIsGlobalConstant(global) == llvm::True {
-                        const_llval = llvm::LLVMGetInitializer(global);
-                    }
-                }
-            }
-            let llval = const_llval.unwrap_or_else(|| {
-                let load = bx.load(self.llval, self.align);
-                if let layout::Abi::Scalar(ref scalar) = self.layout.abi {
-                    scalar_load_metadata(load, scalar);
-                }
-                load
-            });
-            OperandValue::Immediate(base::to_immediate(bx, llval, self.layout))
-        } else if let layout::Abi::ScalarPair(ref a, ref b) = self.layout.abi {
-            let load = |i, scalar: &layout::Scalar| {
-                let llptr = bx.struct_gep(self.llval, i as u64);
-                let load = bx.load(llptr, self.align);
-                scalar_load_metadata(load, scalar);
-                if scalar.is_bool() {
-                    bx.trunc(load, bx.cx().type_i1())
-                } else {
-                    load
-                }
-            };
-            OperandValue::Pair(load(0, a), load(1, b))
-        } else {
-            OperandValue::Ref(self.llval, None, self.align)
-        };
-
-        OperandRef { val, layout: self.layout }
-    }
+}
 
+impl<'a, 'tcx: 'a, V: CodegenObject> PlaceRef<'tcx, V> {
     /// Access a field, at a point when the value's case is known.
-    pub fn project_field(
-        self,
-        bx: &Builder<'a, 'll, 'tcx>,
+    pub fn project_field<Bx: BuilderMethods<'a, 'tcx, Value = V>>(
+        self, bx: &Bx,
         ix: usize,
-    ) -> PlaceRef<'tcx, &'ll Value> {
+    ) -> PlaceRef<'tcx, Bx::Value> {
         let cx = bx.cx();
         let field = self.layout.field(cx, ix);
         let offset = self.layout.fields.offset(ix);
@@ -195,7 +133,7 @@ impl PlaceRef<'tcx, &'ll Value> {
             };
             PlaceRef {
                 // HACK(eddyb) have to bitcast pointers until LLVM removes pointee types.
-                llval: bx.pointercast(llval, cx.type_ptr_to(field.llvm_type(cx))),
+                llval: bx.pointercast(llval, cx.type_ptr_to(cx.backend_type(field))),
                 llextra: if cx.type_has_metadata(field.ty) {
                     self.llextra
                 } else {
@@ -268,7 +206,7 @@ impl PlaceRef<'tcx, &'ll Value> {
         let byte_ptr = bx.gep(byte_ptr, &[offset]);
 
         // Finally, cast back to the type expected
-        let ll_fty = field.llvm_type(cx);
+        let ll_fty = cx.backend_type(field);
         debug!("struct_field_ptr: Field type is {:?}", ll_fty);
 
         PlaceRef {
@@ -278,6 +216,9 @@ impl PlaceRef<'tcx, &'ll Value> {
             align: effective_field_align,
         }
     }
+}
+
+impl PlaceRef<'tcx, &'ll Value> {
 
     /// Obtain the actual discriminant of a value.
     pub fn codegen_get_discr(
@@ -301,7 +242,7 @@ impl PlaceRef<'tcx, &'ll Value> {
         }
 
         let discr = self.project_field(bx, 0);
-        let lldiscr = discr.load(bx).immediate();
+        let lldiscr = bx.load_operand(discr).immediate();
         match self.layout.variants {
             layout::Variants::Single { .. } => bug!(),
             layout::Variants::Tagged { ref tag, .. } => {
@@ -449,7 +390,7 @@ impl FunctionCx<'a, 'll, 'tcx, &'ll Value> {
                     return place;
                 }
                 LocalRef::UnsizedPlace(place) => {
-                    return place.load(bx).deref(&cx);
+                    return bx.load_operand(place).deref(&cx);
                 }
                 LocalRef::Operand(..) => {
                     bug!("using operand local {:?} as place", place);
diff --git a/src/librustc_codegen_llvm/type_.rs b/src/librustc_codegen_llvm/type_.rs
index 55237e27d9e..1285f588ea9 100644
--- a/src/librustc_codegen_llvm/type_.rs
+++ b/src/librustc_codegen_llvm/type_.rs
@@ -394,15 +394,21 @@ impl DerivedTypeMethods<'tcx> for CodegenCx<'ll, 'tcx> {
 }
 
 impl LayoutTypeMethods<'tcx> for CodegenCx<'ll, 'tcx> {
-    fn backend_type(&self, ty: &TyLayout<'tcx>) -> &'ll Type {
-        ty.llvm_type(&self)
+    fn backend_type(&self, layout: TyLayout<'tcx>) -> &'ll Type {
+        layout.llvm_type(&self)
+    }
+    fn immediate_backend_type(&self, layout: TyLayout<'tcx>) -> &'ll Type {
+        layout.immediate_llvm_type(self)
+    }
+    fn is_backend_immediate(&self, layout: TyLayout<'tcx>) -> bool {
+        layout.is_llvm_immediate()
     }
     fn scalar_pair_element_backend_type<'a>(
         &self,
-        ty: &TyLayout<'tcx>,
+        layout: TyLayout<'tcx>,
         index: usize,
         immediate: bool
     ) -> &'ll Type {
-        ty.scalar_pair_element_llvm_type(&self, index, immediate)
+        layout.scalar_pair_element_llvm_type(self, index, immediate)
     }
 }