Skip to content
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.

Commit 9aab517

Browse files
committedDec 1, 2024
rust_for_linux: -Zreg-struct-return commandline flag for X86 (#116973)
1 parent f005c74 commit 9aab517

File tree

15 files changed

+279
-4
lines changed

15 files changed

+279
-4
lines changed
 

‎compiler/rustc_codegen_gcc/src/context.rs

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

545545
impl<'gcc, 'tcx> HasX86AbiOpt for CodegenCx<'gcc, 'tcx> {
546546
fn x86_abi_opt(&self) -> X86Abi {
547-
X86Abi { regparm: self.tcx.sess.opts.unstable_opts.regparm }
547+
X86Abi {
548+
regparm: self.tcx.sess.opts.unstable_opts.regparm,
549+
reg_struct_return: self.tcx.sess.opts.unstable_opts.reg_struct_return,
550+
}
548551
}
549552
}
550553

‎compiler/rustc_interface/src/tests.rs

+1
Original file line numberDiff line numberDiff line change
@@ -831,6 +831,7 @@ fn test_unstable_options_tracking_hash() {
831831
tracked!(precise_enum_drop_elaboration, false);
832832
tracked!(profile_sample_use, Some(PathBuf::from("abc")));
833833
tracked!(profiler_runtime, "abc".to_string());
834+
tracked!(reg_struct_return, true);
834835
tracked!(regparm, Some(3));
835836
tracked!(relax_elf_relocations, Some(true));
836837
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
@@ -552,7 +552,10 @@ impl<'tcx> HasWasmCAbiOpt for TyCtxt<'tcx> {
552552

553553
impl<'tcx> HasX86AbiOpt for TyCtxt<'tcx> {
554554
fn x86_abi_opt(&self) -> X86Abi {
555-
X86Abi { regparm: self.sess.opts.unstable_opts.regparm }
555+
X86Abi {
556+
regparm: self.sess.opts.unstable_opts.regparm,
557+
reg_struct_return: self.sess.opts.unstable_opts.reg_struct_return,
558+
}
556559
}
557560
}
558561

‎compiler/rustc_session/messages.ftl

+1
Original file line numberDiff line numberDiff line change
@@ -135,5 +135,6 @@ session_unsupported_crate_type_for_target =
135135
136136
session_unsupported_dwarf_version = requested DWARF version {$dwarf_version} is greater than 5
137137
138+
session_unsupported_reg_struct_return_arch = `-Zreg-struct-return` is only supported on x86
138139
session_unsupported_regparm = `-Zregparm={$regparm}` is unsupported (valid values 0-3)
139140
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
@@ -489,6 +489,10 @@ pub(crate) struct UnsupportedRegparm {
489489
#[diag(session_unsupported_regparm_arch)]
490490
pub(crate) struct UnsupportedRegparmArch;
491491

492+
#[derive(Diagnostic)]
493+
#[diag(session_unsupported_reg_struct_return_arch)]
494+
pub(crate) struct UnsupportedRegStructReturnArch;
495+
492496
#[derive(Diagnostic)]
493497
#[diag(session_failed_to_create_profiler)]
494498
pub(crate) struct FailedToCreateProfiler {

‎compiler/rustc_session/src/options.rs

+3
Original file line numberDiff line numberDiff line change
@@ -1985,6 +1985,9 @@ options! {
19851985
"enable queries of the dependency graph for regression testing (default: no)"),
19861986
randomize_layout: bool = (false, parse_bool, [TRACKED],
19871987
"randomize the layout of types (default: no)"),
1988+
reg_struct_return: bool = (false, parse_bool, [TRACKED],
1989+
"On x86-32 targets, it overrides the default ABI to return small structs in registers.
1990+
It is UNSOUND to link together crates that use different values for this flag!"),
19881991
regparm: Option<u32> = (None, parse_opt_number, [TRACKED],
19891992
"On x86-32 targets, setting this to N causes the compiler to pass N arguments \
19901993
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
@@ -1305,6 +1305,11 @@ fn validate_commandline_args_with_session_available(sess: &Session) {
13051305
sess.dcx().emit_err(errors::UnsupportedRegparmArch);
13061306
}
13071307
}
1308+
if sess.opts.unstable_opts.reg_struct_return {
1309+
if sess.target.arch != "x86" {
1310+
sess.dcx().emit_err(errors::UnsupportedRegStructReturnArch);
1311+
}
1312+
}
13081313

13091314
// The code model check applies to `thunk` and `thunk-extern`, but not `thunk-inline`, so it is
13101315
// 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
@@ -661,7 +661,9 @@ impl<'a, Ty> FnAbi<'a, Ty> {
661661
}
662662
_ => (x86::Flavor::General, None),
663663
};
664-
x86::compute_abi_info(cx, self, x86::X86Options { flavor, regparm });
664+
let reg_struct_return = cx.x86_abi_opt().reg_struct_return;
665+
let opts = x86::X86Options { flavor, regparm, reg_struct_return };
666+
x86::compute_abi_info(cx, self, opts);
665667
}
666668
"x86_64" => match abi {
667669
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
@@ -14,6 +14,7 @@ pub(crate) enum Flavor {
1414
pub(crate) struct X86Options {
1515
pub flavor: Flavor,
1616
pub regparm: Option<u32>,
17+
pub reg_struct_return: bool,
1718
}
1819

1920
pub(crate) fn compute_abi_info<'a, Ty, C>(cx: &C, fn_abi: &mut FnAbi<'a, Ty>, opts: X86Options)
@@ -31,7 +32,7 @@ where
3132
// https://www.angelcode.com/dev/callconv/callconv.html
3233
// Clang's ABI handling is in lib/CodeGen/TargetInfo.cpp
3334
let t = cx.target_spec();
34-
if t.abi_return_struct_as_int {
35+
if t.abi_return_struct_as_int || opts.reg_struct_return {
3536
// According to Clang, everyone but MSVC returns single-element
3637
// float aggregates directly in a floating-point register.
3738
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
@@ -2108,6 +2108,8 @@ pub struct X86Abi {
21082108
/// On x86-32 targets, the regparm N causes the compiler to pass arguments
21092109
/// in registers EAX, EDX, and ECX instead of on the stack.
21102110
pub regparm: Option<u32>,
2111+
/// Override the default ABI to return small structs in registers
2112+
pub reg_struct_return: bool,
21112113
}
21122114

21132115
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

+206
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,206 @@
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+
//@ revisions: ENABLED DISABLED
7+
//@ add-core-stubs
8+
//@ compile-flags: --target i686-unknown-linux-gnu -O -C no-prepopulate-passes
9+
//@ [ENABLED] compile-flags: -Zreg-struct-return
10+
//@ needs-llvm-components: x86
11+
12+
#![crate_type = "lib"]
13+
#![no_std]
14+
#![no_core]
15+
#![feature(no_core, lang_items)]
16+
17+
extern crate minicore;
18+
use minicore::*;
19+
20+
#[repr(C)]
21+
pub struct Foo {
22+
x: u32,
23+
y: u32,
24+
}
25+
26+
#[repr(C)]
27+
pub struct Foo1 {
28+
x: u32,
29+
}
30+
31+
#[repr(C)]
32+
pub struct Foo2 {
33+
x: bool,
34+
y: bool,
35+
z: i16,
36+
}
37+
38+
#[repr(C)]
39+
pub struct Foo3 {
40+
x: i16,
41+
y: bool,
42+
z: bool,
43+
}
44+
45+
#[repr(C)]
46+
pub struct Foo4 {
47+
x: char,
48+
y: bool,
49+
z: u8,
50+
}
51+
52+
#[repr(C)]
53+
pub struct Foo5 {
54+
x: u32,
55+
y: u16,
56+
z: u8,
57+
a: bool,
58+
}
59+
60+
#[repr(C)]
61+
pub struct FooOversize1 {
62+
x: u32,
63+
y: u32,
64+
z: u32,
65+
}
66+
67+
#[repr(C)]
68+
pub struct FooOversize2 {
69+
f0: u16,
70+
f1: u16,
71+
f2: u16,
72+
f3: u16,
73+
f4: u16,
74+
}
75+
76+
#[repr(C)]
77+
pub struct FooFloat1 {
78+
x: f32,
79+
y: f32,
80+
}
81+
82+
#[repr(C)]
83+
pub struct FooFloat2 {
84+
x: f64,
85+
}
86+
87+
#[repr(C)]
88+
pub struct FooFloat3 {
89+
x: f32,
90+
}
91+
92+
pub mod tests {
93+
use {
94+
Foo, Foo1, Foo2, Foo3, Foo4, Foo5, FooFloat1, FooFloat2, FooFloat3, FooOversize1,
95+
FooOversize2,
96+
};
97+
98+
// ENABLED: i64 @f1()
99+
// DISABLED: void @f1(ptr {{.*}}sret
100+
#[no_mangle]
101+
pub extern "fastcall" fn f1() -> Foo {
102+
Foo { x: 1, y: 2 }
103+
}
104+
105+
// CHECK: { i32, i32 } @f2()
106+
#[no_mangle]
107+
pub extern "Rust" fn f2() -> Foo {
108+
Foo { x: 1, y: 2 }
109+
}
110+
111+
// ENABLED: i64 @f3()
112+
// DISABLED: void @f3(ptr {{.*}}sret
113+
#[no_mangle]
114+
pub extern "C" fn f3() -> Foo {
115+
Foo { x: 1, y: 2 }
116+
}
117+
118+
// ENABLED: i64 @f4()
119+
// DISABLED: void @f4(ptr {{.*}}sret
120+
#[no_mangle]
121+
pub extern "cdecl" fn f4() -> Foo {
122+
Foo { x: 1, y: 2 }
123+
}
124+
125+
// ENABLED: i64 @f5()
126+
// DISABLED: void @f5(ptr {{.*}}sret
127+
#[no_mangle]
128+
pub extern "stdcall" fn f5() -> Foo {
129+
Foo { x: 1, y: 2 }
130+
}
131+
132+
// ENABLED: i64 @f6()
133+
// DISABLED: void @f6(ptr {{.*}}sret
134+
#[no_mangle]
135+
pub extern "thiscall" fn f6() -> Foo {
136+
Foo { x: 1, y: 2 }
137+
}
138+
139+
// ENABLED: i32 @f7()
140+
// DISABLED: void @f7(ptr {{.*}}sret
141+
#[no_mangle]
142+
pub extern "C" fn f7() -> Foo1 {
143+
Foo1 { x: 1 }
144+
}
145+
146+
// ENABLED: i32 @f8()
147+
// DISABLED: void @f8(ptr {{.*}}sret
148+
#[no_mangle]
149+
pub extern "C" fn f8() -> Foo2 {
150+
Foo2 { x: true, y: false, z: 5 }
151+
}
152+
153+
// ENABLED: i32 @f9()
154+
// DISABLED: void @f9(ptr {{.*}}sret
155+
#[no_mangle]
156+
pub extern "C" fn f9() -> Foo3 {
157+
Foo3 { x: 5, y: false, z: true }
158+
}
159+
160+
// ENABLED: i64 @f10()
161+
// DISABLED: void @f10(ptr {{.*}}sret
162+
#[no_mangle]
163+
pub extern "C" fn f10() -> Foo4 {
164+
Foo4 { x: 'x', y: true, z: 170 }
165+
}
166+
167+
// ENABLED: i64 @f11()
168+
// DISABLED: void @f11(ptr {{.*}}sret
169+
#[no_mangle]
170+
pub extern "C" fn f11() -> Foo5 {
171+
Foo5 { x: 1, y: 2, z: 3, a: true }
172+
}
173+
174+
// CHECK: void @f12(ptr {{.*}}sret
175+
#[no_mangle]
176+
pub extern "C" fn f12() -> FooOversize1 {
177+
FooOversize1 { x: 1, y: 2, z: 3 }
178+
}
179+
180+
// CHECK: void @f13(ptr {{.*}}sret
181+
#[no_mangle]
182+
pub extern "C" fn f13() -> FooOversize2 {
183+
FooOversize2 { f0: 1, f1: 2, f2: 3, f3: 4, f4: 5 }
184+
}
185+
186+
// ENABLED: i64 @f14()
187+
// DISABLED: void @f14(ptr {{.*}}sret
188+
#[no_mangle]
189+
pub extern "C" fn f14() -> FooFloat1 {
190+
FooFloat1 { x: 1.0, y: 1.0 }
191+
}
192+
193+
// ENABLED: double @f15()
194+
// DISABLED: void @f15(ptr {{.*}}sret
195+
#[no_mangle]
196+
pub extern "C" fn f15() -> FooFloat2 {
197+
FooFloat2 { x: 1.0 }
198+
}
199+
200+
// ENABLED: float @f16()
201+
// DISABLED: void @f16(ptr {{.*}}sret
202+
#[no_mangle]
203+
pub extern "C" fn f16() -> FooFloat3 {
204+
FooFloat3 { x: 1.0 }
205+
}
206+
}
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)
Failed to load comments.