Skip to content

Commit 446cbc9

Browse files
committed
Auto merge of #80594 - bjorn3:abi_refactor3, r=petrochenkov
Various ABI refactorings This includes changes to the rust abi and various refactorings that will hopefully make it easier to use the abi handling infrastructure of rustc in cg_clif. There are several refactorings that I haven't done. I am opening this draft PR to check that I haven't broken any non x86_64 architectures. r? `@ghost`
2 parents 26c2d1f + fa12fdb commit 446cbc9

File tree

4 files changed

+118
-95
lines changed

4 files changed

+118
-95
lines changed

Cargo.lock

-1
Original file line numberDiff line numberDiff line change
@@ -3551,7 +3551,6 @@ version = "0.0.0"
35513551
dependencies = [
35523552
"rustc_ast",
35533553
"rustc_span",
3554-
"rustc_target",
35553554
"tracing",
35563555
]
35573556

compiler/rustc_ast_pretty/Cargo.toml

-1
Original file line numberDiff line numberDiff line change
@@ -11,4 +11,3 @@ doctest = false
1111
tracing = "0.1"
1212
rustc_span = { path = "../rustc_span" }
1313
rustc_ast = { path = "../rustc_ast" }
14-
rustc_target = { path = "../rustc_target" }

compiler/rustc_middle/src/ty/layout.rs

+81-82
Original file line numberDiff line numberDiff line change
@@ -2514,7 +2514,7 @@ where
25142514
extra_args: &[Ty<'tcx>],
25152515
caller_location: Option<Ty<'tcx>>,
25162516
codegen_fn_attr_flags: CodegenFnAttrFlags,
2517-
mk_arg_type: impl Fn(Ty<'tcx>, Option<usize>) -> ArgAbi<'tcx, Ty<'tcx>>,
2517+
make_self_ptr_thin: bool,
25182518
) -> Self;
25192519
fn adjust_for_abi(&mut self, cx: &C, abi: SpecAbi);
25202520
}
@@ -2574,9 +2574,7 @@ where
25742574
// Assume that fn pointers may always unwind
25752575
let codegen_fn_attr_flags = CodegenFnAttrFlags::UNWIND;
25762576

2577-
call::FnAbi::new_internal(cx, sig, extra_args, None, codegen_fn_attr_flags, |ty, _| {
2578-
ArgAbi::new(cx.layout_of(ty))
2579-
})
2577+
call::FnAbi::new_internal(cx, sig, extra_args, None, codegen_fn_attr_flags, false)
25802578
}
25812579

25822580
fn of_instance(cx: &C, instance: ty::Instance<'tcx>, extra_args: &[Ty<'tcx>]) -> Self {
@@ -2590,55 +2588,14 @@ where
25902588

25912589
let attrs = cx.tcx().codegen_fn_attrs(instance.def_id()).flags;
25922590

2593-
call::FnAbi::new_internal(cx, sig, extra_args, caller_location, attrs, |ty, arg_idx| {
2594-
let mut layout = cx.layout_of(ty);
2595-
// Don't pass the vtable, it's not an argument of the virtual fn.
2596-
// Instead, pass just the data pointer, but give it the type `*const/mut dyn Trait`
2597-
// or `&/&mut dyn Trait` because this is special-cased elsewhere in codegen
2598-
if let (ty::InstanceDef::Virtual(..), Some(0)) = (&instance.def, arg_idx) {
2599-
let fat_pointer_ty = if layout.is_unsized() {
2600-
// unsized `self` is passed as a pointer to `self`
2601-
// FIXME (mikeyhew) change this to use &own if it is ever added to the language
2602-
cx.tcx().mk_mut_ptr(layout.ty)
2603-
} else {
2604-
match layout.abi {
2605-
Abi::ScalarPair(..) => (),
2606-
_ => bug!("receiver type has unsupported layout: {:?}", layout),
2607-
}
2608-
2609-
// In the case of Rc<Self>, we need to explicitly pass a *mut RcBox<Self>
2610-
// with a Scalar (not ScalarPair) ABI. This is a hack that is understood
2611-
// elsewhere in the compiler as a method on a `dyn Trait`.
2612-
// To get the type `*mut RcBox<Self>`, we just keep unwrapping newtypes until we
2613-
// get a built-in pointer type
2614-
let mut fat_pointer_layout = layout;
2615-
'descend_newtypes: while !fat_pointer_layout.ty.is_unsafe_ptr()
2616-
&& !fat_pointer_layout.ty.is_region_ptr()
2617-
{
2618-
for i in 0..fat_pointer_layout.fields.count() {
2619-
let field_layout = fat_pointer_layout.field(cx, i);
2620-
2621-
if !field_layout.is_zst() {
2622-
fat_pointer_layout = field_layout;
2623-
continue 'descend_newtypes;
2624-
}
2625-
}
2626-
2627-
bug!("receiver has no non-zero-sized fields {:?}", fat_pointer_layout);
2628-
}
2629-
2630-
fat_pointer_layout.ty
2631-
};
2632-
2633-
// we now have a type like `*mut RcBox<dyn Trait>`
2634-
// change its layout to that of `*mut ()`, a thin pointer, but keep the same type
2635-
// this is understood as a special case elsewhere in the compiler
2636-
let unit_pointer_ty = cx.tcx().mk_mut_ptr(cx.tcx().mk_unit());
2637-
layout = cx.layout_of(unit_pointer_ty);
2638-
layout.ty = fat_pointer_ty;
2639-
}
2640-
ArgAbi::new(layout)
2641-
})
2591+
call::FnAbi::new_internal(
2592+
cx,
2593+
sig,
2594+
extra_args,
2595+
caller_location,
2596+
attrs,
2597+
matches!(instance.def, ty::InstanceDef::Virtual(..)),
2598+
)
26422599
}
26432600

