From f1f453cf3b124711b2e20315937403d89913bcd2 Mon Sep 17 00:00:00 2001 From: Eduard Burtescu Date: Wed, 25 May 2016 11:55:44 +0300 Subject: [PATCH] trans: generalize OperandValue::FatPtr to all pairs of immediates. --- src/librustc_trans/common.rs | 58 ++++++++++++++++ src/librustc_trans/mir/block.rs | 107 +++++++++++++++++++---------- src/librustc_trans/mir/constant.rs | 18 +++-- src/librustc_trans/mir/operand.rs | 100 +++++++++++++++++++++------ src/librustc_trans/mir/rvalue.rs | 46 +++++-------- 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, 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) } }