Skip to content

Commit 88f7032

Browse files
committed
rustc_trans: nest abi::ArgType's for fat pointers instead of eagerly flattening.
1 parent f2e7e17 commit 88f7032

File tree

4 files changed

+161
-137
lines changed

4 files changed

+161
-137
lines changed

src/librustc_trans/abi.rs

Lines changed: 81 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -420,7 +420,7 @@ impl CastTarget {
420420
/// should be passed to or returned from a function
421421
///
422422
/// This is borrowed from clang's ABIInfo.h
423-
#[derive(Clone, Copy, Debug)]
423+
#[derive(Debug)]
424424
pub struct ArgType<'tcx> {
425425
kind: ArgKind,
426426
pub layout: FullLayout<'tcx>,
@@ -429,7 +429,8 @@ pub struct ArgType<'tcx> {
429429
/// Dummy argument, which is emitted before the real argument.
430430
pub pad: Option<Reg>,
431431
/// Attributes of argument.
432-
pub attrs: ArgAttributes
432+
pub attrs: ArgAttributes,
433+
pub nested: Vec<ArgType<'tcx>>
433434
}
434435

435436
impl<'a, 'tcx> ArgType<'tcx> {
@@ -439,11 +440,13 @@ impl<'a, 'tcx> ArgType<'tcx> {
439440
layout,
440441
cast: None,
441442
pad: None,
442-
attrs: ArgAttributes::default()
443+
attrs: ArgAttributes::default(),
444+
nested: vec![]
443445
}
444446
}
445447

446448
pub fn make_indirect(&mut self, ccx: &CrateContext<'a, 'tcx>) {
449+
assert!(self.nested.is_empty());
447450
assert_eq!(self.kind, ArgKind::Direct);
448451

449452
// Wipe old attributes, likely not valid through indirection.
@@ -460,6 +463,7 @@ impl<'a, 'tcx> ArgType<'tcx> {
460463
}
461464

462465
pub fn ignore(&mut self) {
466+
assert!(self.nested.is_empty());
463467
assert_eq!(self.kind, ArgKind::Direct);
464468
self.kind = ArgKind::Ignore;
465469
}
@@ -482,10 +486,12 @@ impl<'a, 'tcx> ArgType<'tcx> {
482486
}
483487

484488
pub fn cast_to<T: Into<CastTarget>>(&mut self, target: T) {
489+
assert!(self.nested.is_empty());
485490
self.cast = Some(target.into());
486491
}
487492

488493
pub fn pad_with(&mut self, reg: Reg) {
494+
assert!(self.nested.is_empty());
489495
self.pad = Some(reg);
490496
}
491497

@@ -561,6 +567,12 @@ impl<'a, 'tcx> ArgType<'tcx> {
561567
}
562568

