rustc_trans: nest abi::ArgType's for fat pointers instead of eagerly flattening.
This commit is contained in:
parent
f2e7e17d9e
commit
88f70323e4
4 changed files with 161 additions and 137 deletions
|
@ -420,7 +420,7 @@ impl CastTarget {
|
|||
/// should be passed to or returned from a function
|
||||
///
|
||||
/// This is borrowed from clang's ABIInfo.h
|
||||
#[derive(Clone, Copy, Debug)]
|
||||
#[derive(Debug)]
|
||||
pub struct ArgType<'tcx> {
|
||||
kind: ArgKind,
|
||||
pub layout: FullLayout<'tcx>,
|
||||
|
@ -429,7 +429,8 @@ pub struct ArgType<'tcx> {
|
|||
/// Dummy argument, which is emitted before the real argument.
|
||||
pub pad: Option<Reg>,
|
||||
/// Attributes of argument.
|
||||
pub attrs: ArgAttributes
|
||||
pub attrs: ArgAttributes,
|
||||
pub nested: Vec<ArgType<'tcx>>
|
||||
}
|
||||
|
||||
impl<'a, 'tcx> ArgType<'tcx> {
|
||||
|
@ -439,11 +440,13 @@ impl<'a, 'tcx> ArgType<'tcx> {
|
|||
layout,
|
||||
cast: None,
|
||||
pad: None,
|
||||
attrs: ArgAttributes::default()
|
||||
attrs: ArgAttributes::default(),
|
||||
nested: vec![]
|
||||
}
|
||||
}
|
||||
|
||||
pub fn make_indirect(&mut self, ccx: &CrateContext<'a, 'tcx>) {
|
||||
assert!(self.nested.is_empty());
|
||||
assert_eq!(self.kind, ArgKind::Direct);
|
||||
|
||||
// Wipe old attributes, likely not valid through indirection.
|
||||
|
@ -460,6 +463,7 @@ impl<'a, 'tcx> ArgType<'tcx> {
|
|||
}
|
||||
|
||||
pub fn ignore(&mut self) {
|
||||
assert!(self.nested.is_empty());
|
||||
assert_eq!(self.kind, ArgKind::Direct);
|
||||
self.kind = ArgKind::Ignore;
|
||||
}
|
||||
|
@ -482,10 +486,12 @@ impl<'a, 'tcx> ArgType<'tcx> {
|
|||
}
|
||||
|
||||
pub fn cast_to<T: Into<CastTarget>>(&mut self, target: T) {
|
||||
assert!(self.nested.is_empty());
|
||||
self.cast = Some(target.into());
|
||||
}
|
||||
|
||||
pub fn pad_with(&mut self, reg: Reg) {
|
||||
assert!(self.nested.is_empty());
|
||||
self.pad = Some(reg);
|
||||
}
|
||||
|
||||
|
@ -561,6 +567,12 @@ impl<'a, 'tcx> ArgType<'tcx> {
|
|||
}
|
||||
|
||||
pub fn store_fn_arg(&self, bcx: &Builder<'a, 'tcx>, idx: &mut usize, dst: LvalueRef<'tcx>) {
|
||||
if !self.nested.is_empty() {
|
||||
for (i, arg) in self.nested.iter().enumerate() {
|
||||
arg.store_fn_arg(bcx, idx, dst.project_field(bcx, i));
|
||||
}
|
||||
return;
|
||||
}
|
||||
if self.pad.is_some() {
|
||||
*idx += 1;
|
||||
}
|
||||
|
@ -578,7 +590,7 @@ impl<'a, 'tcx> ArgType<'tcx> {
|
|||
///
|
||||
/// I will do my best to describe this structure, but these
|
||||
/// comments are reverse-engineered and may be inaccurate. -NDM
|
||||
#[derive(Clone, Debug)]
|
||||
#[derive(Debug)]
|
||||
pub struct FnType<'tcx> {
|
||||
/// The LLVM types of each argument.
|
||||
pub args: Vec<ArgType<'tcx>>,
|
||||
|
@ -613,7 +625,8 @@ impl<'a, 'tcx> FnType<'tcx> {
|
|||
extra_args: &[Ty<'tcx>]) -> FnType<'tcx> {
|
||||
let mut fn_ty = FnType::unadjusted(ccx, sig, extra_args);
|
||||
// Don't pass the vtable, it's not an argument of the virtual fn.
|
||||
fn_ty.args[1].ignore();
|
||||
assert_eq!(fn_ty.args[0].nested.len(), 2);
|
||||
fn_ty.args[0].nested[1].ignore();
|
||||
fn_ty.adjust_for_abi(ccx, sig);
|
||||
fn_ty
|
||||
}
|
||||
|
@ -766,7 +779,7 @@ impl<'a, 'tcx> FnType<'tcx> {
|
|||
for ty in inputs.iter().chain(extra_args.iter()) {
|
||||
let mut arg = arg_of(ty, false);
|
||||
|
||||
if let ty::layout::Layout::FatPointer { .. } = *arg.layout.layout {
|
||||
if type_is_fat_ptr(ccx, ty) {
|
||||
let mut data = ArgType::new(arg.layout.field(ccx, 0));
|
||||
let mut info = ArgType::new(arg.layout.field(ccx, 1));
|
||||
|
||||
|
@ -780,14 +793,16 @@ impl<'a, 'tcx> FnType<'tcx> {
|
|||
info.attrs.set(ArgAttribute::NoAlias);
|
||||
}
|
||||
}
|
||||
args.push(data);
|
||||
args.push(info);
|
||||
// FIXME(eddyb) other ABIs don't have logic for nested.
|
||||
if rust_abi {
|
||||
arg.nested = vec![data, info];
|
||||
}
|
||||
} else {
|
||||
if let Some(inner) = rust_ptr_attrs(ty, &mut arg) {
|
||||
arg.attrs.set_dereferenceable(ccx.size_of(inner));
|
||||
}
|
||||
args.push(arg);
|
||||
}
|
||||
args.push(arg);
|
||||
}
|
||||
|
||||
FnType {
|
||||
|
@ -854,6 +869,13 @@ impl<'a, 'tcx> FnType<'tcx> {
|
|||
}
|
||||
for arg in &mut self.args {
|
||||
if arg.is_ignore() { continue; }
|
||||
if !arg.nested.is_empty() {
|
||||
for arg in &mut arg.nested {
|
||||
assert!(arg.nested.is_empty());
|
||||
fixup(arg);
|
||||
}
|
||||
continue;
|
||||
}
|
||||
fixup(arg);
|
||||
}
|
||||
if self.ret.is_indirect() {
|
||||
|
@ -915,24 +937,36 @@ impl<'a, 'tcx> FnType<'tcx> {
|
|||
ccx.immediate_llvm_type_of(self.ret.layout.ty)
|
||||
};
|
||||
|
||||
for arg in &self.args {
|
||||
if arg.is_ignore() {
|
||||
continue;
|
||||
}
|
||||
// add padding
|
||||
if let Some(ty) = arg.pad {
|
||||
llargument_tys.push(ty.llvm_type(ccx));
|
||||
}
|
||||
{
|
||||
let mut push = |arg: &ArgType<'tcx>| {
|
||||
if arg.is_ignore() {
|
||||
return;
|
||||
}
|
||||
// add padding
|
||||
if let Some(ty) = arg.pad {
|
||||
llargument_tys.push(ty.llvm_type(ccx));
|
||||
}
|
||||
|
||||
let llarg_ty = if arg.is_indirect() {
|
||||
arg.memory_ty(ccx).ptr_to()
|
||||
} else if let Some(cast) = arg.cast {
|
||||
cast.llvm_type(ccx)
|
||||
} else {
|
||||
ccx.immediate_llvm_type_of(arg.layout.ty)
|
||||
let llarg_ty = if arg.is_indirect() {
|
||||
arg.memory_ty(ccx).ptr_to()
|
||||
} else if let Some(cast) = arg.cast {
|
||||
cast.llvm_type(ccx)
|
||||
} else {
|
||||
ccx.immediate_llvm_type_of(arg.layout.ty)
|
||||
};
|
||||
|
||||
llargument_tys.push(llarg_ty);
|
||||
};
|
||||
|
||||
llargument_tys.push(llarg_ty);
|
||||
for arg in &self.args {
|
||||
if !arg.nested.is_empty() {
|
||||
for arg in &arg.nested {
|
||||
assert!(arg.nested.is_empty());
|
||||
push(arg);
|
||||
}
|
||||
continue;
|
||||
}
|
||||
push(arg);
|
||||
}
|
||||
}
|
||||
|
||||
if self.variadic {
|
||||
|
@ -948,12 +982,22 @@ impl<'a, 'tcx> FnType<'tcx> {
|
|||
self.ret.attrs.apply_llfn(llvm::AttributePlace::Argument(i), llfn);
|
||||
}
|
||||
i += 1;
|
||||
for arg in &self.args {
|
||||
let mut apply = |arg: &ArgType| {
|
||||
if !arg.is_ignore() {
|
||||
if arg.pad.is_some() { i += 1; }
|
||||
arg.attrs.apply_llfn(llvm::AttributePlace::Argument(i), llfn);
|
||||
i += 1;
|
||||
}
|
||||
};
|
||||
for arg in &self.args {
|
||||
if !arg.nested.is_empty() {
|
||||
for arg in &arg.nested {
|
||||
assert!(arg.nested.is_empty());
|
||||
apply(arg);
|
||||
}
|
||||
continue;
|
||||
}
|
||||
apply(arg);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -963,12 +1007,22 @@ impl<'a, 'tcx> FnType<'tcx> {
|
|||
self.ret.attrs.apply_callsite(llvm::AttributePlace::Argument(i), callsite);
|
||||
}
|
||||
i += 1;
|
||||
for arg in &self.args {
|
||||
let mut apply = |arg: &ArgType| {
|
||||
if !arg.is_ignore() {
|
||||
if arg.pad.is_some() { i += 1; }
|
||||
arg.attrs.apply_callsite(llvm::AttributePlace::Argument(i), callsite);
|
||||
i += 1;
|
||||
}
|
||||
};
|
||||
for arg in &self.args {
|
||||
if !arg.nested.is_empty() {
|
||||
for arg in &arg.nested {
|
||||
assert!(arg.nested.is_empty());
|
||||
apply(arg);
|
||||
}
|
||||
continue;
|
||||
}
|
||||
apply(arg);
|
||||
}
|
||||
|
||||
if self.cconv != llvm::CCallConv {
|
||||
|
|
|
@ -27,7 +27,7 @@ use type_::Type;
|
|||
use value::Value;
|
||||
use rustc::traits;
|
||||
use rustc::ty::{self, Ty, TyCtxt};
|
||||
use rustc::ty::layout::{self, HasDataLayout, Layout, LayoutOf};
|
||||
use rustc::ty::layout::{self, HasDataLayout, LayoutOf};
|
||||
use rustc::ty::subst::{Kind, Subst, Substs};
|
||||
use rustc::hir;
|
||||
|
||||
|
@ -41,10 +41,15 @@ use syntax_pos::{Span, DUMMY_SP};
|
|||
pub use context::{CrateContext, SharedCrateContext};
|
||||
|
||||
pub fn type_is_fat_ptr<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, ty: Ty<'tcx>) -> bool {
|
||||
if let Layout::FatPointer { .. } = *ccx.layout_of(ty).layout {
|
||||
true
|
||||
} else {
|
||||
false
|
||||
match ty.sty {
|
||||
ty::TyRef(_, ty::TypeAndMut { ty, .. }) |
|
||||
ty::TyRawPtr(ty::TypeAndMut { ty, .. }) => {
|
||||
!ccx.shared().type_is_sized(ty)
|
||||
}
|
||||
ty::TyAdt(def, _) if def.is_box() => {
|
||||
!ccx.shared().type_is_sized(ty.boxed_ty())
|
||||
}
|
||||
_ => false
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -63,9 +68,8 @@ pub fn type_is_immediate<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, ty: Ty<'tcx>) -
|
|||
pub fn type_is_imm_pair<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, ty: Ty<'tcx>)
|
||||
-> bool {
|
||||
let layout = ccx.layout_of(ty);
|
||||
match *layout.layout {
|
||||
Layout::FatPointer => true,
|
||||
Layout::Univariant => {
|
||||
match *layout.fields {
|
||||
layout::FieldPlacement::Arbitrary { .. } => {
|
||||
// There must be only 2 fields.
|
||||
if layout.fields.count() != 2 {
|
||||
return false;
|
||||
|
|
|
@ -215,13 +215,12 @@ impl<'a, 'tcx> MirContext<'a, 'tcx> {
|
|||
}
|
||||
|
||||
mir::TerminatorKind::Return => {
|
||||
let ret = self.fn_ty.ret;
|
||||
if ret.is_ignore() || ret.is_indirect() {
|
||||
if self.fn_ty.ret.is_ignore() || self.fn_ty.ret.is_indirect() {
|
||||
bcx.ret_void();
|
||||
return;
|
||||
}
|
||||
|
||||
let llval = if let Some(cast_ty) = ret.cast {
|
||||
let llval = if let Some(cast_ty) = self.fn_ty.ret.cast {
|
||||
let op = match self.locals[mir::RETURN_POINTER] {
|
||||
LocalRef::Operand(Some(op)) => op,
|
||||
LocalRef::Operand(None) => bug!("use of return before def"),
|
||||
|
@ -234,7 +233,7 @@ impl<'a, 'tcx> MirContext<'a, 'tcx> {
|
|||
};
|
||||
let llslot = match op.val {
|
||||
Immediate(_) | Pair(..) => {
|
||||
let scratch = LvalueRef::alloca(&bcx, ret.layout.ty, "ret");
|
||||
let scratch = LvalueRef::alloca(&bcx, self.fn_ty.ret.layout.ty, "ret");
|
||||
op.store(&bcx, scratch);
|
||||
scratch.llval
|
||||
}
|
||||
|
@ -246,7 +245,7 @@ impl<'a, 'tcx> MirContext<'a, 'tcx> {
|
|||
};
|
||||
let load = bcx.load(
|
||||
bcx.pointercast(llslot, cast_ty.llvm_type(bcx.ccx).ptr_to()),
|
||||
Some(ret.layout.align(bcx.ccx)));
|
||||
Some(self.fn_ty.ret.layout.align(bcx.ccx)));
|
||||
load
|
||||
} else {
|
||||
let op = self.trans_consume(&bcx, &mir::Lvalue::Local(mir::RETURN_POINTER));
|
||||
|
@ -562,9 +561,18 @@ impl<'a, 'tcx> MirContext<'a, 'tcx> {
|
|||
(&args[..], None)
|
||||
};
|
||||
|
||||
let mut idx = 0;
|
||||
for arg in first_args {
|
||||
for (idx, arg) in first_args.iter().enumerate() {
|
||||
let mut op = self.trans_operand(&bcx, arg);
|
||||
if idx == 0 {
|
||||
if let Pair(_, meta) = op.val {
|
||||
if let Some(ty::InstanceDef::Virtual(_, idx)) = def {
|
||||
let llmeth = meth::VirtualIndex::from_index(idx)
|
||||
.get_fn(&bcx, meta);
|
||||
let llty = fn_ty.llvm_type(bcx.ccx).ptr_to();
|
||||
llfn = Some(bcx.pointercast(llmeth, llty));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// The callee needs to own the argument memory if we pass it
|
||||
// by-ref, so make a local copy of non-immediate constants.
|
||||
|
@ -574,12 +582,11 @@ impl<'a, 'tcx> MirContext<'a, 'tcx> {
|
|||
op.val = Ref(tmp.llval, tmp.alignment);
|
||||
}
|
||||
|
||||
self.trans_argument(&bcx, op, &mut llargs, &fn_ty,
|
||||
&mut idx, &mut llfn, &def);
|
||||
self.trans_argument(&bcx, op, &mut llargs, &fn_ty.args[idx]);
|
||||
}
|
||||
if let Some(tup) = untuple {
|
||||
self.trans_arguments_untupled(&bcx, tup, &mut llargs, &fn_ty,
|
||||
&mut idx, &mut llfn, &def)
|
||||
self.trans_arguments_untupled(&bcx, tup, &mut llargs,
|
||||
&fn_ty.args[first_args.len()..])
|
||||
}
|
||||
|
||||
let fn_ptr = match (llfn, instance) {
|
||||
|
@ -602,36 +609,22 @@ impl<'a, 'tcx> MirContext<'a, 'tcx> {
|
|||
bcx: &Builder<'a, 'tcx>,
|
||||
op: OperandRef<'tcx>,
|
||||
llargs: &mut Vec<ValueRef>,
|
||||
fn_ty: &FnType<'tcx>,
|
||||
next_idx: &mut usize,
|
||||
llfn: &mut Option<ValueRef>,
|
||||
def: &Option<ty::InstanceDef<'tcx>>) {
|
||||
arg: &ArgType<'tcx>) {
|
||||
if let Pair(a, b) = op.val {
|
||||
// Treat the values in a fat pointer separately.
|
||||
if common::type_is_fat_ptr(bcx.ccx, op.ty) {
|
||||
let (ptr, meta) = (a, b);
|
||||
if *next_idx == 0 {
|
||||
if let Some(ty::InstanceDef::Virtual(_, idx)) = *def {
|
||||
let llmeth = meth::VirtualIndex::from_index(idx).get_fn(bcx, meta);
|
||||
let llty = fn_ty.llvm_type(bcx.ccx).ptr_to();
|
||||
*llfn = Some(bcx.pointercast(llmeth, llty));
|
||||
}
|
||||
}
|
||||
|
||||
if !arg.nested.is_empty() {
|
||||
assert_eq!(arg.nested.len(), 2);
|
||||
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, llfn, def);
|
||||
self.trans_argument(bcx, imm_op(meta), llargs, fn_ty, next_idx, llfn, def);
|
||||
self.trans_argument(bcx, imm_op(a), llargs, &arg.nested[0]);
|
||||
self.trans_argument(bcx, imm_op(b), llargs, &arg.nested[1]);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
let arg = &fn_ty.args[*next_idx];
|
||||
*next_idx += 1;
|
||||
|
||||
// Fill padding with undef value, where applicable.
|
||||
if let Some(ty) = arg.pad {
|
||||
llargs.push(C_undef(ty.llvm_type(bcx.ccx)));
|
||||
|
@ -686,10 +679,7 @@ impl<'a, 'tcx> MirContext<'a, 'tcx> {
|
|||
bcx: &Builder<'a, 'tcx>,
|
||||
operand: &mir::Operand<'tcx>,
|
||||
llargs: &mut Vec<ValueRef>,
|
||||
fn_ty: &FnType<'tcx>,
|
||||
next_idx: &mut usize,
|
||||
llfn: &mut Option<ValueRef>,
|
||||
def: &Option<ty::InstanceDef<'tcx>>) {
|
||||
args: &[ArgType<'tcx>]) {
|
||||
let tuple = self.trans_operand(bcx, operand);
|
||||
|
||||
let arg_types = match tuple.ty.sty {
|
||||
|
@ -702,18 +692,9 @@ impl<'a, 'tcx> MirContext<'a, 'tcx> {
|
|||
match tuple.val {
|
||||
Ref(llval, align) => {
|
||||
let tuple_ptr = LvalueRef::new_sized(llval, tuple.ty, align);
|
||||
for (n, &ty) in arg_types.iter().enumerate() {
|
||||
for n in 0..arg_types.len() {
|
||||
let field_ptr = tuple_ptr.project_field(bcx, n);
|
||||
let op = if common::type_is_fat_ptr(bcx.ccx, ty) {
|
||||
field_ptr.load(bcx)
|
||||
} else {
|
||||
// trans_argument will load this if it needs to
|
||||
OperandRef {
|
||||
val: Ref(field_ptr.llval, field_ptr.alignment),
|
||||
ty
|
||||
}
|
||||
};
|
||||
self.trans_argument(bcx, op, llargs, fn_ty, next_idx, llfn, def);
|
||||
self.trans_argument(bcx, field_ptr.load(bcx), llargs, &args[n]);
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -728,7 +709,7 @@ impl<'a, 'tcx> MirContext<'a, 'tcx> {
|
|||
val: Immediate(elem),
|
||||
ty,
|
||||
};
|
||||
self.trans_argument(bcx, op, llargs, fn_ty, next_idx, llfn, def);
|
||||
self.trans_argument(bcx, op, llargs, &args[n]);
|
||||
}
|
||||
}
|
||||
Pair(a, b) => {
|
||||
|
@ -740,7 +721,7 @@ impl<'a, 'tcx> MirContext<'a, 'tcx> {
|
|||
val: Immediate(elem),
|
||||
ty,
|
||||
};
|
||||
self.trans_argument(bcx, op, llargs, fn_ty, next_idx, llfn, def);
|
||||
self.trans_argument(bcx, op, llargs, &args[n]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -22,7 +22,7 @@ use builder::Builder;
|
|||
use common::{self, CrateContext, Funclet};
|
||||
use debuginfo::{self, declare_local, VariableAccess, VariableKind, FunctionDebugContext};
|
||||
use monomorphize::Instance;
|
||||
use abi::{self, ArgAttribute, FnType};
|
||||
use abi::{ArgAttribute, FnType};
|
||||
use type_of;
|
||||
|
||||
use syntax_pos::{DUMMY_SP, NO_EXPANSION, BytePos, Span};
|
||||
|
@ -401,22 +401,10 @@ fn arg_local_refs<'a, 'tcx>(bcx: &Builder<'a, 'tcx>,
|
|||
};
|
||||
|
||||
let lvalue = LvalueRef::alloca(bcx, arg_ty, &name);
|
||||
for (i, &tupled_arg_ty) in tupled_arg_tys.iter().enumerate() {
|
||||
let dst = lvalue.project_field(bcx, i);
|
||||
for i in 0..tupled_arg_tys.len() {
|
||||
let arg = &mircx.fn_ty.args[idx];
|
||||
idx += 1;
|
||||
if common::type_is_fat_ptr(bcx.ccx, tupled_arg_ty) {
|
||||
// We pass fat pointers as two words, but inside the tuple
|
||||
// they are the two sub-fields of a single aggregate field.
|
||||
let meta = &mircx.fn_ty.args[idx];
|
||||
idx += 1;
|
||||
arg.store_fn_arg(bcx, &mut llarg_idx,
|
||||
dst.project_field(bcx, abi::FAT_PTR_ADDR));
|
||||
meta.store_fn_arg(bcx, &mut llarg_idx,
|
||||
dst.project_field(bcx, abi::FAT_PTR_EXTRA));
|
||||
} else {
|
||||
arg.store_fn_arg(bcx, &mut llarg_idx, dst);
|
||||
}
|
||||
arg.store_fn_arg(bcx, &mut llarg_idx, lvalue.project_field(bcx, i));
|
||||
}
|
||||
|
||||
// Now that we have one alloca that contains the aggregate value,
|
||||
|
@ -453,26 +441,19 @@ fn arg_local_refs<'a, 'tcx>(bcx: &Builder<'a, 'tcx>,
|
|||
llarg_idx += 1;
|
||||
LvalueRef::new_sized(llarg, arg_ty, Alignment::AbiAligned)
|
||||
} else if !lvalue_locals.contains(local.index()) &&
|
||||
arg.cast.is_none() && arg_scope.is_none() {
|
||||
if arg.is_ignore() {
|
||||
return LocalRef::new_operand(bcx.ccx, arg_ty);
|
||||
}
|
||||
!arg.nested.is_empty() {
|
||||
assert_eq!(arg.nested.len(), 2);
|
||||
let (a, b) = (&arg.nested[0], &arg.nested[1]);
|
||||
assert!(!a.is_ignore() && a.cast.is_none() && a.pad.is_none());
|
||||
assert!(!b.is_ignore() && b.cast.is_none() && b.pad.is_none());
|
||||
|
||||
// We don't have to cast or keep the argument in the alloca.
|
||||
// FIXME(eddyb): We should figure out how to use llvm.dbg.value instead
|
||||
// of putting everything in allocas just so we can use llvm.dbg.declare.
|
||||
if arg.pad.is_some() {
|
||||
llarg_idx += 1;
|
||||
}
|
||||
let llarg = llvm::get_param(bcx.llfn(), llarg_idx as c_uint);
|
||||
let mut a = llvm::get_param(bcx.llfn(), llarg_idx as c_uint);
|
||||
llarg_idx += 1;
|
||||
let val = if common::type_is_fat_ptr(bcx.ccx, arg_ty) {
|
||||
let meta = &mircx.fn_ty.args[idx];
|
||||
idx += 1;
|
||||
assert!(meta.cast.is_none() && meta.pad.is_none());
|
||||
let llmeta = llvm::get_param(bcx.llfn(), llarg_idx as c_uint);
|
||||
llarg_idx += 1;
|
||||
|
||||
let mut b = llvm::get_param(bcx.llfn(), llarg_idx as c_uint);
|
||||
llarg_idx += 1;
|
||||
|
||||
if common::type_is_fat_ptr(bcx.ccx, arg_ty) {
|
||||
// FIXME(eddyb) As we can't perfectly represent the data and/or
|
||||
// vtable pointer in a fat pointers in Rust's typesystem, and
|
||||
// because we split fat pointers into two ArgType's, they're
|
||||
|
@ -486,36 +467,40 @@ fn arg_local_refs<'a, 'tcx>(bcx: &Builder<'a, 'tcx>,
|
|||
let data_llty = bcx.ccx.llvm_type_of(pointee);
|
||||
let meta_llty = type_of::unsized_info_ty(bcx.ccx, pointee);
|
||||
|
||||
let llarg = bcx.pointercast(llarg, data_llty.ptr_to());
|
||||
bcx.set_value_name(llarg, &(name.clone() + ".ptr"));
|
||||
let llmeta = bcx.pointercast(llmeta, meta_llty);
|
||||
bcx.set_value_name(llmeta, &(name + ".meta"));
|
||||
a = bcx.pointercast(a, data_llty.ptr_to());
|
||||
bcx.set_value_name(a, &(name.clone() + ".ptr"));
|
||||
b = bcx.pointercast(b, meta_llty);
|
||||
bcx.set_value_name(b, &(name + ".meta"));
|
||||
}
|
||||
|
||||
OperandValue::Pair(llarg, llmeta)
|
||||
} else {
|
||||
bcx.set_value_name(llarg, &name);
|
||||
OperandValue::Immediate(llarg)
|
||||
};
|
||||
return LocalRef::Operand(Some(OperandRef {
|
||||
val: OperandValue::Pair(a, b),
|
||||
ty: arg_ty
|
||||
}));
|
||||
} else if !lvalue_locals.contains(local.index()) &&
|
||||
!arg.is_indirect() && arg.cast.is_none() &&
|
||||
arg_scope.is_none() {
|
||||
if arg.is_ignore() {
|
||||
return LocalRef::new_operand(bcx.ccx, arg_ty);
|
||||
}
|
||||
|
||||
// We don't have to cast or keep the argument in the alloca.
|
||||
// FIXME(eddyb): We should figure out how to use llvm.dbg.value instead
|
||||
// of putting everything in allocas just so we can use llvm.dbg.declare.
|
||||
if arg.pad.is_some() {
|
||||
llarg_idx += 1;
|
||||
}
|
||||
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,
|
||||
val: OperandValue::Immediate(llarg),
|
||||
ty: arg_ty
|
||||
};
|
||||
return LocalRef::Operand(Some(operand.unpack_if_pair(bcx)));
|
||||
} else {
|
||||
let tmp = LvalueRef::alloca(bcx, arg_ty, &name);
|
||||
if common::type_is_fat_ptr(bcx.ccx, arg_ty) {
|
||||
// we pass fat pointers as two words, but we want to
|
||||
// represent them internally as a pointer to two words,
|
||||
// so make an alloca to store them in.
|
||||
let meta = &mircx.fn_ty.args[idx];
|
||||
idx += 1;
|
||||
arg.store_fn_arg(bcx, &mut llarg_idx, tmp.project_field(bcx, abi::FAT_PTR_ADDR));
|
||||
meta.store_fn_arg(bcx, &mut llarg_idx, tmp.project_field(bcx, abi::FAT_PTR_EXTRA));
|
||||
} else {
|
||||
// otherwise, arg is passed by value, so make a
|
||||
// temporary and store it there
|
||||
arg.store_fn_arg(bcx, &mut llarg_idx, tmp);
|
||||
}
|
||||
arg.store_fn_arg(bcx, &mut llarg_idx, tmp);
|
||||
tmp
|
||||
};
|
||||
arg_scope.map(|scope| {
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue