Skip to content

Commit e78a9f7

Browse files
committed
enable PassMode::Indirect { on_stack: true } tail call arguments
1 parent d2218f5 commit e78a9f7

4 files changed

Lines changed: 344 additions & 46 deletions

File tree

compiler/rustc_codegen_ssa/src/mir/block.rs

Lines changed: 28 additions & 46 deletions
Original file line numberDiff line numberDiff line change
@@ -1256,55 +1256,37 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
12561256
}
12571257
}
12581258
CallKind::Tail => {
1259-
match fn_abi.args[i].mode {
1260-
PassMode::Indirect { on_stack: false, .. } => {
1261-
let Some(tmp) = tail_call_temporaries[i].take() else {
1262-
span_bug!(
1263-
fn_span,
1264-
"missing temporary for indirect tail call argument #{i}"
1265-
)
1266-
};
1267-
1268-
let local = self.mir.args_iter().nth(i).unwrap();
1269-
1270-
match &self.locals[local] {
1271-
LocalRef::Place(arg) => {
1272-
bx.typed_place_copy(arg.val, tmp.val, fn_abi.args[i].layout);
1273-
op.val = Ref(arg.val);
1274-
}
1275-
LocalRef::Operand(arg) => {
1276-
let Ref(place_value) = arg.val else {
1277-
bug!("only `Ref` should use `PassMode::Indirect`");
1278-
};
1279-
bx.typed_place_copy(
1280-
place_value,
1281-
tmp.val,
1282-
fn_abi.args[i].layout,
1283-
);
1284-
op.val = arg.val;
1285-
}
1286-
LocalRef::UnsizedPlace(_) => {
1287-
span_bug!(fn_span, "unsized types are not supported")
1288-
}
1289-
LocalRef::PendingOperand => {
1290-
span_bug!(fn_span, "argument local should not be pending")
1291-
}
1292-
};
1293-
1294-
bx.lifetime_end(tmp.val.llval, tmp.layout.size);
1295-
}
1296-
PassMode::Indirect { on_stack: true, .. } => {
1297-
// FIXME: some LLVM backends (notably x86) do not correctly pass byval
1298-
// arguments to tail calls (as of LLVM 21). See also:
1299-
//
1300-
// - https://github.com/rust-lang/rust/pull/144232#discussion_r2218543841
1301-
// - https://github.com/rust-lang/rust/issues/144855
1259+
if let PassMode::Indirect { on_stack: false, .. } = fn_abi.args[i].mode {
1260+
let Some(tmp) = tail_call_temporaries[i].take() else {
13021261
span_bug!(
13031262
fn_span,
1304-
"arguments using PassMode::Indirect {{ on_stack: true, .. }} are currently not supported for tail calls"
1263+
"missing temporary for indirect tail call argument #{i}"
13051264
)
1306-
}
1307-
_ => (),
1265+
};
1266+
1267+
let local = self.mir.args_iter().nth(i).unwrap();
1268+
1269+
match &self.locals[local] {
1270+
LocalRef::Place(arg) => {
1271+
bx.typed_place_copy(arg.val, tmp.val, fn_abi.args[i].layout);
1272+
op.val = Ref(arg.val);
1273+
}
1274+
LocalRef::Operand(arg) => {
1275+
let Ref(place_value) = arg.val else {
1276+
bug!("only `Ref` should use `PassMode::Indirect`");
1277+
};
1278+
bx.typed_place_copy(place_value, tmp.val, fn_abi.args[i].layout);
1279+
op.val = arg.val;
1280+
}
1281+
LocalRef::UnsizedPlace(_) => {
1282+
span_bug!(fn_span, "unsized types are not supported")
1283+
}
1284+
LocalRef::PendingOperand => {
1285+
span_bug!(fn_span, "argument local should not be pending")
1286+
}
1287+
};
1288+
1289+
bx.lifetime_end(tmp.val.llval, tmp.layout.size);
13081290
}
13091291
}
13101292
}
Lines changed: 98 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,98 @@
1+
//@ build-pass
2+
//@ ignore-backends: gcc
3+
//@ add-minicore
4+
//@ min-llvm-version: 22
5+
//
6+
//@ revisions: host
7+
//@ revisions: i686
8+
//@[i686] compile-flags: --target i686-unknown-linux-gnu
9+
//@[i686] needs-llvm-components: x86
10+
//@ revisions: x86-64
11+
//@[x86-64] compile-flags: --target x86_64-unknown-linux-gnu
12+
//@[x86-64] needs-llvm-components: x86
13+
//@ revisions: x86-64-win
14+
//@[x86-64-win] compile-flags: --target x86_64-pc-windows-msvc
15+
//@[x86-64-win] needs-llvm-components: x86
16+
//@ revisions: arm
17+
//@[arm] compile-flags: --target arm-unknown-linux-gnueabi
18+
//@[arm] needs-llvm-components: arm
19+
//@ revisions: thumb
20+
//@[thumb] compile-flags: --target thumbv8m.main-none-eabi
21+
//@[thumb] needs-llvm-components: arm
22+
//@ revisions: aarch64
23+
//@[aarch64] compile-flags: --target aarch64-unknown-linux-gnu
24+
//@[aarch64] needs-llvm-components: aarch64
25+
//@ revisions: s390x
26+
//@[s390x] compile-flags: --target s390x-unknown-linux-gnu
27+
//@[s390x] needs-llvm-components: systemz
28+
//@ revisions: sparc
29+
//@[sparc] compile-flags: --target sparc-unknown-linux-gnu
30+
//@[sparc] needs-llvm-components: sparc
31+
//@ revisions: sparc64
32+
//@[sparc64] compile-flags: --target sparc64-unknown-linux-gnu
33+
//@[sparc64] needs-llvm-components: sparc
34+
//@ revisions: powerpc64
35+
//@[powerpc64] compile-flags: --target powerpc64-unknown-linux-gnu
36+
//@[powerpc64] needs-llvm-components: powerpc
37+
//@ revisions: riscv
38+
//@[riscv] compile-flags: --target riscv64gc-unknown-linux-gnu
39+
//@[riscv] needs-llvm-components: riscv
40+
//@ revisions: loongarch32
41+
//@[loongarch32] compile-flags: --target loongarch32-unknown-none
42+
//@[loongarch32] needs-llvm-components: loongarch
43+
//@ revisions: loongarch64
44+
//@[loongarch64] compile-flags: --target loongarch64-unknown-linux-gnu
45+
//@[loongarch64] needs-llvm-components: loongarch
46+
//@ revisions: bpf
47+
//@[bpf] compile-flags: --target bpfeb-unknown-none
48+
//@[bpf] needs-llvm-components: bpf
49+
//@ revisions: m68k
50+
//@[m68k] compile-flags: --target m68k-unknown-linux-gnu
51+
//@[m68k] needs-llvm-components: m68k
52+
//@ revisions: nvptx64
53+
//@[nvptx64] compile-flags: --target nvptx64-nvidia-cuda
54+
//@[nvptx64] needs-llvm-components: nvptx
55+
//
56+
// Wasm needs a special target feature.
57+
//
58+
//@ revisions: wasm
59+
//@[wasm] compile-flags: --target wasm32-unknown-unknown -Ctarget-feature=+tail-call
60+
//@[wasm] needs-llvm-components: webassembly
61+
//@ revisions: wasip1
62+
//@[wasip1] compile-flags: --target wasm32-wasip1 -Ctarget-feature=+tail-call
63+
//@[wasip1] needs-llvm-components: webassembly
64+
//
65+
// Failing cases (just zero support)
66+
//
67+
// //@ revisions: powerpc
68+
// //@[powerpc] compile-flags: --target powerpc-unknown-linux-gnu
69+
// //@[powerpc] needs-llvm-components: powerpc
70+
// //@ revisions: aix
71+
// //@[aix] compile-flags: --target powerpc64-ibm-aix
72+
// //@[aix] needs-llvm-components: powerpc
73+
// //@ revisions: csky
74+
// //@[csky] compile-flags: --target csky-unknown-linux-gnuabiv2
75+
// //@[csky] needs-llvm-components: csky
76+
// //@ revisions: mips
77+
// //@[mips] compile-flags: --target mips-unknown-linux-gnu
78+
// //@[mips] needs-llvm-components: mips
79+
// //@ revisions: mips64
80+
// //@[mips64] compile-flags: --target mips64-unknown-linux-gnuabi64
81+
// //@[mips64] needs-llvm-components: mips
82+
#![feature(no_core, explicit_tail_calls)]
83+
#![expect(incomplete_features)]
84+
#![no_core]
85+
#![crate_type = "lib"]
86+
87+
extern crate minicore;
88+
use minicore::*;
89+
90+
#[inline(never)]
91+
fn simple1(x: u64) -> u64 {
92+
x
93+
}
94+
95+
#[unsafe(no_mangle)]
96+
fn simple2(x: u64) -> u64 {
97+
become simple1(x);
98+
}
Lines changed: 109 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,109 @@
1+
//@ build-pass
2+
//@ ignore-backends: gcc
3+
//@ add-minicore
4+
//@ min-llvm-version: 22
5+
//
6+
//@ revisions: host
7+
//@ revisions: i686
8+
//@[i686] compile-flags: --target i686-unknown-linux-gnu
9+
//@[i686] needs-llvm-components: x86
10+
//@ revisions: x86-64
11+
//@[x86-64] compile-flags: --target x86_64-unknown-linux-gnu
12+
//@[x86-64] needs-llvm-components: x86
13+
//@ revisions: x86-64-win
14+
//@[x86-64-win] compile-flags: --target x86_64-pc-windows-msvc
15+
//@[x86-64-win] needs-llvm-components: x86
16+
//@ revisions: arm
17+
//@[arm] compile-flags: --target arm-unknown-linux-gnueabi
18+
//@[arm] needs-llvm-components: arm
19+
//@ revisions: thumb
20+
//@[thumb] compile-flags: --target thumbv8m.main-none-eabi
21+
//@[thumb] needs-llvm-components: arm
22+
//@ revisions: aarch64
23+
//@[aarch64] compile-flags: --target aarch64-unknown-linux-gnu
24+
//@[aarch64] needs-llvm-components: aarch64
25+
//@ revisions: s390x
26+
//@[s390x] compile-flags: --target s390x-unknown-linux-gnu
27+
//@[s390x] needs-llvm-components: systemz
28+
//@ revisions: sparc
29+
//@[sparc] compile-flags: --target sparc-unknown-linux-gnu
30+
//@[sparc] needs-llvm-components: sparc
31+
//@ revisions: sparc64
32+
//@[sparc64] compile-flags: --target sparc64-unknown-linux-gnu
33+
//@[sparc64] needs-llvm-components: sparc
34+
//@ revisions: powerpc64
35+
//@[powerpc64] compile-flags: --target powerpc64-unknown-linux-gnu
36+
//@[powerpc64] needs-llvm-components: powerpc
37+
//@ revisions: loongarch32
38+
//@[loongarch32] compile-flags: --target loongarch32-unknown-none
39+
//@[loongarch32] needs-llvm-components: loongarch
40+
//@ revisions: loongarch64
41+
//@[loongarch64] compile-flags: --target loongarch64-unknown-linux-gnu
42+
//@[loongarch64] needs-llvm-components: loongarch
43+
//@ revisions: bpf
44+
//@[bpf] compile-flags: --target bpfeb-unknown-none
45+
//@[bpf] needs-llvm-components: bpf
46+
//@ revisions: m68k
47+
//@[m68k] compile-flags: --target m68k-unknown-linux-gnu
48+
//@[m68k] needs-llvm-components: m68k
49+
//@ revisions: nvptx64
50+
//@[nvptx64] compile-flags: --target nvptx64-nvidia-cuda
51+
//@[nvptx64] needs-llvm-components: nvptx
52+
//
53+
// Riscv does not support byval in LLVM 22 (but wil in LLVM 23)
54+
//
55+
// //@ revisions: riscv
56+
// //@[riscv] compile-flags: --target riscv64gc-unknown-linux-gnu
57+
// //@[riscv] needs-llvm-components: riscv
58+
//
59+
// Wasm needs a special target feature.
60+
//
61+
//@ revisions: wasm
62+
//@[wasm] compile-flags: --target wasm32-unknown-unknown -Ctarget-feature=+tail-call
63+
//@[wasm] needs-llvm-components: webassembly
64+
//@ revisions: wasip1
65+
//@[wasip1] compile-flags: --target wasm32-wasip1 -Ctarget-feature=+tail-call
66+
//@[wasip1] needs-llvm-components: webassembly
67+
//
68+
// Failing cases (just zero support)
69+
//
70+
// //@ revisions: powerpc
71+
// //@[powerpc] compile-flags: --target powerpc-unknown-linux-gnu
72+
// //@[powerpc] needs-llvm-components: powerpc
73+
// //@ revisions: aix
74+
// //@[aix] compile-flags: --target powerpc64-ibm-aix
75+
// //@[aix] needs-llvm-components: powerpc
76+
// //@ revisions: csky
77+
// //@[csky] compile-flags: --target csky-unknown-linux-gnuabiv2
78+
// //@[csky] needs-llvm-components: csky
79+
// //@ revisions: mips
80+
// //@[mips] compile-flags: --target mips-unknown-linux-gnu
81+
// //@[mips] needs-llvm-components: mips
82+
// //@ revisions: mips64
83+
// //@[mips64] compile-flags: --target mips64-unknown-linux-gnuabi64
84+
// //@[mips64] needs-llvm-components: mips
85+
#![feature(no_core, explicit_tail_calls)]
86+
#![expect(incomplete_features)]
87+
#![no_core]
88+
#![crate_type = "lib"]
89+
90+
extern crate minicore;
91+
use minicore::*;
92+
93+
#[repr(C)]
94+
struct PassedByVal {
95+
a: u64,
96+
b: u64,
97+
c: u64,
98+
d: u64,
99+
}
100+
101+
#[inline(never)]
102+
extern "C" fn callee(x: PassedByVal) -> PassedByVal {
103+
x
104+
}
105+
106+
#[unsafe(no_mangle)]
107+
extern "C" fn byval(x: PassedByVal) -> PassedByVal {
108+
become callee(x);
109+
}

0 commit comments

Comments
 (0)