about summary refs log tree commit diff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/librustc_trans/common.rs21
-rw-r--r--src/librustc_trans/intrinsic.rs6
-rw-r--r--src/librustc_trans/mir/analyze.rs9
-rw-r--r--src/librustc_trans/mir/block.rs33
-rw-r--r--src/librustc_trans/mir/constant.rs7
-rw-r--r--src/librustc_trans/mir/lvalue.rs8
-rw-r--r--src/librustc_trans/mir/mod.rs8
-rw-r--r--src/librustc_trans/mir/operand.rs76
-rw-r--r--src/librustc_trans/mir/rvalue.rs3
-rw-r--r--src/librustc_trans/type_of.rs19
10 files changed, 84 insertions, 106 deletions
diff --git a/src/librustc_trans/common.rs b/src/librustc_trans/common.rs
index f476416619e..03ae58fd941 100644
--- a/src/librustc_trans/common.rs
+++ b/src/librustc_trans/common.rs
@@ -28,7 +28,7 @@ use type_of::LayoutLlvmExt;
 use value::Value;
 use rustc::traits;
 use rustc::ty::{self, Ty, TyCtxt};
-use rustc::ty::layout::{self, HasDataLayout, LayoutOf};
+use rustc::ty::layout::{HasDataLayout, LayoutOf};
 use rustc::ty::subst::{Kind, Subst, Substs};
 use rustc::hir;
 
@@ -54,25 +54,6 @@ pub fn type_is_fat_ptr<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, ty: Ty<'tcx>) ->
     }
 }
 
-/// Returns true if the type is represented as a pair of immediates.
-pub fn type_is_imm_pair<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, ty: Ty<'tcx>)
-                                  -> bool {
-    let layout = ccx.layout_of(ty);
-    match layout.fields {
-        layout::FieldPlacement::Arbitrary { .. } => {
-            // There must be only 2 fields.
-            if layout.fields.count() != 2 {
-                return false;
-            }
-
-            // The two fields must be both immediates.
-            layout.field(ccx, 0).is_llvm_immediate() &&
-            layout.field(ccx, 1).is_llvm_immediate()
-        }
-        _ => false
-    }
-}
-
 pub fn type_needs_drop<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, ty: Ty<'tcx>) -> bool {
     ty.needs_drop(tcx, ty::ParamEnv::empty(traits::Reveal::All))
 }
diff --git a/src/librustc_trans/intrinsic.rs b/src/librustc_trans/intrinsic.rs
index d982fa192b3..7d08090cd7e 100644
--- a/src/librustc_trans/intrinsic.rs
+++ b/src/librustc_trans/intrinsic.rs
@@ -675,10 +675,8 @@ pub fn trans_intrinsic_call<'a, 'tcx>(bcx: &Builder<'a, 'tcx>,
             let ptr = bcx.pointercast(llresult, ty.llvm_type(ccx).ptr_to());
             bcx.store(llval, ptr, Some(ccx.align_of(ret_ty)));
         } else {
-            OperandRef {
-                val: OperandValue::Immediate(llval),
-                layout: result.layout
-            }.unpack_if_pair(bcx).val.store(bcx, result);
+            OperandRef::from_immediate_or_packed_pair(bcx, llval, result.layout)
+                .val.store(bcx, result);
         }
     }
 }
diff --git a/src/librustc_trans/mir/analyze.rs b/src/librustc_trans/mir/analyze.rs
index 93780aefe4d..bf822249a64 100644
--- a/src/librustc_trans/mir/analyze.rs
+++ b/src/librustc_trans/mir/analyze.rs
@@ -19,7 +19,6 @@ use rustc::mir::visit::{Visitor, LvalueContext};
 use rustc::mir::traversal;
 use rustc::ty;
 use rustc::ty::layout::LayoutOf;
-use common;
 use type_of::LayoutLlvmExt;
 use super::MirContext;
 