563569
pub fn store_fn_arg(&self, bcx: &Builder<'a, 'tcx>, idx: &mut usize, dst: LvalueRef<'tcx>) {
570+
if !self.nested.is_empty() {
571+
for (i, arg) in self.nested.iter().enumerate() {
572+
arg.store_fn_arg(bcx, idx, dst.project_field(bcx, i));
573+
}
574+
return;
575+
}
564576
if self.pad.is_some() {
565577
*idx += 1;
566578
}
@@ -578,7 +590,7 @@ impl<'a, 'tcx> ArgType<'tcx> {
578590
///
579591
/// I will do my best to describe this structure, but these
580592
/// comments are reverse-engineered and may be inaccurate. -NDM
581-
#[derive(Clone, Debug)]
593+
#[derive(Debug)]
582594
pub struct FnType<'tcx> {
583595
/// The LLVM types of each argument.
584596
pub args: Vec<ArgType<'tcx>>,
@@ -613,7 +625,8 @@ impl<'a, 'tcx> FnType<'tcx> {
613625
extra_args: &[Ty<'tcx>]) -> FnType<'tcx> {
614626
let mut fn_ty = FnType::unadjusted(ccx, sig, extra_args);
615627
// Don't pass the vtable, it's not an argument of the virtual fn.
616-
fn_ty.args[1].ignore();
628+
assert_eq!(fn_ty.args[0].nested.len(), 2);
629+
fn_ty.args[0].nested[1].ignore();
617630
fn_ty.adjust_for_abi(ccx, sig);
618631
fn_ty
619632
}
@@ -766,7 +779,7 @@ impl<'a, 'tcx> FnType<'tcx> {
766779
for ty in inputs.iter().chain(extra_args.iter()) {
767780
let mut arg = arg_of(ty, false);
768781

769-
if let ty::layout::Layout::FatPointer { .. } = *arg.layout.layout {
782+
if type_is_fat_ptr(ccx, ty) {
770783
let mut data = ArgType::new(arg.layout.field(ccx, 0));
771784
let mut info = ArgType::new(arg.layout.field(ccx, 1));
772785

@@ -780,14 +793,16 @@ impl<'a, 'tcx> FnType<'tcx> {
780793
info.attrs.set(ArgAttribute::NoAlias);
781794
}
782795
}
783-
args.push(data);
784-
args.push(info);
796+
// FIXME(eddyb) other ABIs don't have logic for nested.
797+
if rust_abi {
798+
arg.nested = vec![data, info];
799+
}
785800
} else {
786801
if let Some(inner) = rust_ptr_attrs(ty, &mut arg) {
787802
arg.attrs.set_dereferenceable(ccx.size_of(inner));
788803
}
789-
args.push(arg);
790804
}
805+
args.push(arg);
791806
}
792807

793808
FnType {
@@ -854,6 +869,13 @@ impl<'a, 'tcx> FnType<'tcx> {
854869
}
855870
for arg in &mut self.args {
856871
if arg.is_ignore() { continue; }
872+
if !arg.nested.is_empty() {
873+
for arg in &mut arg.nested {
874+
assert!(arg.nested.is_empty());
875+
fixup(arg);
876+
}
877+
continue;
878+
}
857879
fixup(arg);
858880
}
859881
if self.ret.is_indirect() {
@@ -915,24 +937,36 @@ impl<'a, 'tcx> FnType<'tcx> {
915937
ccx.immediate_llvm_type_of(self.ret.layout.ty)
916938
};
917939

918-
for arg in &self.args {
919-
if arg.is_ignore() {
920-
continue;
921-
}
922-
// add padding
923-
if let Some(ty) = arg.pad {
924-
llargument_tys.push(ty.llvm_type(ccx));
925-
}
940+
{
941+
let mut push = |arg: &ArgType<'tcx>| {
942+
if arg.is_ignore() {
943+
return;
944+
}
945+
// add padding
946+
if let Some(ty) = arg.pad {
947+
llargument_tys.push(ty.llvm_type(ccx));
948+
}
926949

927-
let llarg_ty = if arg.is_indirect() {
928-
arg.memory_ty(ccx).ptr_to()
929-
} else if let Some(cast) = arg.cast {
930-
cast.llvm_type(ccx)
931-
} else {
932-
ccx.immediate_llvm_type_of(arg.layout.ty)
933-
};
950+
let llarg_ty = if arg.is_indirect() {
951+
arg.memory_ty(ccx).ptr_to()
952+
} else if let Some(cast) = arg.cast {
953+
cast.llvm_type(ccx)
954+
} else {
955+
ccx.immediate_llvm_type_of(arg.layout.ty)
956+
};
934957

935-
llargument_tys.push(llarg_ty);
958+
llargument_tys.push(llarg_ty);
959+
};
960+
for arg in &self.args {
961+
if !arg.nested.is_empty() {
962+
for arg in &arg.nested {
963+
assert!(arg.nested.is_empty());
964+
push(arg);
965+
}
966+
continue;
967+
}
968+
push(arg);
969+
}
936970
}
937971

938972
if self.variadic {
@@ -948,12 +982,22 @@ impl<'a, 'tcx> FnType<'tcx> {
948982
self.ret.attrs.apply_llfn(llvm::AttributePlace::Argument(i), llfn);
949983
}
950984
i += 1;
951-
for arg in &self.args {
985+
let mut apply = |arg: &ArgType| {
952986
if !arg.is_ignore() {
953987
if arg.pad.is_some() { i += 1; }
954988
arg.attrs.apply_llfn(llvm::AttributePlace::Argument(i), llfn);
955989
i += 1;
956990
}
991+
};
992+
for arg in &self.args {
993+
if !arg.nested.is_empty() {
994+
for arg in &arg.nested {
995+
assert!(arg.nested.is_empty());
996+
apply(arg);
997+
}
998+
continue;
999+
}
1000+
apply(arg);
9571001
}
9581002
}
9591003

@@ -963,12 +1007,22 @@ impl<'a, 'tcx> FnType<'tcx> {
9631007
self.ret.attrs.apply_callsite(llvm::AttributePlace::Argument(i), callsite);
9641008
}
9651009
i += 1;
966-
for arg in &self.args {
1010+
let mut apply = |arg: &ArgType| {
9671011
if !arg.is_ignore() {
9681012
if arg.pad.is_some() { i += 1; }
9691013
arg.attrs.apply_callsite(llvm::AttributePlace::Argument(i), callsite);
9701014
i += 1;
9711015
}
1016+
};
1017+
for arg in &self.args {
1018+
if !arg.nested.is_empty() {
1019+
for arg in &arg.nested {
1020+
assert!(arg.nested.is_empty());
1021+
apply(arg);
1022+
}
1023+
continue;
1024+
}
1025+
apply(arg);
9721026
}
9731027

9741028
if self.cconv != llvm::CCallConv {

src/librustc_trans/common.rs

Lines changed: 12 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@ use type_::Type;
2727
use value::Value;
2828
use rustc::traits;
2929
use rustc::ty::{self, Ty, TyCtxt};
30-
use rustc::ty::layout::{self, HasDataLayout, Layout, LayoutOf};
30+
use rustc::ty::layout::{self, HasDataLayout, LayoutOf};
3131
use rustc::ty::subst::{Kind, Subst, Substs};
3232
use rustc::hir;
3333

@@ -41,10 +41,15 @@ use syntax_pos::{Span, DUMMY_SP};
4141
pub use context::{CrateContext, SharedCrateContext};
4242

4343
pub fn type_is_fat_ptr<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, ty: Ty<'tcx>) -> bool {
44-
if let Layout::FatPointer { .. } = *ccx.layout_of(ty).layout {
45-
true
46-
} else {
47-
false
44+
match ty.sty {
45+
ty::TyRef(_, ty::TypeAndMut { ty, .. }) |
46+
ty::TyRawPtr(ty::TypeAndMut { ty, .. }) => {
47+
!ccx.shared().type_is_sized(ty)
48+
}
49+
ty::TyAdt(def, _) if def.is_box() => {
50+
!ccx.shared().type_is_sized(ty.boxed_ty())
51+
}
52+
_ => false
4853
}
4954
}
5055

@@ -63,9 +68,8 @@ pub fn type_is_immediate<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, ty: Ty<'tcx>) -
6368
pub fn type_is_imm_pair<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, ty: Ty<'tcx>)
6469
-> bool {
6570
let layout = ccx.layout_of(ty);
66-
match *layout.layout {
67-
Layout::FatPointer => true,
68-
Layout::Univariant => {
71+
match *layout.fields {
72+
layout::FieldPlacement::Arbitrary { .. } => {
6973
// There must be only 2 fields.
7074
if layout.fields.count() != 2 {
7175
return false;

0 commit comments

Comments
 (0)