about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--src/librustc_trans/common.rs58
-rw-r--r--src/librustc_trans/mir/block.rs107
-rw-r--r--src/librustc_trans/mir/constant.rs18
-rw-r--r--src/librustc_trans/mir/operand.rs100
-rw-r--r--src/librustc_trans/mir/rvalue.rs46
5 files changed, 238 insertions, 91 deletions
diff --git a/src/librustc_trans/common.rs b/src/librustc_trans/common.rs
index e9b7b590b19..884833ca79a 100644
--- a/src/librustc_trans/common.rs
+++ b/src/librustc_trans/common.rs
@@ -39,6 +39,7 @@ use monomorphize;
 use type_::Type;
 use value::Value;
 use rustc::ty::{self, Ty, TyCtxt};
+use rustc::ty::layout::Layout;
 use rustc::traits::{self, SelectionContext, ProjectionMode};
 use rustc::ty::fold::TypeFoldable;
 use rustc::hir;
@@ -99,6 +100,63 @@ pub fn type_is_immediate<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, ty: Ty<'tcx>) -
     }
 }
 
+/// Returns Some([a, b]) if the type has a pair of fields with types a and b.
+pub fn type_pair_fields<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, ty: Ty<'tcx>)
+                                  -> Option<[Ty<'tcx>; 2]> {
+    match ty.sty {
+        ty::TyEnum(adt, substs) | ty::TyStruct(adt, substs) => {
+            assert_eq!(adt.variants.len(), 1);
+            let fields = &adt.variants[0].fields;
+            if fields.len() != 2 {
+                return None;
+            }
+            Some([monomorphize::field_ty(ccx.tcx(), substs, &fields[0]),
+                  monomorphize::field_ty(ccx.tcx(), substs, &fields[1])])
+        }
+        ty::TyClosure(_, ty::ClosureSubsts { upvar_tys: tys, .. }) |
+        ty::TyTuple(tys) => {
+            if tys.len() != 2 {
+                return None;
+            }
+            Some([tys[0], tys[1]])
+        }
+        _ => None
+    }
+}
+
+/// 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 tcx = ccx.tcx();
+    let layout = tcx.normalizing_infer_ctxt(ProjectionMode::Any).enter(|infcx| {
+        match ty.layout(&infcx) {
+            Ok(layout) => layout,
+            Err(err) => {
+                bug!("type_is_imm_pair: layout for `{:?}` failed: {}",
+                     ty, err);
+            }
+        }
+    });
+
+    match *layout {
+        Layout::FatPointer { .. } => true,
+        Layout::Univariant { ref variant, .. } => {
+            // There must be only 2 fields.
+            if variant.offset_after_field.len() != 2 {
+                return false;
+            }
+
+            match type_pair_fields(ccx, ty) {
+                Some([a, b]) => {
+                    type_is_immediate(ccx, a) && type_is_immediate(ccx, b)
+                }
+                None => false
+            }
+        }
+        _ => false
+    }
+}
+
 /// Identify types which have size zero at runtime.
 pub fn type_is_zero_size<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, ty: Ty<'tcx>) -> bool {
     use machine::llsize_of_alloc;
diff --git a/src/librustc_trans/mir/block.rs b/src/librustc_trans/mir/block.rs
index e4d137d36ac..cf41f5bf2bc 100644
--- a/src/librustc_trans/mir/block.rs
+++ b/src/librustc_trans/mir/block.rs
@@ -17,7 +17,7 @@ use adt;
 use base;
 use build;
 use callee::{Callee, CalleeData, Fn, Intrinsic, NamedTupleConstructor, Virtual};
-use common::{self, type_is_fat_ptr, Block, BlockAndBuilder, LandingPad};
+use common::{self, Block, BlockAndBuilder, LandingPad};
 use common::{C_bool, C_str_slice, C_struct, C_u32, C_undef};
 use consts;
 use debuginfo::DebugLoc;
@@ -36,7 +36,7 @@ use super::analyze::CleanupKind;
 use super::constant::Const;
 use super::lvalue::{LvalueRef, load_fat_ptr};
 use super::operand::OperandRef;
-use super::operand::OperandValue::{self, FatPtr, Immediate, Ref};
+use super::operand::OperandValue::*;
 
 impl<'bcx, 'tcx> MirContext<'bcx, 'tcx> {
     pub fn trans_block(&mut self, bb: mir::BasicBlock) {
@@ -410,8 +410,8 @@ impl<'bcx, 'tcx> MirContext<'bcx, 'tcx> {
                         }
                     }
 
-                    let val = self.trans_operand(&bcx, arg).val;
-                    self.trans_argument(&bcx, val, &mut llargs, &fn_ty,
+                    let op = self.trans_operand(&bcx, arg);
+                    self.trans_argument(&bcx, op, &mut llargs, &fn_ty,
                                         &mut idx, &mut callee.data);
                 }
                 if let Some(tup) = untuple {
@@ -449,7 +449,7 @@ impl<'bcx, 'tcx> MirContext<'bcx, 'tcx> {
                         if let ReturnDest::IndirectOperand(dst, _) = ret_dest {
                             // Make a fake operand for store_return
                             let op = OperandRef {
-                                val: OperandValue::Ref(dst),
+                                val: Ref(dst),
                                 ty: sig.output.unwrap()
                             };
                             self.store_return(&bcx, ret_dest, fn_ty.ret, op);
@@ -487,7 +487,7 @@ impl<'bcx, 'tcx> MirContext<'bcx, 'tcx> {
                         ret_bcx.at_start(|ret_bcx| {
                             debug_loc.apply_to_bcx(ret_bcx);
                             let op = OperandRef {
-                                val: OperandValue::Immediate(invokeret),
+                                val: Immediate(invokeret),
                                 ty: sig.output.unwrap()
                             };
                             self.store_return(&ret_bcx, ret_dest, fn_ty.ret, op);
@@ -498,7 +498,7 @@ impl<'bcx, 'tcx> MirContext<'bcx, 'tcx> {
                     fn_ty.apply_attrs_callsite(llret);
                     if let Some((_, target)) = *destination {
                         let op = OperandRef {
-                            val: OperandValue::Immediate(llret),
+                            val: Immediate(llret),
                             ty: sig.output.unwrap()
                         };
                         self.store_return(&bcx, ret_dest, fn_ty.ret, op);
@@ -513,25 +513,36 @@ impl<'bcx, 'tcx> MirContext<'bcx, 'tcx> {
 
     fn trans_argument(&mut self,
                       bcx: &BlockAndBuilder<'bcx, 'tcx>,
-                      val: OperandValue,
+                      mut op: OperandRef<'tcx>,
                       llargs: &mut Vec<ValueRef>,
                       fn_ty: &FnType,
                       next_idx: &mut usize,
                       callee: &mut CalleeData) {
-        // Treat the values in a fat pointer separately.
-        if let FatPtr(ptr, meta) = val {
-            if *next_idx == 0 {
-                if let Virtual(idx) = *callee {
-                    let llfn = bcx.with_block(|bcx| {
-                        meth::get_virtual_method(bcx, meta, idx)
-                    });
-                    let llty = fn_ty.llvm_type(bcx.ccx()).ptr_to();
-                    *callee = Fn(bcx.pointercast(llfn, llty));
+        if let Pair(a, b) = op.val {
+            // Treat the values in a fat pointer separately.
+            if common::type_is_fat_ptr(bcx.tcx(), op.ty) {
+                let (ptr, meta) = (a, b);
+                if *next_idx == 0 {
+                    if let Virtual(idx) = *callee {
+                        let llfn = bcx.with_block(|bcx| {
+                            meth::get_virtual_method(bcx, meta, idx)
+                        });
+                        let llty = fn_ty.llvm_type(bcx.ccx()).ptr_to();
+                        *callee = Fn(bcx.pointercast(llfn, llty));
+                    }
                 }
+
+                let imm_op = |x| OperandRef {
+                    val: Immediate(x),
+                    // We won't be checking the type again.
+                    ty: bcx.tcx().types.err
+                };
+                self.trans_argument(bcx, imm_op(ptr), llargs, fn_ty, next_idx, callee);
+                self.trans_argument(bcx, imm_op(meta), llargs, fn_ty, next_idx, callee);
+                return;
             }
-            self.trans_argument(bcx, Immediate(ptr), llargs, fn_ty, next_idx, callee);
-            self.trans_argument(bcx, Immediate(meta), llargs, fn_ty, next_idx, callee);
-            return;
+
+            op = op.pack_if_pair(bcx);
         }
 
         let arg = &fn_ty.args[*next_idx];
@@ -547,7 +558,7 @@ impl<'bcx, 'tcx> MirContext<'bcx, 'tcx> {
         }
 
         // Force by-ref if we have to load through a cast pointer.
-        let (mut llval, by_ref) = match val {
+        let (mut llval, by_ref) = match op.val {
             Immediate(llval) if arg.is_indirect() || arg.cast.is_some() => {
                 let llscratch = build::AllocaFcx(bcx.fcx(), arg.original_ty, "arg");
                 bcx.store(llval, llscratch);
@@ -555,7 +566,7 @@ impl<'bcx, 'tcx> MirContext<'bcx, 'tcx> {
             }
             Immediate(llval) => (llval, false),
             Ref(llval) => (llval, true),
-            FatPtr(_, _) => bug!("fat pointers handled above")
+            Pair(..) => bug!("pairs handled above")
         };
 
         if by_ref && !arg.is_indirect() {
@@ -602,12 +613,16 @@ impl<'bcx, 'tcx> MirContext<'bcx, 'tcx> {
                     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) = load_fat_ptr(bcx, ptr);
-                        FatPtr(lldata, llextra)
+                        Pair(lldata, llextra)
                     } else {
                         // trans_argument will load this if it needs to
                         Ref(ptr)
                     };
-                    self.trans_argument(bcx, val, llargs, fn_ty, next_idx, callee);
+                    let op = OperandRef {
+                        val: val,
+                        ty: ty
+                    };
+                    self.trans_argument(bcx, op, llargs, fn_ty, next_idx, callee);
                 }
 
             }
@@ -619,11 +634,29 @@ impl<'bcx, 'tcx> MirContext<'bcx, 'tcx> {
                         elem = bcx.trunc(elem, Type::i1(bcx.ccx()));
                     }
                     // If the tuple is immediate, the elements are as well
-                    let val = Immediate(elem);
-                    self.trans_argument(bcx, val, llargs, fn_ty, next_idx, callee);
+                    let op = OperandRef {
+                        val: Immediate(elem),
+                        ty: ty
+                    };
+                    self.trans_argument(bcx, op, llargs, fn_ty, next_idx, callee);
+                }
+            }
+            Pair(a, b) => {
+                let elems = [a, b];
+                for (n, &ty) in arg_types.iter().enumerate() {
+                    let mut elem = elems[n];
+                    // Truncate bools to i1, if needed
+                    if ty.is_bool() && common::val_ty(elem) != Type::i1(bcx.ccx()) {
+                        elem = bcx.trunc(elem, Type::i1(bcx.ccx()));
+                    }
+                    // Pair is always made up of immediates
+                    let op = OperandRef {
+                        val: Immediate(elem),
+                        ty: ty
+                    };
+                    self.trans_argument(bcx, op, llargs, fn_ty, next_idx, callee);
                 }
             }
-            FatPtr(_, _) => bug!("tuple is a fat pointer?!")
         }
 
     }
@@ -779,7 +812,7 @@ impl<'bcx, 'tcx> MirContext<'bcx, 'tcx> {
                 let f = Callee::def(bcx.ccx(), def_id, substs);
                 let datum = f.reify(bcx.ccx());
                 val = OperandRef {
-                    val: OperandValue::Immediate(datum.val),
+                    val: Immediate(datum.val),
                     ty: datum.ty
                 };
             }
@@ -806,17 +839,15 @@ impl<'bcx, 'tcx> MirContext<'bcx, 'tcx> {
                 self.temps[idx as usize] = TempRef::Operand(Some(op));
             }
             DirectOperand(idx) => {
-                let op = if type_is_fat_ptr(bcx.tcx(), op.ty) {
-                    let llval = op.immediate();
-                    let ptr = bcx.extract_value(llval, 0);
-                    let meta = bcx.extract_value(llval, 1);
-
-                    OperandRef {
-                        val: OperandValue::FatPtr(ptr, meta),
-                        ty: op.ty
-                    }
+                // If there is a cast, we have to store and reload.
+                let op = if ret_ty.cast.is_some() {
+                    let tmp = bcx.with_block(|bcx| {
+                        base::alloc_ty(bcx, op.ty, "tmp_ret")
+                    });
+                    ret_ty.store(bcx, op.immediate(), tmp);
+                    self.trans_load(bcx, tmp, op.ty)
                 } else {
-                    op
+                    op.unpack_if_pair(bcx)
                 };
                 self.temps[idx as usize] = TempRef::Operand(Some(op));
             }
diff --git a/src/librustc_trans/mir/constant.rs b/src/librustc_trans/mir/constant.rs
index 9498a244e80..e73d02a1e29 100644
--- a/src/librustc_trans/mir/constant.rs
+++ b/src/librustc_trans/mir/constant.rs
@@ -98,9 +98,15 @@ impl<'tcx> Const<'tcx> {
         Const::new(val, ty)
     }
 
+    fn get_pair(&self) -> (ValueRef, ValueRef) {
+        (const_get_elt(self.llval, &[0]),
+         const_get_elt(self.llval, &[1]))
+    }
+
     fn get_fat_ptr(&self) -> (ValueRef, ValueRef) {
-        (const_get_elt(self.llval, &[abi::FAT_PTR_ADDR as u32]),
-         const_get_elt(self.llval, &[abi::FAT_PTR_EXTRA as u32]))
+        assert_eq!(abi::FAT_PTR_ADDR, 0);
+        assert_eq!(abi::FAT_PTR_EXTRA, 1);
+        self.get_pair()
     }
 
     fn as_lvalue(&self) -> ConstLvalue<'tcx> {
@@ -115,9 +121,9 @@ impl<'tcx> Const<'tcx> {
         let llty = type_of::immediate_type_of(ccx, self.ty);
         let llvalty = val_ty(self.llval);
 
-        let val = if common::type_is_fat_ptr(ccx.tcx(), self.ty) {
-            let (data, extra) = self.get_fat_ptr();
-            OperandValue::FatPtr(data, extra)
+        let val = if common::type_is_imm_pair(ccx, self.ty) {
+            let (a, b) = self.get_pair();
+            OperandValue::Pair(a, b)
         } else if common::type_is_immediate(ccx, self.ty) && llty == llvalty {
             // If the types match, we can use the value directly.
             OperandValue::Immediate(self.llval)
@@ -656,7 +662,7 @@ impl<'a, 'tcx> MirConstContext<'a, 'tcx> {
                                 consts::ptrcast(data_ptr, ll_cast_ty)
                             }
                         } else {
-                            bug!("Unexpected non-FatPtr operand")
+                            bug!("Unexpected non-fat-pointer operand")
                         }
                     }
                 };
diff --git a/src/librustc_trans/mir/operand.rs b/src/librustc_trans/mir/operand.rs
index 107ec1159f0..9e04f1cb207 100644
--- a/src/librustc_trans/mir/operand.rs
+++ b/src/librustc_trans/mir/operand.rs
@@ -13,12 +13,12 @@ use rustc::ty::Ty;
 use rustc::mir::repr as mir;
 use base;
 use common::{self, Block, BlockAndBuilder};
-use datum;
 use value::Value;
+use type_of;
+use type_::Type;
 
 use std::fmt;
 
-use super::lvalue::load_fat_ptr;
 use super::{MirContext, TempRef};
 
 /// The representation of a Rust value. The enum variant is in fact
@@ -31,9 +31,8 @@ pub enum OperandValue {
     Ref(ValueRef),
     /// A single LLVM value.
     Immediate(ValueRef),
-    /// A fat pointer. The first ValueRef is the data and the second
-    /// is the extra.
-    FatPtr(ValueRef, ValueRef)
+    /// A pair of immediate LLVM values. Used by fat pointers too.
+    Pair(ValueRef, ValueRef)
 }
 
 /// An `OperandRef` is an "SSA" reference to a Rust value, along with
@@ -64,15 +63,15 @@ impl<'tcx> fmt::Debug for OperandRef<'tcx> {
                 write!(f, "OperandRef(Immediate({:?}) @ {:?})",
                        Value(i), self.ty)
             }
-            OperandValue::FatPtr(a, d) => {
-                write!(f, "OperandRef(FatPtr({:?}, {:?}) @ {:?})",
-                       Value(a), Value(d), self.ty)
+            OperandValue::Pair(a, b) => {
+                write!(f, "OperandRef(Pair({:?}, {:?}) @ {:?})",
+                       Value(a), Value(b), self.ty)
             }
         }
     }
 }
 
-impl<'tcx> OperandRef<'tcx> {
+impl<'bcx, 'tcx> OperandRef<'tcx> {
     /// Asserts that this operand refers to a scalar and returns
     /// a reference to its value.
     pub fn immediate(self) -> ValueRef {
@@ -81,6 +80,54 @@ impl<'tcx> OperandRef<'tcx> {
             _ => bug!()
         }
     }
+
+    /// If this operand is a Pair, we return an
+    /// Immediate aggregate with the two values.
+    pub fn pack_if_pair(mut self, bcx: &BlockAndBuilder<'bcx, 'tcx>)
+                        -> OperandRef<'tcx> {
+        if let OperandValue::Pair(a, b) = self.val {
+            // Reconstruct the immediate aggregate.
+            let llty = type_of::type_of(bcx.ccx(), self.ty);
+            let mut llpair = common::C_undef(llty);
+            let elems = [a, b];
+            for i in 0..2 {
+                let mut elem = elems[i];
+                // Extend boolean i1's to i8.
+                if common::val_ty(elem) == Type::i1(bcx.ccx()) {
+                    elem = bcx.zext(elem, Type::i8(bcx.ccx()));
+                }
+                llpair = bcx.insert_value(llpair, elem, i);
+            }
+            self.val = OperandValue::Immediate(llpair);
+        }
+        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: &BlockAndBuilder<'bcx, 'tcx>)
+                          -> OperandRef<'tcx> {
+        if let OperandValue::Immediate(llval) = self.val {
+            // Deconstruct the immediate aggregate.
+            if common::type_is_imm_pair(bcx.ccx(), self.ty) {
+                let mut a = bcx.extract_value(llval, 0);
+                let mut b = bcx.extract_value(llval, 1);
+
+                let pair_fields = common::type_pair_fields(bcx.ccx(), self.ty);
+                if let Some([a_ty, b_ty]) = pair_fields {
+                    if a_ty.is_bool() {
+                        a = bcx.trunc(a, Type::i1(bcx.ccx()));
+                    }
+                    if b_ty.is_bool() {
+                        b = bcx.trunc(b, Type::i1(bcx.ccx()));
+                    }
+                }
+
+                self.val = OperandValue::Pair(a, b);
+            }
+        }
+        self
+    }
 }
 
 impl<'bcx, 'tcx> MirContext<'bcx, 'tcx> {
@@ -92,15 +139,24 @@ impl<'bcx, 'tcx> MirContext<'bcx, 'tcx> {
     {
         debug!("trans_load: {:?} @ {:?}", Value(llval), ty);
 
-        let val = match datum::appropriate_rvalue_mode(bcx.ccx(), ty) {
-            datum::ByValue => {
-                OperandValue::Immediate(base::load_ty_builder(bcx, llval, ty))
-            }
-            datum::ByRef if common::type_is_fat_ptr(bcx.tcx(), ty) => {
-                let (lldata, llextra) = load_fat_ptr(bcx, llval);
-                OperandValue::FatPtr(lldata, llextra)
-            }
-            datum::ByRef => OperandValue::Ref(llval)
+        let val = if common::type_is_imm_pair(bcx.ccx(), ty) {
+            let a_ptr = bcx.struct_gep(llval, 0);
+            let b_ptr = bcx.struct_gep(llval, 1);
+
+            // This is None only for fat pointers, which don't
+            // need any special load-time behavior anyway.
+            let pair_fields = common::type_pair_fields(bcx.ccx(), ty);
+            let (a, b) = if let Some([a_ty, b_ty]) = pair_fields {
+                (base::load_ty_builder(bcx, a_ptr, a_ty),
+                 base::load_ty_builder(bcx, b_ptr, b_ty))
+            } else {
+                (bcx.load(a_ptr), bcx.load(b_ptr))
+            };
+            OperandValue::Pair(a, b)
+        } else if common::type_is_immediate(bcx.ccx(), ty) {
+            OperandValue::Immediate(base::load_ty_builder(bcx, llval, ty))
+        } else {
+            OperandValue::Ref(llval)
         };
 
         OperandRef { val: val, ty: ty }
@@ -173,8 +229,12 @@ impl<'bcx, 'tcx> MirContext<'bcx, 'tcx> {
         match operand.val {
             OperandValue::Ref(r) => base::memcpy_ty(bcx, lldest, r, operand.ty),
             OperandValue::Immediate(s) => base::store_ty(bcx, s, lldest, operand.ty),
-            OperandValue::FatPtr(data, extra) => {
-                base::store_fat_ptr(bcx, data, extra, lldest, operand.ty);
+            OperandValue::Pair(a, b) => {
+                use build::*;
+                let a = base::from_immediate(bcx, a);
+                let b = base::from_immediate(bcx, b);
+                Store(bcx, a, StructGEP(bcx, lldest, 0));
+                Store(bcx, b, StructGEP(bcx, lldest, 1));
             }
         }
     }
diff --git a/src/librustc_trans/mir/rvalue.rs b/src/librustc_trans/mir/rvalue.rs
index b0567ab26e7..d019677d0e6 100644
--- a/src/librustc_trans/mir/rvalue.rs
+++ b/src/librustc_trans/mir/rvalue.rs
@@ -16,14 +16,12 @@ use rustc::mir::repr as mir;
 use asm;
 use base;
 use callee::Callee;
-use common::{self, val_ty,
-             C_null, C_uint, C_undef, BlockAndBuilder, Result};
+use common::{self, val_ty, C_null, C_uint, BlockAndBuilder, Result};
 use datum::{Datum, Lvalue};
 use debuginfo::DebugLoc;
 use adt;
 use machine;
 use type_of;
-use type_::Type;
 use tvec;
 use value::Value;
 use Disr;
@@ -68,9 +66,10 @@ impl<'bcx, 'tcx> MirContext<'bcx, '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);
                 bcx.with_block(|bcx| {
                     match operand.val {
-                        OperandValue::FatPtr(..) => bug!(),
+                        OperandValue::Pair(..) => bug!(),
                         OperandValue::Immediate(llval) => {
                             // unsize from an immediate structure. We don't
                             // really need a temporary alloca here, but
@@ -255,7 +254,7 @@ impl<'bcx, 'tcx> MirContext<'bcx, 'tcx> {
                         assert!(common::type_is_fat_ptr(bcx.tcx(), cast_ty));
 
                         match operand.val {
-                            OperandValue::FatPtr(lldata, llextra) => {
+                            OperandValue::Pair(lldata, llextra) => {
                                 // unsize from a fat pointer - this is a
                                 // "trait-object-to-supertrait" coercion, for
                                 // example,
@@ -264,7 +263,7 @@ impl<'bcx, 'tcx> MirContext<'bcx, 'tcx> {
                                 // the types match up.
                                 let llcast_ty = type_of::fat_ptr_base_ty(bcx.ccx(), cast_ty);
                                 let lldata = bcx.pointercast(lldata, llcast_ty);
-                                OperandValue::FatPtr(lldata, llextra)
+                                OperandValue::Pair(lldata, llextra)
                             }
                             OperandValue::Immediate(lldata) => {
                                 // "standard" unsize
@@ -272,7 +271,7 @@ impl<'bcx, 'tcx> MirContext<'bcx, 'tcx> {
                                     base::unsize_thin_ptr(bcx, lldata,
                                                           operand.ty, cast_ty)
                                 });
-                                OperandValue::FatPtr(lldata, llextra)
+                                OperandValue::Pair(lldata, llextra)
                             }
                             OperandValue::Ref(_) => {
                                 bug!("by-ref operand {:?} in trans_rvalue_operand",
@@ -343,13 +342,13 @@ impl<'bcx, 'tcx> MirContext<'bcx, 'tcx> {
                     mir::CastKind::Misc => { // Casts from a fat-ptr.
                         let ll_cast_ty = type_of::immediate_type_of(bcx.ccx(), cast_ty);
                         let ll_from_ty = type_of::immediate_type_of(bcx.ccx(), operand.ty);
-                        if let OperandValue::FatPtr(data_ptr, meta_ptr) = operand.val {
+                        if let OperandValue::Pair(data_ptr, meta_ptr) = operand.val {
                             if common::type_is_fat_ptr(bcx.tcx(), cast_ty) {
                                 let ll_cft = ll_cast_ty.field_types();
                                 let ll_fft = ll_from_ty.field_types();
                                 let data_cast = bcx.pointercast(data_ptr, ll_cft[0]);
                                 assert_eq!(ll_cft[1].kind(), ll_fft[1].kind());
-                                OperandValue::FatPtr(data_cast, meta_ptr)
+                                OperandValue::Pair(data_cast, meta_ptr)
                             } else { // cast to thin-ptr
                                 // Cast of fat-ptr to thin-ptr is an extraction of data-ptr and
                                 // pointer-cast of that pointer to desired pointer type.
@@ -357,7 +356,7 @@ impl<'bcx, 'tcx> MirContext<'bcx, 'tcx> {
                                 OperandValue::Immediate(llval)
                             }
                         } else {
-                            bug!("Unexpected non-FatPtr operand")
+                            bug!("Unexpected non-Pair operand")
                         }
                     }
                 };
@@ -386,8 +385,8 @@ impl<'bcx, 'tcx> MirContext<'bcx, 'tcx> {
                     }
                 } else {
                     OperandRef {
-                        val: OperandValue::FatPtr(tr_lvalue.llval,
-                                                  tr_lvalue.llextra),
+                        val: OperandValue::Pair(tr_lvalue.llval,
+                                                tr_lvalue.llextra),
                         ty: ref_ty,
                     }
                 };
@@ -408,8 +407,8 @@ impl<'bcx, 'tcx> MirContext<'bcx, 'tcx> {
                 let rhs = self.trans_operand(&bcx, rhs);
                 let llresult = if common::type_is_fat_ptr(bcx.tcx(), lhs.ty) {
                     match (lhs.val, rhs.val) {
-                        (OperandValue::FatPtr(lhs_addr, lhs_extra),
-                         OperandValue::FatPtr(rhs_addr, rhs_extra)) => {
+                        (OperandValue::Pair(lhs_addr, lhs_extra),
+                         OperandValue::Pair(rhs_addr, rhs_extra)) => {
                             bcx.with_block(|bcx| {
                                 base::compare_fat_ptrs(bcx,
                                                        lhs_addr, lhs_extra,
@@ -441,7 +440,7 @@ impl<'bcx, 'tcx> MirContext<'bcx, 'tcx> {
                 let val_ty = self.mir.binop_ty(bcx.tcx(), op, lhs.ty, rhs.ty);
                 let operand_ty = bcx.tcx().mk_tup(vec![val_ty, bcx.tcx().types.bool]);
                 let operand = OperandRef {
-                    val: OperandValue::Immediate(result),
+                    val: result,
                     ty: operand_ty
                 };
 
@@ -579,7 +578,7 @@ impl<'bcx, 'tcx> MirContext<'bcx, 'tcx> {
                                       op: mir::BinOp,
                                       lhs: ValueRef,
                                       rhs: ValueRef,
-                                      input_ty: Ty<'tcx>) -> ValueRef {
+                                      input_ty: Ty<'tcx>) -> OperandValue {
         let (val, of) = match op {
             // These are checked using intrinsics
             mir::BinOp::Add | mir::BinOp::Sub | mir::BinOp::Mul => {
@@ -592,10 +591,8 @@ impl<'bcx, 'tcx> MirContext<'bcx, 'tcx> {
                 let intrinsic = get_overflow_intrinsic(oop, bcx, input_ty);
                 let res = bcx.call(intrinsic, &[lhs, rhs], None);
 
-                let val = bcx.extract_value(res, 0);
-                let of = bcx.extract_value(res, 1);
-
-                (val, bcx.zext(of, Type::bool(bcx.ccx())))
+                (bcx.extract_value(res, 0),
+                 bcx.extract_value(res, 1))
             }
             mir::BinOp::Shl | mir::BinOp::Shr => {
                 let lhs_llty = val_ty(lhs);
@@ -608,19 +605,14 @@ impl<'bcx, 'tcx> MirContext<'bcx, 'tcx> {
                 let of = bcx.icmp(llvm::IntNE, outer_bits, C_null(rhs_llty));
                 let val = self.trans_scalar_binop(bcx, op, lhs, rhs, input_ty);
 
-                (val, bcx.zext(of, Type::bool(bcx.ccx())))
+                (val, of)
             }
             _ => {
                 bug!("Operator `{:?}` is not a checkable operator", op)
             }
         };
 
-        let val_ty = val_ty(val);
-        let res_ty = Type::struct_(bcx.ccx(), &[val_ty, Type::bool(bcx.ccx())], false);
-
-        let mut res_val = C_undef(res_ty);
-        res_val = bcx.insert_value(res_val, val, 0);
-        bcx.insert_value(res_val, of, 1)
+        OperandValue::Pair(val, of)
     }
 }