Skip to content

Commit 57bc996

Browse files
committed
Prototype VaList proposal
1 parent 48aee7e commit 57bc996

File tree

24 files changed

+185
-214
lines changed

24 files changed

+185
-214
lines changed

compiler/rustc_abi/src/layout/ty.rs

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -182,6 +182,9 @@ pub trait TyAbiInterface<'a, C>: Sized + std::fmt::Debug {
182182
fn is_tuple(this: TyAndLayout<'a, Self>) -> bool;
183183
fn is_unit(this: TyAndLayout<'a, Self>) -> bool;
184184
fn is_transparent(this: TyAndLayout<'a, Self>) -> bool;
185+
/// Returns `true` if the type is always passed indirectly. Currently only
186+
/// used for `VaList`s.
187+
fn is_pass_indirectly(this: TyAndLayout<'a, Self>) -> bool;
185188
}
186189

187190
impl<'a, Ty> TyAndLayout<'a, Ty> {
@@ -279,6 +282,13 @@ impl<'a, Ty> TyAndLayout<'a, Ty> {
279282
Ty::is_transparent(self)
280283
}
281284

285+
pub fn is_pass_indirectly<C>(self) -> bool
286+
where
287+
Ty: TyAbiInterface<'a, C>,
288+
{
289+
Ty::is_pass_indirectly(self)
290+
}
291+
282292
/// Finds the one field that is not a 1-ZST.
283293
/// Returns `None` if there are multiple non-1-ZST fields or only 1-ZST-fields.
284294
pub fn non_1zst_field<C>(&self, cx: &C) -> Option<(FieldIdx, Self)>

compiler/rustc_abi/src/lib.rs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -93,6 +93,9 @@ bitflags! {
9393
// Other flags can still inhibit reordering and thus randomization.
9494
// The seed stored in `ReprOptions.field_shuffle_seed`.
9595
const RANDOMIZE_LAYOUT = 1 << 4;
96+
// If true, the type is always passed indirectly in C-like ABIs.
97+
// Currently only used for `VaList`s.
98+
const PASS_INDIRECTLY = 1 << 5;
9699
// Any of these flags being set prevent field reordering optimisation.
97100
const FIELD_ORDER_UNOPTIMIZABLE = ReprFlags::IS_C.bits()
98101
| ReprFlags::IS_SIMD.bits()

compiler/rustc_codegen_ssa/src/traits/intrinsic.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -30,10 +30,10 @@ pub trait IntrinsicCallBuilderMethods<'tcx>: BackendTypes {
3030
vtable_byte_offset: u64,
3131
typeid: Self::Metadata,
3232
) -> Self::Value;
33-
/// Trait method used to inject `va_start` on the "spoofed" `VaListImpl` in
33+
/// Trait method used to inject `va_start` on the "spoofed" `VaList` in
3434
/// Rust defined C-variadic functions.
3535
fn va_start(&mut self, val: Self::Value) -> Self::Value;
36-
/// Trait method used to inject `va_end` on the "spoofed" `VaListImpl` before
36+
/// Trait method used to inject `va_end` on the "spoofed" `VaList` before
3737
/// Rust defined C-variadic functions return.
3838
fn va_end(&mut self, val: Self::Value) -> Self::Value;
3939
}

compiler/rustc_middle/src/ty/layout.rs

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ use std::{cmp, fmt};
33

44
use rustc_abi::{
55
AddressSpace, Align, ExternAbi, FieldIdx, FieldsShape, HasDataLayout, LayoutData, PointeeInfo,
6-
PointerKind, Primitive, ReprOptions, Scalar, Size, TagEncoding, TargetDataLayout,
6+
PointerKind, Primitive, ReprFlags, ReprOptions, Scalar, Size, TagEncoding, TargetDataLayout,
77
TyAbiInterface, VariantIdx, Variants,
88
};
99
use rustc_error_messages::DiagMessage;
@@ -1138,6 +1138,10 @@ where
11381138
fn is_transparent(this: TyAndLayout<'tcx>) -> bool {
11391139
matches!(this.ty.kind(), ty::Adt(def, _) if def.repr().transparent())
11401140
}
1141+
1142+
fn is_pass_indirectly(this: TyAndLayout<'tcx>) -> bool {
1143+
matches!(this.ty.kind(), ty::Adt(def, _) if def.repr().flags.contains(ReprFlags::PASS_INDIRECTLY))
1144+
}
11411145
}
11421146

11431147
/// Calculates whether a function's ABI can unwind or not.

compiler/rustc_middle/src/ty/mod.rs

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1585,6 +1585,12 @@ impl<'tcx> TyCtxt<'tcx> {
15851585
flags.insert(ReprFlags::IS_LINEAR);
15861586
}
15871587

1588+
if self.is_lang_item(did.to_def_id(), LangItem::VaList)
1589+
&& !flags.contains(ReprFlags::IS_TRANSPARENT)
1590+
{
1591+
flags.insert(ReprFlags::PASS_INDIRECTLY);
1592+
}
1593+
15881594
ReprOptions { int: size, align: max_align, pack: min_pack, flags, field_shuffle_seed }
15891595
}
15901596

compiler/rustc_target/src/callconv/aarch64.rs

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -114,6 +114,12 @@ where
114114
// Not touching this...
115115
return;
116116
}
117+
// `is_pass_indirectly` is only `true` for `VaList`, which would be passed indirectly by the
118+
// logic below anyway, so this is just here to make it explicit that this case is handled.
119+
if arg.layout.is_pass_indirectly() {
120+
arg.make_indirect();
121+
return;
122+
}
117123
if !arg.layout.is_aggregate() {
118124
if kind == AbiKind::DarwinPCS {
119125
// On Darwin, when passing an i8/i16, it must be sign-extended to 32 bits,

compiler/rustc_target/src/callconv/powerpc.rs

Lines changed: 13 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
use rustc_abi::TyAbiInterface;
2+
13
use crate::callconv::{ArgAbi, FnAbi};
24
use crate::spec::HasTargetSpec;
35

@@ -9,7 +11,10 @@ fn classify_ret<Ty>(ret: &mut ArgAbi<'_, Ty>) {
911
}
1012
}
1113

12-
fn classify_arg<Ty>(cx: &impl HasTargetSpec, arg: &mut ArgAbi<'_, Ty>) {
14+
fn classify_arg<'a, Ty, C>(cx: &impl HasTargetSpec, arg: &mut ArgAbi<'a, Ty>)
15+
where
16+
Ty: TyAbiInterface<'a, C> + Copy,
17+
{
1318
if arg.is_ignore() {
1419
// powerpc-unknown-linux-{gnu,musl,uclibc} doesn't ignore ZSTs.
1520
if cx.target_spec().os == "linux"
@@ -20,14 +25,19 @@ fn classify_arg<Ty>(cx: &impl HasTargetSpec, arg: &mut ArgAbi<'_, Ty>) {
2025
}
2126
return;
2227
}
23-
if arg.layout.is_aggregate() {
28+
// `is_pass_indirectly` is only `true` for `VaList` which is already an aggregate, so the
29+
// `.is_pass_indirectly()` call is just to make it explicit that this case is handled.
30+
if arg.layout.is_aggregate() || arg.layout.is_pass_indirectly() {
2431
arg.make_indirect();
2532
} else {
2633
arg.extend_integer_width_to(32);
2734
}
2835
}
2936

30-
pub(crate) fn compute_abi_info<Ty>(cx: &impl HasTargetSpec, fn_abi: &mut FnAbi<'_, Ty>) {
37+
pub(crate) fn compute_abi_info<'a, Ty, C>(cx: &impl HasTargetSpec, fn_abi: &mut FnAbi<'a, Ty>)
38+
where
39+
Ty: TyAbiInterface<'a, C> + Copy,
40+
{
3141
if !fn_abi.ret.is_ignore() {
3242
classify_ret(&mut fn_abi.ret);
3343
}

compiler/rustc_target/src/callconv/s390x.rs

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,12 @@ where
3737
}
3838
return;
3939
}
40+
// `is_pass_indirectly` is only `true` for `VaList`, which would be passed indirectly by the
41+
// logic below anyway, so this is just here to make it explicit that this case is handled.
42+
if arg.layout.is_pass_indirectly() {
43+
arg.make_indirect();
44+
return;
45+
}
4046

4147
let size = arg.layout.size;
4248
if size.bits() <= 128 {

compiler/rustc_target/src/callconv/x86_64.rs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -186,6 +186,11 @@ where
186186
// Not touching this...
187187
return;
188188
}
189+
if is_arg && arg.layout.is_pass_indirectly() {
190+
int_regs = int_regs.saturating_sub(1);
191+
arg.make_indirect();
192+
return;
193+
}
189194
let mut cls_or_mem = classify_arg(cx, arg);
190195

191196
if is_arg {

compiler/rustc_target/src/callconv/x86_win64.rs

Lines changed: 13 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,14 @@
1-
use rustc_abi::{BackendRepr, Float, Integer, Primitive, RegKind, Size};
1+
use rustc_abi::{BackendRepr, Float, Integer, Primitive, RegKind, Size, TyAbiInterface};
22

33
use crate::callconv::{ArgAbi, FnAbi, Reg};
44
use crate::spec::{HasTargetSpec, RustcAbi};
55

66
// Win64 ABI: https://docs.microsoft.com/en-us/cpp/build/parameter-passing
77

8-
pub(crate) fn compute_abi_info<Ty>(cx: &impl HasTargetSpec, fn_abi: &mut FnAbi<'_, Ty>) {
8+
pub(crate) fn compute_abi_info<'a, Ty, C>(cx: &impl HasTargetSpec, fn_abi: &mut FnAbi<'a, Ty>)
9+
where
10+
Ty: TyAbiInterface<'a, C> + Copy,
11+
{
912
let fixup = |a: &mut ArgAbi<'_, Ty>, is_ret: bool| {
1013
match a.layout.backend_repr {
1114
BackendRepr::Memory { sized: false } => {}
@@ -59,6 +62,14 @@ pub(crate) fn compute_abi_info<Ty>(cx: &impl HasTargetSpec, fn_abi: &mut FnAbi<'
5962
arg.make_indirect_from_ignore();
6063
continue;
6164
}
65+
// The `win64` ABI can be used on non-Windows targets which set `PASS_INDIRECTLY` on
66+
// `VaList`, so that case is handled here. `is_pass_indirectly` is only `true` for the
67+
// System V `VaList`, which would be passed indirectly by `fixup` anyway, so this is just
68+
// here to make it explicit that this case is handled.
69+
if arg.layout.is_pass_indirectly() {
70+
arg.make_indirect();
71+
continue;
72+
}
6273
fixup(arg, false);
6374
}
6475
// FIXME: We should likely also do something about ZST return types, similar to above.

0 commit comments

Comments
 (0)