Skip to content

Commit f705d43

Browse files
authored
Unrolled build for rust-lang#130432
Rollup merge of rust-lang#130432 - azhogin:azhogin/regparm, r=workingjubilee,pnkfelix rust_for_linux: -Zregparm=<N> commandline flag for X86 (rust-lang#116972) Command line flag `-Zregparm=<N>` for X86 (32-bit) for rust-for-linux: rust-lang#116972 Implemented in the similar way as fastcall/vectorcall support (args are marked InReg if fit).
2 parents 1de57a5 + 37dc4ec commit f705d43

File tree

18 files changed

+350
-52
lines changed

18 files changed

+350
-52
lines changed

compiler/rustc_codegen_gcc/src/builder.rs

+7-1
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@ use rustc_middle::ty::{Instance, ParamEnv, Ty, TyCtxt};
3030
use rustc_span::Span;
3131
use rustc_span::def_id::DefId;
3232
use rustc_target::abi::call::FnAbi;
33-
use rustc_target::spec::{HasTargetSpec, HasWasmCAbiOpt, Target, WasmCAbi};
33+
use rustc_target::spec::{HasTargetSpec, HasWasmCAbiOpt, HasX86AbiOpt, Target, WasmCAbi, X86Abi};
3434

3535
use crate::common::{SignType, TypeReflection, type_is_pointer};
3636
use crate::context::CodegenCx;
@@ -2347,6 +2347,12 @@ impl<'tcx> HasWasmCAbiOpt for Builder<'_, '_, 'tcx> {
23472347
}
23482348
}
23492349

2350+
impl<'tcx> HasX86AbiOpt for Builder<'_, '_, 'tcx> {
2351+
fn x86_abi_opt(&self) -> X86Abi {
2352+
self.cx.x86_abi_opt()
2353+
}
2354+
}
2355+
23502356
pub trait ToGccComp {
23512357
fn to_gcc_comparison(&self) -> ComparisonOp;
23522358
}

compiler/rustc_codegen_gcc/src/context.rs

+9-1
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,9 @@ use rustc_session::Session;
1919
use rustc_span::source_map::respan;
2020
use rustc_span::{DUMMY_SP, Span};
2121
use rustc_target::abi::{HasDataLayout, PointeeInfo, Size, TargetDataLayout, VariantIdx};
22-
use rustc_target::spec::{HasTargetSpec, HasWasmCAbiOpt, Target, TlsModel, WasmCAbi};
22+
use rustc_target::spec::{
23+
HasTargetSpec, HasWasmCAbiOpt, HasX86AbiOpt, Target, TlsModel, WasmCAbi, X86Abi,
24+
};
2325

2426
use crate::callee::get_fn;
2527
use crate::common::SignType;
@@ -538,6 +540,12 @@ impl<'gcc, 'tcx> HasWasmCAbiOpt for CodegenCx<'gcc, 'tcx> {
538540
}
539541
}
540542

543+
impl<'gcc, 'tcx> HasX86AbiOpt for CodegenCx<'gcc, 'tcx> {
544+
fn x86_abi_opt(&self) -> X86Abi {
545+
X86Abi { regparm: self.tcx.sess.opts.unstable_opts.regparm }
546+
}
547+
}
548+
541549
impl<'gcc, 'tcx> LayoutOfHelpers<'tcx> for CodegenCx<'gcc, 'tcx> {
542550
#[inline]
543551
fn handle_layout_err(&self, err: LayoutError<'tcx>, span: Span, ty: Ty<'tcx>) -> ! {

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!(regparm, Some(3));
839840
tracked!(relax_elf_relocations, Some(true));
840841
tracked!(remap_cwd_prefix, Some(PathBuf::from("abc")));
841842
tracked!(sanitizer, SanitizerSet::ADDRESS);

compiler/rustc_middle/src/ty/layout.rs

+15-1
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,9 @@ use rustc_span::{DUMMY_SP, ErrorGuaranteed, Span};
2121
use rustc_target::abi::call::FnAbi;
2222
use rustc_target::abi::{FieldIdx, TyAbiInterface, VariantIdx, call};
2323
use rustc_target::spec::abi::Abi as SpecAbi;
24-
use rustc_target::spec::{HasTargetSpec, HasWasmCAbiOpt, PanicStrategy, Target, WasmCAbi};
24+
use rustc_target::spec::{
25+
HasTargetSpec, HasWasmCAbiOpt, HasX86AbiOpt, PanicStrategy, Target, WasmCAbi, X86Abi,
26+
};
2527
use tracing::debug;
2628
use {rustc_abi as abi, rustc_hir as hir};
2729

@@ -544,6 +546,12 @@ impl<'tcx> HasWasmCAbiOpt for TyCtxt<'tcx> {
544546
}
545547
}
546548