26442601
fn new_internal(
@@ -2647,7 +2604,7 @@ where
26472604
extra_args: &[Ty<'tcx>],
26482605
caller_location: Option<Ty<'tcx>>,
26492606
codegen_fn_attr_flags: CodegenFnAttrFlags,
2650-
mk_arg_type: impl Fn(Ty<'tcx>, Option<usize>) -> ArgAbi<'tcx, Ty<'tcx>>,
2607+
force_thin_self_ptr: bool,
26512608
) -> Self {
26522609
debug!("FnAbi::new_internal({:?}, {:?})", sig, extra_args);
26532610

@@ -2778,7 +2735,23 @@ where
27782735

27792736
let arg_of = |ty: Ty<'tcx>, arg_idx: Option<usize>| {
27802737
let is_return = arg_idx.is_none();
2781-
let mut arg = mk_arg_type(ty, arg_idx);
2738+
2739+
let layout = cx.layout_of(ty);
2740+
let layout = if force_thin_self_ptr && arg_idx == Some(0) {
2741+
// Don't pass the vtable, it's not an argument of the virtual fn.
2742+
// Instead, pass just the data pointer, but give it the type `*const/mut dyn Trait`
2743+
// or `&/&mut dyn Trait` because this is special-cased elsewhere in codegen
2744+
make_thin_self_ptr(cx, layout)
2745+
} else {
2746+
layout
2747+
};
2748+
2749+
let mut arg = ArgAbi::new(cx, layout, |layout, scalar, offset| {
2750+
let mut attrs = ArgAttributes::new();
2751+
adjust_for_rust_scalar(&mut attrs, scalar, *layout, offset, is_return);
2752+
attrs
2753+
});
2754+
27822755
if arg.layout.is_zst() {
27832756
// For some forsaken reason, x86_64-pc-windows-gnu
27842757
// doesn't ignore zero-sized struct arguments.
@@ -2794,30 +2767,6 @@ where
27942767
}
27952768
}
27962769

2797-
// FIXME(eddyb) other ABIs don't have logic for scalar pairs.
2798-
if !is_return && rust_abi {
2799-
if let Abi::ScalarPair(ref a, ref b) = arg.layout.abi {
2800-
let mut a_attrs = ArgAttributes::new();
2801-
let mut b_attrs = ArgAttributes::new();
2802-
adjust_for_rust_scalar(&mut a_attrs, a, arg.layout, Size::ZERO, false);
2803-
adjust_for_rust_scalar(
2804-
&mut b_attrs,
2805-
b,
2806-
arg.layout,
2807-
a.value.size(cx).align_to(b.value.align(cx).abi),
2808-
false,
2809-
);
2810-
arg.mode = PassMode::Pair(a_attrs, b_attrs);
2811-
return arg;
2812-
}
2813-
}
2814-
2815-
if let Abi::Scalar(ref scalar) = arg.layout.abi {
2816-
if let PassMode::Direct(ref mut attrs) = arg.mode {
2817-
adjust_for_rust_scalar(attrs, scalar, arg.layout, Size::ZERO, is_return);
2818-
}
2819-
}
2820-
28212770
arg
28222771
};
28232772

@@ -2894,9 +2843,10 @@ where
28942843
let max_by_val_size = Pointer.size(cx) * 2;
28952844
let size = arg.layout.size;
28962845

2897-
if arg.layout.is_unsized() || size > max_by_val_size {
2898-
arg.make_indirect();
2899-
} else {
2846+
let is_indirect_not_on_stack =
2847+
matches!(arg.mode, PassMode::Indirect { on_stack: false, .. });
2848+
assert!(is_indirect_not_on_stack, "{:?}", arg);
2849+
if !arg.layout.is_unsized() && size <= max_by_val_size {
29002850
// We want to pass small aggregates as immediates, but using
29012851
// a LLVM aggregate type for this leads to bad optimizations,
29022852
// so we pick an appropriately sized integer type instead.
@@ -2915,3 +2865,52 @@ where
29152865
}
29162866
}
29172867
}
2868+
2869+
fn make_thin_self_ptr<'tcx, C>(cx: &C, mut layout: TyAndLayout<'tcx>) -> TyAndLayout<'tcx>
2870+
where
2871+
C: LayoutOf<Ty = Ty<'tcx>, TyAndLayout = TyAndLayout<'tcx>>
2872+
+ HasTyCtxt<'tcx>
2873+
+ HasParamEnv<'tcx>,
2874+
{
2875+
let fat_pointer_ty = if layout.is_unsized() {
2876+
// unsized `self` is passed as a pointer to `self`
2877+
// FIXME (mikeyhew) change this to use &own if it is ever added to the language
2878+
cx.tcx().mk_mut_ptr(layout.ty)
2879+
} else {
2880+
match layout.abi {
2881+
Abi::ScalarPair(..) => (),
2882+
_ => bug!("receiver type has unsupported layout: {:?}", layout),
2883+
}
2884+
2885+
// In the case of Rc<Self>, we need to explicitly pass a *mut RcBox<Self>
2886+
// with a Scalar (not ScalarPair) ABI. This is a hack that is understood
2887+
// elsewhere in the compiler as a method on a `dyn Trait`.
2888+
// To get the type `*mut RcBox<Self>`, we just keep unwrapping newtypes until we
2889+
// get a built-in pointer type
2890+
let mut fat_pointer_layout = layout;
2891+
'descend_newtypes: while !fat_pointer_layout.ty.is_unsafe_ptr()
2892+
&& !fat_pointer_layout.ty.is_region_ptr()
2893+
{
2894+
for i in 0..fat_pointer_layout.fields.count() {
2895+
let field_layout = fat_pointer_layout.field(cx, i);
2896+
2897+
if !field_layout.is_zst() {
2898+
fat_pointer_layout = field_layout;
2899+
continue 'descend_newtypes;
2900+
}
2901+
}
2902+
2903+
bug!("receiver has no non-zero-sized fields {:?}", fat_pointer_layout);
2904+
}
2905+
2906+
fat_pointer_layout.ty
2907+
};
2908+
2909+
// we now have a type like `*mut RcBox<dyn Trait>`
2910+
// change its layout to that of `*mut ()`, a thin pointer, but keep the same type
2911+
// this is understood as a special case elsewhere in the compiler
2912+
let unit_pointer_ty = cx.tcx().mk_mut_ptr(cx.tcx().mk_unit());
2913+
layout = cx.layout_of(unit_pointer_ty);
2914+
layout.ty = fat_pointer_ty;
2915+
layout
2916+
}