@@ -32,10 +31,11 @@ pub fn lvalue_locals<'a, 'tcx>(mircx: &MirContext<'a, 'tcx>) -> BitVector {
     for (index, ty) in mir.local_decls.iter().map(|l| l.ty).enumerate() {
         let ty = mircx.monomorphize(&ty);
         debug!("local {} has type {:?}", index, ty);
-        if mircx.ccx.layout_of(ty).is_llvm_immediate() {
+        let layout = mircx.ccx.layout_of(ty);
+        if layout.is_llvm_immediate() {
             // These sorts of types are immediates that we can store
             // in an ValueRef without an alloca.
-        } else if common::type_is_imm_pair(mircx.ccx, ty) {
+        } else if layout.is_llvm_scalar_pair(mircx.ccx) {
             // We allow pairs and uses of any of their 2 fields.
         } else {
             // These sorts of types require an alloca. Note that
@@ -145,7 +145,8 @@ impl<'mir, 'a, 'tcx> Visitor<'tcx> for LocalAnalyzer<'mir, 'a, 'tcx> {
                         let ty = proj.base.ty(self.cx.mir, self.cx.ccx.tcx());
 
                         let ty = self.cx.monomorphize(&ty.to_ty(self.cx.ccx.tcx()));
-                        if common::type_is_imm_pair(self.cx.ccx, ty) {
+                        let layout = self.cx.ccx.layout_of(ty);
+                        if layout.is_llvm_scalar_pair(self.cx.ccx) {
                             return;
                         }
                     }
diff --git a/src/librustc_trans/mir/block.rs b/src/librustc_trans/mir/block.rs
index d1b6e9073b8..e739037b07d 100644
--- a/src/librustc_trans/mir/block.rs
+++ b/src/librustc_trans/mir/block.rs
@@ -135,11 +135,7 @@ impl<'a, 'tcx> MirContext<'a, 'tcx> {
                 if let Some((ret_dest, target)) = destination {
                     let ret_bcx = this.get_builder(target);
                     this.set_debug_loc(&ret_bcx, terminator.source_info);
-                    let op = OperandRef {
-                        val: Immediate(invokeret),
-                        layout: fn_ty.ret.layout,
-                    };
-                    this.store_return(&ret_bcx, ret_dest, &fn_ty.ret, op);
+                    this.store_return(&ret_bcx, ret_dest, &fn_ty.ret, invokeret);
                 }
             } else {
                 let llret = bcx.call(fn_ptr, &llargs, cleanup_bundle);
@@ -153,11 +149,7 @@ impl<'a, 'tcx> MirContext<'a, 'tcx> {
                 }
 
                 if let Some((ret_dest, target)) = destination {
-                    let op = OperandRef {
-                        val: Immediate(llret),
-                        layout: fn_ty.ret.layout,
-                    };
-                    this.store_return(&bcx, ret_dest, &fn_ty.ret, op);
+                    this.store_return(&bcx, ret_dest, &fn_ty.ret, llret);
                     funclet_br(this, bcx, target);
                 } else {
                     bcx.unreachable();
@@ -252,7 +244,7 @@ impl<'a, 'tcx> MirContext<'a, 'tcx> {
                     if let Ref(llval, align) = op.val {
                         bcx.load(llval, align.non_abi())
                     } else {
-                        op.pack_if_pair(&bcx).immediate()
+                        op.immediate_or_packed_pair(&bcx)
                     }
                 };
                 bcx.ret(llval);
@@ -545,12 +537,7 @@ impl<'a, 'tcx> MirContext<'a, 'tcx> {
                                          terminator.source_info.span);
 
                     if let ReturnDest::IndirectOperand(dst, _) = ret_dest {
-                        // Make a fake operand for store_return
-                        let op = OperandRef {
-                            val: Ref(dst.llval, Alignment::AbiAligned),
-                            layout: fn_ty.ret.layout,
-                        };
-                        self.store_return(&bcx, ret_dest, &fn_ty.ret, op);
+                        self.store_return(&bcx, ret_dest, &fn_ty.ret, dst.llval);
                     }
 
                     if let Some((_, target)) = *destination {
@@ -649,7 +636,7 @@ impl<'a, 'tcx> MirContext<'a, 'tcx> {
                     op.val.store(bcx, scratch);
                     (scratch.llval, Alignment::AbiAligned, true)
                 } else {
-                    (op.pack_if_pair(bcx).immediate(), Alignment::AbiAligned, false)
+                    (op.immediate_or_packed_pair(bcx), Alignment::AbiAligned, false)
                 }
             }
             Ref(llval, align @ Alignment::Packed(_)) if arg.is_indirect() => {
@@ -915,12 +902,12 @@ impl<'a, 'tcx> MirContext<'a, 'tcx> {
                     bcx: &Builder<'a, 'tcx>,
                     dest: ReturnDest<'tcx>,
                     ret_ty: &ArgType<'tcx>,
-                    op: OperandRef<'tcx>) {
+                    llval: ValueRef) {
         use self::ReturnDest::*;
 
         match dest {
             Nothing => (),
-            Store(dst) => ret_ty.store(bcx, op.immediate(), dst),
+            Store(dst) => ret_ty.store(bcx, llval, dst),
             IndirectOperand(tmp, index) => {
                 let op = tmp.load(bcx);
                 tmp.storage_dead(bcx);
@@ -929,14 +916,14 @@ impl<'a, 'tcx> MirContext<'a, 'tcx> {
             DirectOperand(index) => {
                 // If there is a cast, we have to store and reload.
                 let op = if ret_ty.cast.is_some() {
-                    let tmp = LvalueRef::alloca(bcx, op.layout, "tmp_ret");
+                    let tmp = LvalueRef::alloca(bcx, ret_ty.layout, "tmp_ret");
                     tmp.storage_live(bcx);
-                    ret_ty.store(bcx, op.immediate(), tmp);
+                    ret_ty.store(bcx, llval, tmp);
                     let op = tmp.load(bcx);
                     tmp.storage_dead(bcx);
                     op
                 } else {
-                    op.unpack_if_pair(bcx)
+                    OperandRef::from_immediate_or_packed_pair(bcx, llval, ret_ty.layout)
                 };
                 self.locals[index] = LocalRef::Operand(Some(op));
             }
diff --git a/src/librustc_trans/mir/constant.rs b/src/librustc_trans/mir/constant.rs
index 542893bd62b..3196300a706 100644
--- a/src/librustc_trans/mir/constant.rs
+++ b/src/librustc_trans/mir/constant.rs
@@ -139,13 +139,14 @@ impl<'a, 'tcx> Const<'tcx> {
     }
 
     pub fn to_operand(&self, ccx: &CrateContext<'a, 'tcx>) -> OperandRef<'tcx> {
-        let llty = ccx.layout_of(self.ty).immediate_llvm_type(ccx);
+        let layout = ccx.layout_of(self.ty);
+        let llty = layout.immediate_llvm_type(ccx);
         let llvalty = val_ty(self.llval);
 
-        let val = if llty == llvalty && common::type_is_imm_pair(ccx, self.ty) {
+        let val = if llty == llvalty && layout.is_llvm_scalar_pair(ccx) {
             let (a, b) = self.get_pair(ccx);
             OperandValue::Pair(a, b)
-        } else if llty == llvalty && ccx.layout_of(self.ty).is_llvm_immediate() {
+        } else if llty == llvalty && layout.is_llvm_immediate() {
             // If the types match, we can use the value directly.
             OperandValue::Immediate(self.llval)
         } else {
diff --git a/src/librustc_trans/mir/lvalue.rs b/src/librustc_trans/mir/lvalue.rs
index c6eb822ec87..8340d865eb1 100644
--- a/src/librustc_trans/mir/lvalue.rs
+++ b/src/librustc_trans/mir/lvalue.rs
@@ -16,7 +16,7 @@ use rustc::mir::tcx::LvalueTy;
 use rustc_data_structures::indexed_vec::Idx;
 use base;
 use builder::Builder;
-use common::{self, CrateContext, C_usize, C_u8, C_u32, C_uint, C_int, C_null, C_uint_big};
+use common::{CrateContext, C_usize, C_u8, C_u32, C_uint, C_int, C_null, C_uint_big};
 use consts;
 use type_of::LayoutLlvmExt;
 use type_::Type;
@@ -175,10 +175,10 @@ impl<'a, 'tcx> LvalueRef<'tcx> {
                 load
             };
             OperandValue::Immediate(base::to_immediate(bcx, llval, self.layout))
-        } else if common::type_is_imm_pair(bcx.ccx, self.layout.ty) {
+        } else if self.layout.is_llvm_scalar_pair(bcx.ccx) {
             OperandValue::Pair(
-                self.project_field(bcx, 0).load(bcx).pack_if_pair(bcx).immediate(),
-                self.project_field(bcx, 1).load(bcx).pack_if_pair(bcx).immediate())
+                self.project_field(bcx, 0).load(bcx).immediate(),
+                self.project_field(bcx, 1).load(bcx).immediate())
         } else {
             OperandValue::Ref(self.llval, self.alignment)
         };
diff --git a/src/librustc_trans/mir/mod.rs b/src/librustc_trans/mir/mod.rs
index 38719fedede..6f9d32b1a37 100644
--- a/src/librustc_trans/mir/mod.rs
+++ b/src/librustc_trans/mir/mod.rs
@@ -475,11 +475,9 @@ fn arg_local_refs<'a, 'tcx>(bcx: &Builder<'a, 'tcx>,
             let llarg = llvm::get_param(bcx.llfn(), llarg_idx as c_uint);
             bcx.set_value_name(llarg, &name);
             llarg_idx += 1;
-            let operand = OperandRef {
-                val: OperandValue::Immediate(llarg),
-                layout: arg.layout
-            };
-            return LocalRef::Operand(Some(operand.unpack_if_pair(bcx)));
+            return LocalRef::Operand(Some(
+                OperandRef::from_immediate_or_packed_pair(bcx, llarg, arg.layout)
+            ));
         } else {
             let tmp = LvalueRef::alloca(bcx, arg.layout, &name);
             arg.store_fn_arg(bcx, &mut llarg_idx, tmp);
diff --git a/src/librustc_trans/mir/operand.rs b/src/librustc_trans/mir/operand.rs
index 5659072fa93..3e7aa9d0db5 100644
--- a/src/librustc_trans/mir/operand.rs
+++ b/src/librustc_trans/mir/operand.rs
@@ -15,7 +15,7 @@ use rustc::mir;
 use rustc_data_structures::indexed_vec::Idx;
 
 use base;
-use common::{self, CrateContext, C_undef};
+use common::{CrateContext, C_undef};
 use builder::Builder;
 use value::Value;
 use type_of::LayoutLlvmExt;
@@ -24,7 +24,6 @@ use std::fmt;
 use std::ptr;
 
 use super::{MirContext, LocalRef};
-use super::constant::Const;
 use super::lvalue::{Alignment, LvalueRef};
 
 /// The representation of a Rust value. The enum variant is in fact
@@ -84,10 +83,10 @@ impl<'a, 'tcx> OperandRef<'tcx> {
     pub fn new_zst(ccx: &CrateContext<'a, 'tcx>,
                    layout: TyLayout<'tcx>) -> OperandRef<'tcx> {
         assert!(layout.is_zst());
-        let llty = layout.llvm_type(ccx);
-        // FIXME(eddyb) ZSTs should always be immediate, not pairs.
-        // This hack only exists to unpack a constant undef pair.
-        Const::new(C_undef(llty), layout.ty).to_operand(ccx)
+        OperandRef {
+            val: OperandValue::Immediate(C_undef(layout.llvm_type(ccx))),
+            layout
+        }
     }
 
     /// Asserts that this operand refers to a scalar and returns
@@ -115,12 +114,13 @@ impl<'a, 'tcx> OperandRef<'tcx> {
         }
     }
 
-    /// If this operand is a Pair, we return an
-    /// Immediate aggregate with the two values.
-    pub fn pack_if_pair(mut self, bcx: &Builder<'a, 'tcx>) -> OperandRef<'tcx> {
+    /// If this operand is a `Pair`, we return an aggregate with the two values.
+    /// For other cases, see `immediate`.
+    pub fn immediate_or_packed_pair(self, bcx: &Builder<'a, 'tcx>) -> ValueRef {
         if let OperandValue::Pair(a, b) = self.val {
             let llty = self.layout.llvm_type(bcx.ccx);
-            debug!("Operand::pack_if_pair: packing {:?} into {:?}", self, llty);
+            debug!("Operand::immediate_or_packed_pair: packing {:?} into {:?}",
+                   self, llty);
             // Reconstruct the immediate aggregate.
             let mut llpair = C_undef(llty);
             let elems = [a, b];
@@ -128,29 +128,33 @@ impl<'a, 'tcx> OperandRef<'tcx> {
                 let elem = base::from_immediate(bcx, elems[i]);
                 llpair = bcx.insert_value(llpair, elem, self.layout.llvm_field_index(i));
             }
-            self.val = OperandValue::Immediate(llpair);
+            llpair
+        } else {
+            self.immediate()
         }
-        self
     }
 
-    /// If this operand is a pair in an Immediate,
-    /// we return a Pair with the two halves.
-    pub fn unpack_if_pair(mut self, bcx: &Builder<'a, 'tcx>) -> OperandRef<'tcx> {
-        if let OperandValue::Immediate(llval) = self.val {
-            // Deconstruct the immediate aggregate.
-            if common::type_is_imm_pair(bcx.ccx, self.layout.ty) {
-                debug!("Operand::unpack_if_pair: unpacking {:?}", self);
+    /// If the type is a pair, we return a `Pair`, otherwise, an `Immediate`.
+    pub fn from_immediate_or_packed_pair(bcx: &Builder<'a, 'tcx>,
+                                         llval: ValueRef,
+                                         layout: TyLayout<'tcx>)
+                                         -> OperandRef<'tcx> {
+        let val = if layout.is_llvm_scalar_pair(bcx.ccx) {
+            debug!("Operand::from_immediate_or_packed_pair: unpacking {:?} @ {:?}",
+                    llval, layout);
 
-                let a = bcx.extract_value(llval, self.layout.llvm_field_index(0));
-                let a = base::to_immediate(bcx, a, self.layout.field(bcx.ccx, 0));
+            // Deconstruct the immediate aggregate.
+            let a = bcx.extract_value(llval, layout.llvm_field_index(0));
+            let a = base::to_immediate(bcx, a, layout.field(bcx.ccx, 0));
 
-                let b = bcx.extract_value(llval, self.layout.llvm_field_index(1));
-                let b = base::to_immediate(bcx, b, self.layout.field(bcx.ccx, 1));
+            let b = bcx.extract_value(llval, layout.llvm_field_index(1));
+            let b = base::to_immediate(bcx, b, layout.field(bcx.ccx, 1));
 
-                self.val = OperandValue::Pair(a, b);
-            }
-        }
-        self
+            OperandValue::Pair(a, b)
+        } else {
+            OperandValue::Immediate(llval)
+        };
+        OperandRef { val, layout }
     }
 }
 
@@ -170,16 +174,9 @@ impl<'a, 'tcx> OperandValue {
                 bcx.store(base::from_immediate(bcx, s), dest.llval, dest.alignment.non_abi());
             }
             OperandValue::Pair(a, b) => {
-                // See comment above about zero-sized values.
-                let dest_a = dest.project_field(bcx, 0);
-                if !dest_a.layout.is_zst() {
-                    let a = base::from_immediate(bcx, a);
-                    bcx.store(a, dest_a.llval, dest_a.alignment.non_abi());
-                }
-                let dest_b = dest.project_field(bcx, 1);
-                if !dest_b.layout.is_zst() {
-                    let b = base::from_immediate(bcx, b);
-                    bcx.store(b, dest_b.llval, dest_b.alignment.non_abi());
+                for (i, &x) in [a, b].iter().enumerate() {
+                    OperandValue::Immediate(x)
+                        .store(bcx, dest.project_field(bcx, i));
                 }
             }
         }
@@ -218,13 +215,10 @@ impl<'a, 'tcx> MirContext<'a, 'tcx> {
                         (OperandValue::Pair(a, b),
                          &mir::ProjectionElem::Field(ref f, ty)) => {
                             let llval = [a, b][f.index()];
-                            let op = OperandRef {
+                            return OperandRef {
                                 val: OperandValue::Immediate(llval),
                                 layout: bcx.ccx.layout_of(self.monomorphize(&ty))
                             };
-
-                            // Handle nested pairs.
-                            return op.unpack_if_pair(bcx);
                         }
                         _ => {}
                     }
diff --git a/src/librustc_trans/mir/rvalue.rs b/src/librustc_trans/mir/rvalue.rs
index e52dcd07562..33b1a7e3363 100644
--- a/src/librustc_trans/mir/rvalue.rs
+++ b/src/librustc_trans/mir/rvalue.rs
@@ -70,9 +70,8 @@ impl<'a, 'tcx> MirContext<'a, 'tcx> {
                 // `CoerceUnsized` can be passed by a where-clause,
                 // so the (generic) MIR may not be able to expand it.
                 let operand = self.trans_operand(&bcx, source);
-                let operand = operand.pack_if_pair(&bcx);
                 match operand.val {
-                    OperandValue::Pair(..) => bug!(),
+                    OperandValue::Pair(..) |
                     OperandValue::Immediate(_) => {
                         // unsize from an immediate structure. We don't
                         // really need a temporary alloca here, but
diff --git a/src/librustc_trans/type_of.rs b/src/librustc_trans/type_of.rs
index 529ad51ba8e..6da6f1ebaf0 100644
--- a/src/librustc_trans/type_of.rs
+++ b/src/librustc_trans/type_of.rs
@@ -174,6 +174,7 @@ pub struct PointeeInfo {
 
 pub trait LayoutLlvmExt<'tcx> {
     fn is_llvm_immediate(&self) -> bool;
+    fn is_llvm_scalar_pair<'a>(&self, ccx: &CrateContext<'a, 'tcx>) -> bool;
     fn llvm_type<'a>(&self, ccx: &CrateContext<'a, 'tcx>) -> Type;
     fn immediate_llvm_type<'a>(&self, ccx: &CrateContext<'a, 'tcx>) -> Type;
     fn over_align(&self) -> Option<Align>;
@@ -192,6 +193,24 @@ impl<'tcx> LayoutLlvmExt<'tcx> for TyLayout<'tcx> {
         }
     }
 
+    fn is_llvm_scalar_pair<'a>(&self, ccx: &CrateContext<'a, 'tcx>) -> bool {
+        match self.fields {
+            layout::FieldPlacement::Arbitrary { .. } => {
+                // There must be only 2 fields.
+                if self.fields.count() != 2 {
+                    return false;
+                }
+
+                // The two fields must be both scalars.
+                match (&self.field(ccx, 0).abi, &self.field(ccx, 1).abi) {
+                    (&layout::Abi::Scalar(_), &layout::Abi::Scalar(_)) => true,
+                    _ => false
+                }
+            }
+            _ => false
+        }
+    }
+
     /// Get the LLVM type corresponding to a Rust type, i.e. `rustc::ty::Ty`.
     /// The pointee type of the pointer in `LvalueRef` is always this type.
     /// For sized types, it is also the right LLVM type for an `alloca`