rustc_trans: restrict "immediate pairs" to pairs of scalars.
This commit is contained in:
parent
ac60872077
commit
f1b7cd9925
@ -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))
|
||||
}
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
@ -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));
|
||||
}
|
||||
|
@ -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 {
|
||||
|
@ -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)
|
||||
};
|
||||
|
@ -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);
|
||||
|
@ -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 {
|
||||
/// 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);
|
||||
|
||||
// Deconstruct the immediate aggregate.
|
||||
if common::type_is_imm_pair(bcx.ccx, self.layout.ty) {
|
||||
debug!("Operand::unpack_if_pair: unpacking {:?}", self);
|
||||
let a = bcx.extract_value(llval, layout.llvm_field_index(0));
|
||||
let a = base::to_immediate(bcx, a, layout.field(bcx.ccx, 0));
|
||||
|
||||
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));
|
||||
let b = bcx.extract_value(llval, layout.llvm_field_index(1));
|
||||
let b = base::to_immediate(bcx, b, layout.field(bcx.ccx, 1));
|
||||
|
||||
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));
|
||||
|
||||
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);
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
|
@ -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
|
||||
|
@ -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`
|
||||
|
Loading…
Reference in New Issue
Block a user