549+
impl<'tcx> HasX86AbiOpt for TyCtxt<'tcx> {
550+
fn x86_abi_opt(&self) -> X86Abi {
551+
X86Abi { regparm: self.sess.opts.unstable_opts.regparm }
552+
}
553+
}
554+
547555
impl<'tcx> HasTyCtxt<'tcx> for TyCtxt<'tcx> {
548556
#[inline]
549557
fn tcx(&self) -> TyCtxt<'tcx> {
@@ -595,6 +603,12 @@ impl<'tcx> HasWasmCAbiOpt for LayoutCx<'tcx> {
595603
}
596604
}
597605

606+
impl<'tcx> HasX86AbiOpt for LayoutCx<'tcx> {
607+
fn x86_abi_opt(&self) -> X86Abi {
608+
self.calc.cx.x86_abi_opt()
609+
}
610+
}
611+
598612
impl<'tcx> HasTyCtxt<'tcx> for LayoutCx<'tcx> {
599613
fn tcx(&self) -> TyCtxt<'tcx> {
600614
self.calc.cx

compiler/rustc_session/messages.ftl

+3
Original file line numberDiff line numberDiff line change
@@ -136,3 +136,6 @@ session_unsupported_crate_type_for_target =
136136
dropping unsupported crate type `{$crate_type}` for target `{$target_triple}`
137137
138138
session_unsupported_dwarf_version = requested DWARF version {$dwarf_version} is greater than 5
139+
140+
session_unsupported_regparm = `-Zregparm={$regparm}` is unsupported (valid values 0-3)
141+
session_unsupported_regparm_arch = `-Zregparm=N` is only supported on x86

compiler/rustc_session/src/errors.rs

+10
Original file line numberDiff line numberDiff line change
@@ -485,6 +485,16 @@ pub(crate) struct FunctionReturnRequiresX86OrX8664;
485485
#[diag(session_function_return_thunk_extern_requires_non_large_code_model)]
486486
pub(crate) struct FunctionReturnThunkExternRequiresNonLargeCodeModel;
487487

