mirror of
https://github.com/rust-lang/rust.git
synced 2026-04-27 18:57:42 +03:00
Rollup merge of #153361 - folkertdev:tail-call-indirect-on-stack-true, r=WaffleLapkin
enable `PassMode::Indirect { on_stack: true, .. }` tail call arguments
tracking issue: https://github.com/rust-lang/rust/issues/112788
fixes https://github.com/rust-lang/rust/issues/144855
And add a bunch of tests for tail call target support.
r? WaffleLapkin
This commit is contained in:
@@ -1256,55 +1256,37 @@ fn codegen_call_terminator(
|
||||
}
|
||||
}
|
||||
CallKind::Tail => {
|
||||
match fn_abi.args[i].mode {
|
||||
PassMode::Indirect { on_stack: false, .. } => {
|
||||
let Some(tmp) = tail_call_temporaries[i].take() else {
|
||||
span_bug!(
|
||||
fn_span,
|
||||
"missing temporary for indirect tail call argument #{i}"
|
||||
)
|
||||
};
|
||||
|
||||
let local = self.mir.args_iter().nth(i).unwrap();
|
||||
|
||||
match &self.locals[local] {
|
||||
LocalRef::Place(arg) => {
|
||||
bx.typed_place_copy(arg.val, tmp.val, fn_abi.args[i].layout);
|
||||
op.val = Ref(arg.val);
|
||||
}
|
||||
LocalRef::Operand(arg) => {
|
||||
let Ref(place_value) = arg.val else {
|
||||
bug!("only `Ref` should use `PassMode::Indirect`");
|
||||
};
|
||||
bx.typed_place_copy(
|
||||
place_value,
|
||||
tmp.val,
|
||||
fn_abi.args[i].layout,
|
||||
);
|
||||
op.val = arg.val;
|
||||
}
|
||||
LocalRef::UnsizedPlace(_) => {
|
||||
span_bug!(fn_span, "unsized types are not supported")
|
||||
}
|
||||
LocalRef::PendingOperand => {
|
||||
span_bug!(fn_span, "argument local should not be pending")
|
||||
}
|
||||
};
|
||||
|
||||
bx.lifetime_end(tmp.val.llval, tmp.layout.size);
|
||||
}
|
||||
PassMode::Indirect { on_stack: true, .. } => {
|
||||
// FIXME: some LLVM backends (notably x86) do not correctly pass byval
|
||||
// arguments to tail calls (as of LLVM 21). See also:
|
||||
//
|
||||
// - https://github.com/rust-lang/rust/pull/144232#discussion_r2218543841
|
||||
// - https://github.com/rust-lang/rust/issues/144855
|
||||
if let PassMode::Indirect { on_stack: false, .. } = fn_abi.args[i].mode {
|
||||
let Some(tmp) = tail_call_temporaries[i].take() else {
|
||||
span_bug!(
|
||||
fn_span,
|
||||
"arguments using PassMode::Indirect {{ on_stack: true, .. }} are currently not supported for tail calls"
|
||||
"missing temporary for indirect tail call argument #{i}"
|
||||
)
|
||||
}
|
||||
_ => (),
|
||||
};
|
||||
|
||||
let local = self.mir.args_iter().nth(i).unwrap();
|
||||
|
||||
match &self.locals[local] {
|
||||
LocalRef::Place(arg) => {
|
||||
bx.typed_place_copy(arg.val, tmp.val, fn_abi.args[i].layout);
|
||||
op.val = Ref(arg.val);
|
||||
}
|
||||
LocalRef::Operand(arg) => {
|
||||
let Ref(place_value) = arg.val else {
|
||||
bug!("only `Ref` should use `PassMode::Indirect`");
|
||||
};
|
||||
bx.typed_place_copy(place_value, tmp.val, fn_abi.args[i].layout);
|
||||
op.val = arg.val;
|
||||
}
|
||||
LocalRef::UnsizedPlace(_) => {
|
||||
span_bug!(fn_span, "unsized types are not supported")
|
||||
}
|
||||
LocalRef::PendingOperand => {
|
||||
span_bug!(fn_span, "argument local should not be pending")
|
||||
}
|
||||
};
|
||||
|
||||
bx.lifetime_end(tmp.val.llval, tmp.layout.size);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,97 @@
|
||||
//@ build-pass
|
||||
//@ ignore-backends: gcc
|
||||
//@ add-minicore
|
||||
//@ min-llvm-version: 22
|
||||
//
|
||||
//@ revisions: i686
|
||||
//@[i686] compile-flags: --target i686-unknown-linux-gnu
|
||||
//@[i686] needs-llvm-components: x86
|
||||
//@ revisions: x86-64
|
||||
//@[x86-64] compile-flags: --target x86_64-unknown-linux-gnu
|
||||
//@[x86-64] needs-llvm-components: x86
|
||||
//@ revisions: x86-64-win
|
||||
//@[x86-64-win] compile-flags: --target x86_64-pc-windows-msvc
|
||||
//@[x86-64-win] needs-llvm-components: x86
|
||||
//@ revisions: arm
|
||||
//@[arm] compile-flags: --target arm-unknown-linux-gnueabi
|
||||
//@[arm] needs-llvm-components: arm
|
||||
//@ revisions: thumb
|
||||
//@[thumb] compile-flags: --target thumbv8m.main-none-eabi
|
||||
//@[thumb] needs-llvm-components: arm
|
||||
//@ revisions: aarch64
|
||||
//@[aarch64] compile-flags: --target aarch64-unknown-linux-gnu
|
||||
//@[aarch64] needs-llvm-components: aarch64
|
||||
//@ revisions: s390x
|
||||
//@[s390x] compile-flags: --target s390x-unknown-linux-gnu
|
||||
//@[s390x] needs-llvm-components: systemz
|
||||
//@ revisions: sparc
|
||||
//@[sparc] compile-flags: --target sparc-unknown-linux-gnu
|
||||
//@[sparc] needs-llvm-components: sparc
|
||||
//@ revisions: sparc64
|
||||
//@[sparc64] compile-flags: --target sparc64-unknown-linux-gnu
|
||||
//@[sparc64] needs-llvm-components: sparc
|
||||
//@ revisions: powerpc64
|
||||
//@[powerpc64] compile-flags: --target powerpc64-unknown-linux-gnu
|
||||
//@[powerpc64] needs-llvm-components: powerpc
|
||||
//@ revisions: riscv
|
||||
//@[riscv] compile-flags: --target riscv64gc-unknown-linux-gnu
|
||||
//@[riscv] needs-llvm-components: riscv
|
||||
//@ revisions: loongarch32
|
||||
//@[loongarch32] compile-flags: --target loongarch32-unknown-none
|
||||
//@[loongarch32] needs-llvm-components: loongarch
|
||||
//@ revisions: loongarch64
|
||||
//@[loongarch64] compile-flags: --target loongarch64-unknown-linux-gnu
|
||||
//@[loongarch64] needs-llvm-components: loongarch
|
||||
//@ revisions: bpf
|
||||
//@[bpf] compile-flags: --target bpfeb-unknown-none
|
||||
//@[bpf] needs-llvm-components: bpf
|
||||
//@ revisions: m68k
|
||||
//@[m68k] compile-flags: --target m68k-unknown-linux-gnu
|
||||
//@[m68k] needs-llvm-components: m68k
|
||||
//@ revisions: nvptx64
|
||||
//@[nvptx64] compile-flags: --target nvptx64-nvidia-cuda
|
||||
//@[nvptx64] needs-llvm-components: nvptx
|
||||
//
|
||||
// Wasm needs a special target feature.
|
||||
//
|
||||
//@ revisions: wasm
|
||||
//@[wasm] compile-flags: --target wasm32-unknown-unknown -Ctarget-feature=+tail-call
|
||||
//@[wasm] needs-llvm-components: webassembly
|
||||
//@ revisions: wasip1
|
||||
//@[wasip1] compile-flags: --target wasm32-wasip1 -Ctarget-feature=+tail-call
|
||||
//@[wasip1] needs-llvm-components: webassembly
|
||||
//
|
||||
// Failing cases (just zero support)
|
||||
//
|
||||
// //@ revisions: powerpc
|
||||
// //@[powerpc] compile-flags: --target powerpc-unknown-linux-gnu
|
||||
// //@[powerpc] needs-llvm-components: powerpc
|
||||
// //@ revisions: aix
|
||||
// //@[aix] compile-flags: --target powerpc64-ibm-aix
|
||||
// //@[aix] needs-llvm-components: powerpc
|
||||
// //@ revisions: csky
|
||||
// //@[csky] compile-flags: --target csky-unknown-linux-gnuabiv2
|
||||
// //@[csky] needs-llvm-components: csky
|
||||
// //@ revisions: mips
|
||||
// //@[mips] compile-flags: --target mips-unknown-linux-gnu
|
||||
// //@[mips] needs-llvm-components: mips
|
||||
// //@ revisions: mips64
|
||||
// //@[mips64] compile-flags: --target mips64-unknown-linux-gnuabi64
|
||||
// //@[mips64] needs-llvm-components: mips
|
||||
#![feature(no_core, explicit_tail_calls)]
|
||||
#![expect(incomplete_features)]
|
||||
#![no_core]
|
||||
#![crate_type = "lib"]
|
||||
|
||||
extern crate minicore;
|
||||
use minicore::*;
|
||||
|
||||
#[inline(never)]
|
||||
fn simple1(x: u64) -> u64 {
|
||||
x
|
||||
}
|
||||
|
||||
#[unsafe(no_mangle)]
|
||||
fn simple2(x: u64) -> u64 {
|
||||
become simple1(x);
|
||||
}
|
||||
@@ -0,0 +1,108 @@
|
||||
//@ build-pass
|
||||
//@ ignore-backends: gcc
|
||||
//@ add-minicore
|
||||
//@ min-llvm-version: 22
|
||||
//
|
||||
//@ revisions: i686
|
||||
//@[i686] compile-flags: --target i686-unknown-linux-gnu
|
||||
//@[i686] needs-llvm-components: x86
|
||||
//@ revisions: x86-64
|
||||
//@[x86-64] compile-flags: --target x86_64-unknown-linux-gnu
|
||||
//@[x86-64] needs-llvm-components: x86
|
||||
//@ revisions: x86-64-win
|
||||
//@[x86-64-win] compile-flags: --target x86_64-pc-windows-msvc
|
||||
//@[x86-64-win] needs-llvm-components: x86
|
||||
//@ revisions: arm
|
||||
//@[arm] compile-flags: --target arm-unknown-linux-gnueabi
|
||||
//@[arm] needs-llvm-components: arm
|
||||
//@ revisions: thumb
|
||||
//@[thumb] compile-flags: --target thumbv8m.main-none-eabi
|
||||
//@[thumb] needs-llvm-components: arm
|
||||
//@ revisions: aarch64
|
||||
//@[aarch64] compile-flags: --target aarch64-unknown-linux-gnu
|
||||
//@[aarch64] needs-llvm-components: aarch64
|
||||
//@ revisions: s390x
|
||||
//@[s390x] compile-flags: --target s390x-unknown-linux-gnu
|
||||
//@[s390x] needs-llvm-components: systemz
|
||||
//@ revisions: sparc
|
||||
//@[sparc] compile-flags: --target sparc-unknown-linux-gnu
|
||||
//@[sparc] needs-llvm-components: sparc
|
||||
//@ revisions: sparc64
|
||||
//@[sparc64] compile-flags: --target sparc64-unknown-linux-gnu
|
||||
//@[sparc64] needs-llvm-components: sparc
|
||||
//@ revisions: powerpc64
|
||||
//@[powerpc64] compile-flags: --target powerpc64-unknown-linux-gnu
|
||||
//@[powerpc64] needs-llvm-components: powerpc
|
||||
//@ revisions: loongarch32
|
||||
//@[loongarch32] compile-flags: --target loongarch32-unknown-none
|
||||
//@[loongarch32] needs-llvm-components: loongarch
|
||||
//@ revisions: loongarch64
|
||||
//@[loongarch64] compile-flags: --target loongarch64-unknown-linux-gnu
|
||||
//@[loongarch64] needs-llvm-components: loongarch
|
||||
//@ revisions: bpf
|
||||
//@[bpf] compile-flags: --target bpfeb-unknown-none
|
||||
//@[bpf] needs-llvm-components: bpf
|
||||
//@ revisions: m68k
|
||||
//@[m68k] compile-flags: --target m68k-unknown-linux-gnu
|
||||
//@[m68k] needs-llvm-components: m68k
|
||||
//@ revisions: nvptx64
|
||||
//@[nvptx64] compile-flags: --target nvptx64-nvidia-cuda
|
||||
//@[nvptx64] needs-llvm-components: nvptx
|
||||
//
|
||||
// Riscv does not support byval in LLVM 22 (but wil in LLVM 23)
|
||||
//
|
||||
// //@ revisions: riscv
|
||||
// //@[riscv] compile-flags: --target riscv64gc-unknown-linux-gnu
|
||||
// //@[riscv] needs-llvm-components: riscv
|
||||
//
|
||||
// Wasm needs a special target feature.
|
||||
//
|
||||
//@ revisions: wasm
|
||||
//@[wasm] compile-flags: --target wasm32-unknown-unknown -Ctarget-feature=+tail-call
|
||||
//@[wasm] needs-llvm-components: webassembly
|
||||
//@ revisions: wasip1
|
||||
//@[wasip1] compile-flags: --target wasm32-wasip1 -Ctarget-feature=+tail-call
|
||||
//@[wasip1] needs-llvm-components: webassembly
|
||||
//
|
||||
// Failing cases (just zero support)
|
||||
//
|
||||
// //@ revisions: powerpc
|
||||
// //@[powerpc] compile-flags: --target powerpc-unknown-linux-gnu
|
||||
// //@[powerpc] needs-llvm-components: powerpc
|
||||
// //@ revisions: aix
|
||||
// //@[aix] compile-flags: --target powerpc64-ibm-aix
|
||||
// //@[aix] needs-llvm-components: powerpc
|
||||
// //@ revisions: csky
|
||||
// //@[csky] compile-flags: --target csky-unknown-linux-gnuabiv2
|
||||
// //@[csky] needs-llvm-components: csky
|
||||
// //@ revisions: mips
|
||||
// //@[mips] compile-flags: --target mips-unknown-linux-gnu
|
||||
// //@[mips] needs-llvm-components: mips
|
||||
// //@ revisions: mips64
|
||||
// //@[mips64] compile-flags: --target mips64-unknown-linux-gnuabi64
|
||||
// //@[mips64] needs-llvm-components: mips
|
||||
#![feature(no_core, explicit_tail_calls)]
|
||||
#![expect(incomplete_features)]
|
||||
#![no_core]
|
||||
#![crate_type = "lib"]
|
||||
|
||||
extern crate minicore;
|
||||
use minicore::*;
|
||||
|
||||
#[repr(C)]
|
||||
struct PassedByVal {
|
||||
a: u64,
|
||||
b: u64,
|
||||
c: u64,
|
||||
d: u64,
|
||||
}
|
||||
|
||||
#[inline(never)]
|
||||
extern "C" fn callee(x: PassedByVal) -> PassedByVal {
|
||||
x
|
||||
}
|
||||
|
||||
#[unsafe(no_mangle)]
|
||||
extern "C" fn byval(x: PassedByVal) -> PassedByVal {
|
||||
become callee(x);
|
||||
}
|
||||
@@ -0,0 +1,108 @@
|
||||
//@ build-pass
|
||||
//@ ignore-backends: gcc
|
||||
//@ add-minicore
|
||||
//@ min-llvm-version: 22
|
||||
//
|
||||
//@ revisions: i686
|
||||
//@[i686] compile-flags: --target i686-unknown-linux-gnu
|
||||
//@[i686] needs-llvm-components: x86
|
||||
//@ revisions: x86-64
|
||||
//@[x86-64] compile-flags: --target x86_64-unknown-linux-gnu
|
||||
//@[x86-64] needs-llvm-components: x86
|
||||
//@ revisions: x86-64-win
|
||||
//@[x86-64-win] compile-flags: --target x86_64-pc-windows-msvc
|
||||
//@[x86-64-win] needs-llvm-components: x86
|
||||
//@ revisions: arm
|
||||
//@[arm] compile-flags: --target arm-unknown-linux-gnueabi
|
||||
//@[arm] needs-llvm-components: arm
|
||||
//@ revisions: thumb
|
||||
//@[thumb] compile-flags: --target thumbv8m.main-none-eabi
|
||||
//@[thumb] needs-llvm-components: arm
|
||||
//@ revisions: aarch64
|
||||
//@[aarch64] compile-flags: --target aarch64-unknown-linux-gnu
|
||||
//@[aarch64] needs-llvm-components: aarch64
|
||||
//@ revisions: s390x
|
||||
//@[s390x] compile-flags: --target s390x-unknown-linux-gnu
|
||||
//@[s390x] needs-llvm-components: systemz
|
||||
//@ revisions: sparc
|
||||
//@[sparc] compile-flags: --target sparc-unknown-linux-gnu
|
||||
//@[sparc] needs-llvm-components: sparc
|
||||
//@ revisions: sparc64
|
||||
//@[sparc64] compile-flags: --target sparc64-unknown-linux-gnu
|
||||
//@[sparc64] needs-llvm-components: sparc
|
||||
//@ revisions: powerpc64
|
||||
//@[powerpc64] compile-flags: --target powerpc64-unknown-linux-gnu
|
||||
//@[powerpc64] needs-llvm-components: powerpc
|
||||
//@ revisions: loongarch32
|
||||
//@[loongarch32] compile-flags: --target loongarch32-unknown-none
|
||||
//@[loongarch32] needs-llvm-components: loongarch
|
||||
//@ revisions: loongarch64
|
||||
//@[loongarch64] compile-flags: --target loongarch64-unknown-linux-gnu
|
||||
//@[loongarch64] needs-llvm-components: loongarch
|
||||
//@ revisions: bpf
|
||||
//@[bpf] compile-flags: --target bpfeb-unknown-none
|
||||
//@[bpf] needs-llvm-components: bpf
|
||||
//@ revisions: m68k
|
||||
//@[m68k] compile-flags: --target m68k-unknown-linux-gnu
|
||||
//@[m68k] needs-llvm-components: m68k
|
||||
//@ revisions: nvptx64
|
||||
//@[nvptx64] compile-flags: --target nvptx64-nvidia-cuda
|
||||
//@[nvptx64] needs-llvm-components: nvptx
|
||||
//
|
||||
// Riscv does not support byval in LLVM 22 (but wil in LLVM 23)
|
||||
//
|
||||
// //@ revisions: riscv
|
||||
// //@[riscv] compile-flags: --target riscv64gc-unknown-linux-gnu
|
||||
// //@[riscv] needs-llvm-components: riscv
|
||||
//
|
||||
// Wasm needs a special target feature.
|
||||
//
|
||||
//@ revisions: wasm
|
||||
//@[wasm] compile-flags: --target wasm32-unknown-unknown -Ctarget-feature=+tail-call
|
||||
//@[wasm] needs-llvm-components: webassembly
|
||||
//@ revisions: wasip1
|
||||
//@[wasip1] compile-flags: --target wasm32-wasip1 -Ctarget-feature=+tail-call
|
||||
//@[wasip1] needs-llvm-components: webassembly
|
||||
//
|
||||
// Failing cases (just zero support)
|
||||
//
|
||||
// //@ revisions: powerpc
|
||||
// //@[powerpc] compile-flags: --target powerpc-unknown-linux-gnu
|
||||
// //@[powerpc] needs-llvm-components: powerpc
|
||||
// //@ revisions: aix
|
||||
// //@[aix] compile-flags: --target powerpc64-ibm-aix
|
||||
// //@[aix] needs-llvm-components: powerpc
|
||||
// //@ revisions: csky
|
||||
// //@[csky] compile-flags: --target csky-unknown-linux-gnuabiv2
|
||||
// //@[csky] needs-llvm-components: csky
|
||||
// //@ revisions: mips
|
||||
// //@[mips] compile-flags: --target mips-unknown-linux-gnu
|
||||
// //@[mips] needs-llvm-components: mips
|
||||
// //@ revisions: mips64
|
||||
// //@[mips64] compile-flags: --target mips64-unknown-linux-gnuabi64
|
||||
// //@[mips64] needs-llvm-components: mips
|
||||
#![feature(no_core, explicit_tail_calls)]
|
||||
#![expect(incomplete_features)]
|
||||
#![no_core]
|
||||
#![crate_type = "lib"]
|
||||
|
||||
extern crate minicore;
|
||||
use minicore::*;
|
||||
|
||||
// The rust calling convention will pass this by-value.
|
||||
struct PassedByVal {
|
||||
a: u64,
|
||||
b: u64,
|
||||
c: u64,
|
||||
d: u64,
|
||||
}
|
||||
|
||||
#[inline(never)]
|
||||
fn callee(x: PassedByVal) -> PassedByVal {
|
||||
x
|
||||
}
|
||||
|
||||
#[unsafe(no_mangle)]
|
||||
fn byval(x: PassedByVal) -> PassedByVal {
|
||||
become callee(x);
|
||||
}
|
||||
Reference in New Issue
Block a user