Skip to content

Commit f3eef25

Browse files
committed
rust_for_linux: -Zreg-struct-return commandline flag for X86 (rust-lang#116973)
1 parent bca5fde commit f3eef25

File tree

15 files changed

+136
-4
lines changed

15 files changed

+136
-4
lines changed

compiler/rustc_codegen_gcc/src/context.rs

+4-1
Original file line numberDiff line numberDiff line change
@@ -542,7 +542,10 @@ impl<'gcc, 'tcx> HasWasmCAbiOpt for CodegenCx<'gcc, 'tcx> {
542542

543543
impl<'gcc, 'tcx> HasX86AbiOpt for CodegenCx<'gcc, 'tcx> {
544544
fn x86_abi_opt(&self) -> X86Abi {
545-
X86Abi { regparm: self.tcx.sess.opts.unstable_opts.regparm }
545+
X86Abi {
546+
regparm: self.tcx.sess.opts.unstable_opts.regparm,
547+
reg_struct_return: self.tcx.sess.opts.unstable_opts.reg_struct_return,
548+
}
546549
}
547550
}
548551

compiler/rustc_interface/src/tests.rs

+1
Original file line numberDiff line numberDiff line change
@@ -836,6 +836,7 @@ fn test_unstable_options_tracking_hash() {
836836
tracked!(profile_emit, Some(PathBuf::from("abc")));
837837
tracked!(profile_sample_use, Some(PathBuf::from("abc")));
838838
tracked!(profiler_runtime, "abc".to_string());
839+
tracked!(reg_struct_return, true);
839840
tracked!(regparm, Some(3));
840841
tracked!(relax_elf_relocations, Some(true));
841842
tracked!(remap_cwd_prefix, Some(PathBuf::from("abc")));

compiler/rustc_middle/src/ty/layout.rs

+4-1
Original file line numberDiff line numberDiff line change
@@ -548,7 +548,10 @@ impl<'tcx> HasWasmCAbiOpt for TyCtxt<'tcx> {
548548

549549
impl<'tcx> HasX86AbiOpt for TyCtxt<'tcx> {
550550
fn x86_abi_opt(&self) -> X86Abi {
551-
X86Abi { regparm: self.sess.opts.unstable_opts.regparm }
551+
X86Abi {
552+
regparm: self.sess.opts.unstable_opts.regparm,
553+
reg_struct_return: self.sess.opts.unstable_opts.reg_struct_return,
554+
}
552555
}
553556
}
554557

compiler/rustc_session/messages.ftl

+1
Original file line numberDiff line numberDiff line change
@@ -137,5 +137,6 @@ session_unsupported_crate_type_for_target =
137137
138138
session_unsupported_dwarf_version = requested DWARF version {$dwarf_version} is greater than 5
139139
140+
session_unsupported_reg_struct_return_arch = `-Zreg-struct-return` is only supported on x86
140141
session_unsupported_regparm = `-Zregparm={$regparm}` is unsupported (valid values 0-3)
141142
session_unsupported_regparm_arch = `-Zregparm=N` is only supported on x86

compiler/rustc_session/src/errors.rs

+4
Original file line numberDiff line numberDiff line change
@@ -495,6 +495,10 @@ pub(crate) struct UnsupportedRegparm {
495495
#[diag(session_unsupported_regparm_arch)]
496496
pub(crate) struct UnsupportedRegparmArch;
497497

498+
#[derive(Diagnostic)]
499+
#[diag(session_unsupported_reg_struct_return_arch)]
500+
pub(crate) struct UnsupportedRegStructReturnArch;
501+
498502
#[derive(Diagnostic)]
499503
#[diag(session_failed_to_create_profiler)]
500504
pub(crate) struct FailedToCreateProfiler {

compiler/rustc_session/src/options.rs

+3
Original file line numberDiff line numberDiff line change
@@ -2000,6 +2000,9 @@ options! {
20002000
"enable queries of the dependency graph for regression testing (default: no)"),
20012001
randomize_layout: bool = (false, parse_bool, [TRACKED],
20022002
"randomize the layout of types (default: no)"),
2003+
reg_struct_return: bool = (false, parse_bool, [TRACKED],
2004+
"On x86-32 targets, it overrides the default ABI to return small structs in registers.
2005+
It is UNSOUND to link together crates that use different values for this flag!"),
20032006
regparm: Option<u32> = (None, parse_opt_number, [TRACKED],
20042007
"On x86-32 targets, setting this to N causes the compiler to pass N arguments \
20052008
in registers EAX, EDX, and ECX instead of on the stack for\

compiler/rustc_session/src/session.rs

+5
Original file line numberDiff line numberDiff line change
@@ -1345,6 +1345,11 @@ fn validate_commandline_args_with_session_available(sess: &Session) {
13451345
sess.dcx().emit_err(errors::UnsupportedRegparmArch);
13461346
}
13471347
}
1348+
if sess.opts.unstable_opts.reg_struct_return {
1349+
if sess.target.arch != "x86" {
1350+
sess.dcx().emit_err(errors::UnsupportedRegStructReturnArch);
1351+
}
1352+
}
13481353

13491354
// The code model check applies to `thunk` and `thunk-extern`, but not `thunk-inline`, so it is
13501355
// kept as a `match` to force a change if new ones are added, even if we currently only support

compiler/rustc_target/src/callconv/mod.rs

+3-1
Original file line numberDiff line numberDiff line change
@@ -654,7 +654,9 @@ impl<'a, Ty> FnAbi<'a, Ty> {
654654
}
655655
_ => (x86::Flavor::General, None),
656656
};
657-
x86::compute_abi_info(cx, self, x86::X86Options { flavor, regparm });
657+
let reg_struct_return = cx.x86_abi_opt().reg_struct_return;
658+
let opts = x86::X86Options { flavor, regparm, reg_struct_return };
659+
x86::compute_abi_info(cx, self, opts);
658660
}
659661
"x86_64" => match abi {
660662
spec::abi::Abi::SysV64 { .. } => x86_64::compute_abi_info(cx, self),

compiler/rustc_target/src/callconv/x86.rs

+2-1
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ pub(crate) enum Flavor {
1111
pub(crate) struct X86Options {
1212
pub flavor: Flavor,
1313
pub regparm: Option<u32>,
14+
pub reg_struct_return: bool,
1415
}
1516

1617
pub(crate) fn compute_abi_info<'a, Ty, C>(cx: &C, fn_abi: &mut FnAbi<'a, Ty>, opts: X86Options)
@@ -28,7 +29,7 @@ where
2829
// https://www.angelcode.com/dev/callconv/callconv.html
2930
// Clang's ABI handling is in lib/CodeGen/TargetInfo.cpp
3031
let t = cx.target_spec();
31-
if t.abi_return_struct_as_int {
32+
if t.abi_return_struct_as_int || opts.reg_struct_return {
3233
// According to Clang, everyone but MSVC returns single-element
3334
// float aggregates directly in a floating-point register.
3435
if !t.is_like_msvc && fn_abi.ret.layout.is_single_fp_element(cx) {

compiler/rustc_target/src/spec/mod.rs

+2
Original file line numberDiff line numberDiff line change
@@ -2102,6 +2102,8 @@ pub struct X86Abi {
21022102
/// On x86-32 targets, the regparm N causes the compiler to pass arguments
21032103
/// in registers EAX, EDX, and ECX instead of on the stack.
21042104
pub regparm: Option<u32>,
2105+
/// Override the default ABI to return small structs in registers
2106+
pub reg_struct_return: bool,
21052107
}
21062108

21072109
pub trait HasX86AbiOpt {
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
# `reg-struct-return`
2+
3+
The tracking issue for this feature is: https://github.com/rust-lang/rust/issues/116973.
4+
5+
------------------------
6+
7+
Option -Zreg-struct-return causes the compiler to return small structs in registers
8+
instead of on the stack for extern "C"-like functions.
9+
It is UNSOUND to link together crates that use different values for this flag.
10+
It is only supported on `x86`.
11+
12+
It is equivalent to [Clang]'s and [GCC]'s `-freg-struct-return`.
13+
14+
[Clang]: https://clang.llvm.org/docs/ClangCommandLineReference.html#cmdoption-clang-freg-struct-return
15+
[GCC]: https://gcc.gnu.org/onlinedocs/gcc/Code-Gen-Options.html#index-freg-struct-return

tests/codegen/reg-struct-return.rs

+63
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,63 @@
1+
// Checks how `reg-struct-return` flag works with different calling conventions:
2+
// Return struct with 8/16/32/64 bit size will be converted into i8/i16/i32/i64
3+
// (like abi_return_struct_as_int target spec).
4+
// x86 only.
5+
6+
//@ compile-flags: --target i686-unknown-linux-gnu -Zreg-struct-return -O -C no-prepopulate-passes
7+
//@ needs-llvm-components: x86
8+
9+
#![crate_type = "lib"]
10+
#![no_std]
11+
#![no_core]
12+
#![feature(no_core, lang_items)]
13+
14+
#[lang = "sized"]
15+
trait Sized {}
16+
#[lang = "copy"]
17+
trait Copy {}
18+
19+
#[repr(C)]
20+
pub struct Foo {
21+
x: u32,
22+
y: u32,
23+
}
24+
25+
pub mod tests {
26+
use Foo;
27+
28+
// CHECK: i64 @f1()
29+
#[no_mangle]
30+
pub extern "fastcall" fn f1() -> Foo {
31+
Foo { x: 1, y: 2 }
32+
}
33+
34+
// CHECK: { i32, i32 } @f2()
35+
#[no_mangle]
36+
pub extern "Rust" fn f2() -> Foo {
37+
Foo { x: 1, y: 2 }
38+
}
39+
40+
// CHECK: i64 @f3()
41+
#[no_mangle]
42+
pub extern "C" fn f3() -> Foo {
43+
Foo { x: 1, y: 2 }
44+
}
45+
46+
// CHECK: i64 @f4()
47+
#[no_mangle]
48+
pub extern "cdecl" fn f4() -> Foo {
49+
Foo { x: 1, y: 2 }
50+
}
51+
52+
// CHECK: i64 @f5()
53+
#[no_mangle]
54+
pub extern "stdcall" fn f5() -> Foo {
55+
Foo { x: 1, y: 2 }
56+
}
57+
58+
// CHECK: i64 @f6()
59+
#[no_mangle]
60+
pub extern "thiscall" fn f6() -> Foo {
61+
Foo { x: 1, y: 2 }
62+
}
63+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
error: `-Zreg-struct-return` is only supported on x86
2+
3+
error: aborting due to 1 previous error
4+
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
//@ revisions: x86 x86_64 aarch64
2+
3+
//@ compile-flags: -Zreg-struct-return
4+
5+
//@[x86] check-pass
6+
//@[x86] needs-llvm-components: x86
7+
//@[x86] compile-flags: --target i686-unknown-linux-gnu
8+
9+
//@[x86_64] check-fail
10+
//@[x86_64] needs-llvm-components: x86
11+
//@[x86_64] compile-flags: --target x86_64-unknown-linux-gnu
12+
//@[x86_64] error-pattern: `-Zreg-struct-return` is only supported on x86
13+
14+
//@[aarch64] check-fail
15+
//@[aarch64] needs-llvm-components: aarch64
16+
//@[aarch64] compile-flags: --target aarch64-unknown-linux-gnu
17+
//@[aarch64] error-pattern: `-Zreg-struct-return` is only supported on x86
18+
19+
#![feature(no_core)]
20+
#![no_core]
21+
#![no_main]
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
error: `-Zreg-struct-return` is only supported on x86
2+
3+
error: aborting due to 1 previous error
4+

0 commit comments

Comments
 (0)