compiler/rustc_target/src/abi/call/mod.rs

+37-11
Original file line numberDiff line numberDiff line change
@@ -27,10 +27,16 @@ mod x86_win64;
2727
#[derive(Clone, Copy, PartialEq, Eq, Debug)]
2828
pub enum PassMode {
2929
/// Ignore the argument.
30+
///
31+
/// The argument is either uninhabited or a ZST.
3032
Ignore,
3133
/// Pass the argument directly.
34+
///
35+
/// The argument has a layout abi of `Scalar` or `Vector`.
3236
Direct(ArgAttributes),
3337
/// Pass a pair's elements directly in two arguments.
38+
///
39+
/// The argument has a layout abi of `ScalarPair`.
3440
Pair(ArgAttributes, ArgAttributes),
3541
/// Pass the argument after casting it, to either
3642
/// a single uniform or a pair of registers.
@@ -434,28 +440,49 @@ pub struct ArgAbi<'a, Ty> {
434440
}
435441

436442
impl<'a, Ty> ArgAbi<'a, Ty> {
437-
pub fn new(layout: TyAndLayout<'a, Ty>) -> Self {
438-
ArgAbi { layout, pad: None, mode: PassMode::Direct(ArgAttributes::new()) }
443+
pub fn new(
444+
cx: &impl HasDataLayout,
445+
layout: TyAndLayout<'a, Ty>,
446+
scalar_attrs: impl Fn(&TyAndLayout<'a, Ty>, &abi::Scalar, Size) -> ArgAttributes,
447+
) -> Self {
448+
let mode = match &layout.abi {
449+
Abi::Uninhabited => PassMode::Ignore,
450+
Abi::Scalar(scalar) => PassMode::Direct(scalar_attrs(&layout, scalar, Size::ZERO)),
451+
Abi::ScalarPair(a, b) => PassMode::Pair(
452+
scalar_attrs(&layout, a, Size::ZERO),
453+
scalar_attrs(&layout, b, a.value.size(cx).align_to(b.value.align(cx).abi)),
454+
),
455+
Abi::Vector { .. } => PassMode::Direct(ArgAttributes::new()),
456+
Abi::Aggregate { .. } => Self::indirect_pass_mode(&layout),
457+
};
458+
ArgAbi { layout, pad: None, mode }
439459
}
440460

441-
pub fn make_indirect(&mut self) {
442-
assert_eq!(self.mode, PassMode::Direct(ArgAttributes::new()));
443-
444-
// Start with fresh attributes for the pointer.
461+
fn indirect_pass_mode(layout: &TyAndLayout<'a, Ty>) -> PassMode {
445462
let mut attrs = ArgAttributes::new();
446463

447464
// For non-immediate arguments the callee gets its own copy of
448465
// the value on the stack, so there are no aliases. It's also
449466
// program-invisible so can't possibly capture
450467
attrs.set(ArgAttribute::NoAlias).set(ArgAttribute::NoCapture).set(ArgAttribute::NonNull);
451-
attrs.pointee_size = self.layout.size;
468+
attrs.pointee_size = layout.size;
452469
// FIXME(eddyb) We should be doing this, but at least on
453470
// i686-pc-windows-msvc, it results in wrong stack offsets.
454-
// attrs.pointee_align = Some(self.layout.align.abi);
471+
// attrs.pointee_align = Some(layout.align.abi);
472+
473+
let extra_attrs = layout.is_unsized().then_some(ArgAttributes::new());
455474

456-
let extra_attrs = self.layout.is_unsized().then_some(ArgAttributes::new());
475+
PassMode::Indirect { attrs, extra_attrs, on_stack: false }
476+
}
477+
478+
pub fn make_indirect(&mut self) {
479+
match self.mode {
480+
PassMode::Direct(_) | PassMode::Pair(_, _) => {}
481+
PassMode::Indirect { attrs: _, extra_attrs: None, on_stack: false } => return,
482+
_ => panic!("Tried to make {:?} indirect", self.mode),
483+
}
457484

458-
self.mode = PassMode::Indirect { attrs, extra_attrs, on_stack: false };
485+
self.mode = Self::indirect_pass_mode(&self.layout);
459486
}
460487

461488
pub fn make_indirect_byval(&mut self) {
@@ -486,7 +513,6 @@ impl<'a, Ty> ArgAbi<'a, Ty> {
486513
}
487514

488515
pub fn cast_to<T: Into<CastTarget>>(&mut self, target: T) {
489-
assert_eq!(self.mode, PassMode::Direct(ArgAttributes::new()));
490516
self.mode = PassMode::Cast(target.into());
491517
}
492518

0 commit comments

Comments
 (0)