488+
#[derive(Diagnostic)]
489+
#[diag(session_unsupported_regparm)]
490+
pub(crate) struct UnsupportedRegparm {
491+
pub(crate) regparm: u32,
492+
}
493+
494+
#[derive(Diagnostic)]
495+
#[diag(session_unsupported_regparm_arch)]
496+
pub(crate) struct UnsupportedRegparmArch;
497+
488498
#[derive(Diagnostic)]
489499
#[diag(session_failed_to_create_profiler)]
490500
pub(crate) struct FailedToCreateProfiler {

compiler/rustc_session/src/options.rs

+5
Original file line numberDiff line numberDiff line change
@@ -2000,6 +2000,11 @@ 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+
regparm: Option<u32> = (None, parse_opt_number, [TRACKED],
2004+
"On x86-32 targets, setting this to N causes the compiler to pass N arguments \
2005+
in registers EAX, EDX, and ECX instead of on the stack for\
2006+
\"C\", \"cdecl\", and \"stdcall\" fn.\
2007+
It is UNSOUND to link together crates that use different values for this flag!"),
20032008
relax_elf_relocations: Option<bool> = (None, parse_opt_bool, [TRACKED],
20042009
"whether ELF relocations can be relaxed"),
20052010
remap_cwd_prefix: Option<PathBuf> = (None, parse_opt_pathbuf, [TRACKED],

compiler/rustc_session/src/session.rs

+9
Original file line numberDiff line numberDiff line change
@@ -1337,6 +1337,15 @@ fn validate_commandline_args_with_session_available(sess: &Session) {
13371337
}
13381338
}
13391339

1340+
if let Some(regparm) = sess.opts.unstable_opts.regparm {
1341+
if regparm > 3 {
1342+
sess.dcx().emit_err(errors::UnsupportedRegparm { regparm });
1343+
}
1344+
if sess.target.arch != "x86" {
1345+
sess.dcx().emit_err(errors::UnsupportedRegparmArch);
1346+
}
1347+
}
1348+
13401349
// The code model check applies to `thunk` and `thunk-extern`, but not `thunk-inline`, so it is
13411350
// kept as a `match` to force a change if new ones are added, even if we currently only support
13421351
// `thunk-extern` like Clang.

compiler/rustc_target/src/callconv/mod.rs

+13-9
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ use rustc_macros::HashStable_Generic;
66
use rustc_span::Symbol;
77

88
use crate::abi::{self, Abi, Align, HasDataLayout, Size, TyAbiInterface, TyAndLayout};
9-
use crate::spec::{self, HasTargetSpec, HasWasmCAbiOpt, WasmCAbi};
9+
use crate::spec::{self, HasTargetSpec, HasWasmCAbiOpt, HasX86AbiOpt, WasmCAbi};
1010

1111
mod aarch64;
1212
mod amdgpu;
@@ -631,7 +631,7 @@ impl<'a, Ty> FnAbi<'a, Ty> {
631631
) -> Result<(), AdjustForForeignAbiError>
632632
where
633633
Ty: TyAbiInterface<'a, C> + Copy,
634-
C: HasDataLayout + HasTargetSpec + HasWasmCAbiOpt,
634+
C: HasDataLayout + HasTargetSpec + HasWasmCAbiOpt + HasX86AbiOpt,
635635
{
636636
if abi == spec::abi::Abi::X86Interrupt {
637637
if let Some(arg) = self.args.first_mut() {
@@ -643,14 +643,18 @@ impl<'a, Ty> FnAbi<'a, Ty> {
643643
let spec = cx.target_spec();
644644
match &spec.arch[..] {
645645
"x86" => {
646-
let flavor = if let spec::abi::Abi::Fastcall { .. }
647-
| spec::abi::Abi::Vectorcall { .. } = abi
648-
{
649-
x86::Flavor::FastcallOrVectorcall
650-
} else {
651-
x86::Flavor::General
646+
let (flavor, regparm) = match abi {
647+
spec::abi::Abi::Fastcall { .. } | spec::abi::Abi::Vectorcall { .. } => {
648+
(x86::Flavor::FastcallOrVectorcall, None)
649+
}
650+
spec::abi::Abi::C { .. }
651+
| spec::abi::Abi::Cdecl { .. }
652+
| spec::abi::Abi::Stdcall { .. } => {
653+
(x86::Flavor::General, cx.x86_abi_opt().regparm)
654+
}
655+
_ => (x86::Flavor::General, None),
652656
};
653-
x86::compute_abi_info(cx, self, flavor);
657+
x86::compute_abi_info(cx, self, x86::X86Options { flavor, regparm });
654658
}
655659
"x86_64" => match abi {
656660
spec::abi::Abi::SysV64 { .. } => x86_64::compute_abi_info(cx, self),

compiler/rustc_target/src/callconv/x86.rs

+64-40
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,12 @@ pub(crate) enum Flavor {
88
FastcallOrVectorcall,
99
}
1010

11-
pub(crate) fn compute_abi_info<'a, Ty, C>(cx: &C, fn_abi: &mut FnAbi<'a, Ty>, flavor: Flavor)
11+
pub(crate) struct X86Options {
12+
pub flavor: Flavor,
13+
pub regparm: Option<u32>,
14+
}
15+
16+
pub(crate) fn compute_abi_info<'a, Ty, C>(cx: &C, fn_abi: &mut FnAbi<'a, Ty>, opts: X86Options)
1217
where
1318
Ty: TyAbiInterface<'a, C> + Copy,
1419
C: HasDataLayout + HasTargetSpec,
@@ -128,58 +133,77 @@ where
128133
}
129134
}
130135

131-
if flavor == Flavor::FastcallOrVectorcall {
132-
// Mark arguments as InReg like clang does it,
133-
// so our fastcall/vectorcall is compatible with C/C++ fastcall/vectorcall.
136+
fill_inregs(cx, fn_abi, opts, false);
137+
}
134138

135-
// Clang reference: lib/CodeGen/TargetInfo.cpp
136-
// See X86_32ABIInfo::shouldPrimitiveUseInReg(), X86_32ABIInfo::updateFreeRegs()
139+
pub(crate) fn fill_inregs<'a, Ty, C>(
140+
cx: &C,
141+
fn_abi: &mut FnAbi<'a, Ty>,
142+
opts: X86Options,
143+
rust_abi: bool,
144+
) where
145+
Ty: TyAbiInterface<'a, C> + Copy,
146+
{
147+
if opts.flavor != Flavor::FastcallOrVectorcall && opts.regparm.is_none_or(|x| x == 0) {
148+
return;
149+
}
150+
// Mark arguments as InReg like clang does it,
151+
// so our fastcall/vectorcall is compatible with C/C++ fastcall/vectorcall.
137152

138-
// IsSoftFloatABI is only set to true on ARM platforms,
139-
// which in turn can't be x86?
153+
// Clang reference: lib/CodeGen/TargetInfo.cpp
154+
// See X86_32ABIInfo::shouldPrimitiveUseInReg(), X86_32ABIInfo::updateFreeRegs()
140155

141-
let mut free_regs = 2;
156+
// IsSoftFloatABI is only set to true on ARM platforms,
157+
// which in turn can't be x86?
142158

143-
for arg in fn_abi.args.iter_mut() {
144-
let attrs = match arg.mode {
145-
PassMode::Ignore
146-
| PassMode::Indirect { attrs: _, meta_attrs: None, on_stack: _ } => {
147-
continue;
148-
}
149-
PassMode::Direct(ref mut attrs) => attrs,
150-
PassMode::Pair(..)
151-
| PassMode::Indirect { attrs: _, meta_attrs: Some(_), on_stack: _ }
152-
| PassMode::Cast { .. } => {
153-
unreachable!("x86 shouldn't be passing arguments by {:?}", arg.mode)
154-
}
155-
};
159+
// 2 for fastcall/vectorcall, regparm limited by 3 otherwise
160+
let mut free_regs = opts.regparm.unwrap_or(2).into();
161+
162+
// For types generating PassMode::Cast, InRegs will not be set.
163+
// Maybe, this is a FIXME
164+
let has_casts = fn_abi.args.iter().any(|arg| matches!(arg.mode, PassMode::Cast { .. }));
165+
if has_casts && rust_abi {
166+
return;
167+
}
156168

157-
// At this point we know this must be a primitive of sorts.
158-
let unit = arg.layout.homogeneous_aggregate(cx).unwrap().unit().unwrap();
159-
assert_eq!(unit.size, arg.layout.size);
160-
if unit.kind == RegKind::Float {
169+
for arg in fn_abi.args.iter_mut() {
170+
let attrs = match arg.mode {
171+
PassMode::Ignore | PassMode::Indirect { attrs: _, meta_attrs: None, on_stack: _ } => {
161172
continue;
162173
}
174+
PassMode::Direct(ref mut attrs) => attrs,
175+
PassMode::Pair(..)
176+
| PassMode::Indirect { attrs: _, meta_attrs: Some(_), on_stack: _ }
177+
| PassMode::Cast { .. } => {
178+
unreachable!("x86 shouldn't be passing arguments by {:?}", arg.mode)
179+
}
180+
};
163181

164-
let size_in_regs = (arg.layout.size.bits() + 31) / 32;
182+
// At this point we know this must be a primitive of sorts.
183+
let unit = arg.layout.homogeneous_aggregate(cx).unwrap().unit().unwrap();
184+
assert_eq!(unit.size, arg.layout.size);
185+
if matches!(unit.kind, RegKind::Float | RegKind::Vector) {
186+
continue;
187+
}
165188

166-
if size_in_regs == 0 {
167-
continue;
168-
}
189+
let size_in_regs = (arg.layout.size.bits() + 31) / 32;
169190

170-
if size_in_regs > free_regs {
171-
break;
172-
}
191+
if size_in_regs == 0 {
192+
continue;
193+
}
173194

174-
free_regs -= size_in_regs;
195+
if size_in_regs > free_regs {
196+
break;
197+
}
175198

176-
if arg.layout.size.bits() <= 32 && unit.kind == RegKind::Integer {
177-
attrs.set(ArgAttribute::InReg);
178-
}
199+
free_regs -= size_in_regs;
179200

180-
if free_regs == 0 {
181-
break;
182-
}
201+
if arg.layout.size.bits() <= 32 && unit.kind == RegKind::Integer {
202+
attrs.set(ArgAttribute::InReg);
203+
}
204+
205+
if free_regs == 0 {
206+
break;
183207
}
184208
}
185209
}

compiler/rustc_target/src/spec/mod.rs

+12
Original file line numberDiff line numberDiff line change
@@ -2096,6 +2096,18 @@ pub trait HasWasmCAbiOpt {
20962096
fn wasm_c_abi_opt(&self) -> WasmCAbi;
20972097
}
20982098

2099+
/// x86 (32-bit) abi options.
2100+
#[derive(Debug, Copy, Clone, Hash, PartialEq, Eq)]
2101+
pub struct X86Abi {
2102+
/// On x86-32 targets, the regparm N causes the compiler to pass arguments
2103+
/// in registers EAX, EDX, and ECX instead of on the stack.
2104+
pub regparm: Option<u32>,
2105+
}
2106+
2107+
pub trait HasX86AbiOpt {
2108+
fn x86_abi_opt(&self) -> X86Abi;
2109+
}
2110+
20992111
type StaticCow<T> = Cow<'static, T>;
21002112

21012113
/// Optional aspects of a target specification.
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
# `regparm`
2+
3+
The tracking issue for this feature is: https://github.com/rust-lang/rust/issues/131749.
4+
5+
------------------------
6+
7+
Option -Zregparm=N causes the compiler to pass N arguments
8+
in registers EAX, EDX, and ECX instead of on the stack for "C", "cdecl", and "stdcall" fn.
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 `-mregparm`.
13+
14+
Supported values for this option are 0-3.
15+
16+
[Clang]: https://clang.llvm.org/docs/ClangCommandLineReference.html#cmdoption-clang-mregparm
17+
[GCC]: https://gcc.gnu.org/onlinedocs/gcc/x86-Function-Attributes.html#index-regparm-function-attribute_002c-x86
18+
19+
Implementation details:
20+
For eligible arguments, llvm `inreg` attribute is set.

0 commit comments

Comments
 (0)