trans: generalize OperandValue::FatPtr to all pairs of immediates.

This commit is contained in:
Eduard Burtescu 2016-05-25 11:55:44 +03:00
parent 156b1fb9e1
commit f1f453cf3b
5 changed files with 238 additions and 91 deletions

View File

@ -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;

View File

@ -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));
}

View File

@ -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")
}
}
};

View File

@ -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));
}
}
}

View File

@ -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)
}
}