Skip to content

Commit dff5a6d

Browse files
committed
rust_for_linux: -Zregparm=<N> commandline flag for X86 (rust-lang#116972)
1 parent c8dff28 commit dff5a6d

File tree

10 files changed

+232
-52
lines changed

10 files changed

+232
-52
lines changed

compiler/rustc_codegen_gcc/src/builder.rs

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@ use rustc_span::def_id::DefId;
3030
use rustc_span::Span;
3131
use rustc_target::abi::call::FnAbi;
3232
use rustc_target::abi::{self, Align, HasDataLayout, Size, TargetDataLayout, WrappingRange};
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::{type_is_pointer, SignType, TypeReflection};
3636
use crate::context::CodegenCx;
@@ -2359,6 +2359,12 @@ impl<'tcx> HasWasmCAbiOpt for Builder<'_, '_, 'tcx> {
23592359
}
23602360
}
23612361

2362+
impl<'tcx> HasX86AbiOpt for Builder<'_, '_, 'tcx> {
2363+
fn x86_abi_opt(&self) -> X86Abi {
2364+
self.cx.x86_abi_opt()
2365+
}
2366+
}
2367+
23622368
pub trait ToGccComp {
23632369
fn to_gcc_comparison(&self) -> ComparisonOp;
23642370
}

compiler/rustc_codegen_gcc/src/context.rs

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,9 @@ use rustc_span::source_map::respan;
2020
use rustc_span::{Span, DUMMY_SP};
2121
use rustc_target::abi::call::FnAbi;
2222
use rustc_target::abi::{HasDataLayout, PointeeInfo, Size, TargetDataLayout, VariantIdx};
23-
use rustc_target::spec::{HasTargetSpec, HasWasmCAbiOpt, Target, TlsModel, WasmCAbi};
23+
use rustc_target::spec::{
24+
HasTargetSpec, HasWasmCAbiOpt, HasX86AbiOpt, Target, TlsModel, WasmCAbi, X86Abi,
25+
};
2426

2527
use crate::callee::get_fn;
2628
use crate::common::SignType;
@@ -571,6 +573,12 @@ impl<'gcc, 'tcx> HasWasmCAbiOpt for CodegenCx<'gcc, 'tcx> {
571573
}
572574
}
573575

576+
impl<'gcc, 'tcx> HasX86AbiOpt for CodegenCx<'gcc, 'tcx> {
577+
fn x86_abi_opt(&self) -> X86Abi {
578+
X86Abi { regparm: self.tcx.sess.opts.unstable_opts.regparm }
579+
}
580+
}
581+
574582
impl<'gcc, 'tcx> LayoutOfHelpers<'tcx> for CodegenCx<'gcc, 'tcx> {
575583
type LayoutOfResult = TyAndLayout<'tcx>;
576584

compiler/rustc_interface/src/tests.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -834,6 +834,7 @@ fn test_unstable_options_tracking_hash() {
834834
tracked!(profile_emit, Some(PathBuf::from("abc")));
835835
tracked!(profile_sample_use, Some(PathBuf::from("abc")));
836836
tracked!(profiler_runtime, "abc".to_string());
837+
tracked!(regparm, Some(3));
837838
tracked!(relax_elf_relocations, Some(true));
838839
tracked!(remap_cwd_prefix, Some(PathBuf::from("abc")));
839840
tracked!(sanitizer, SanitizerSet::ADDRESS);

compiler/rustc_middle/src/ty/layout.rs

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,9 @@ use rustc_span::{ErrorGuaranteed, Span, DUMMY_SP};
1717
use rustc_target::abi::call::FnAbi;
1818
use rustc_target::abi::*;
1919
use rustc_target::spec::abi::Abi as SpecAbi;
20-
use rustc_target::spec::{HasTargetSpec, HasWasmCAbiOpt, PanicStrategy, Target, WasmCAbi};
20+
use rustc_target::spec::{
21+
HasTargetSpec, HasWasmCAbiOpt, HasX86AbiOpt, PanicStrategy, Target, WasmCAbi, X86Abi,
22+
};
2123
use tracing::debug;
2224

2325
use crate::error::UnsupportedFnAbi;
@@ -534,6 +536,12 @@ impl<'tcx> HasWasmCAbiOpt for TyCtxt<'tcx> {
534536
}
535537
}
536538

539+
impl<'tcx> HasX86AbiOpt for TyCtxt<'tcx> {
540+
fn x86_abi_opt(&self) -> X86Abi {
541+
X86Abi { regparm: self.sess.opts.unstable_opts.regparm }
542+
}
543+
}
544+
537545
impl<'tcx> HasTyCtxt<'tcx> for TyCtxt<'tcx> {
538546
#[inline]
539547
fn tcx(&self) -> TyCtxt<'tcx> {
@@ -585,6 +593,12 @@ impl<'tcx> HasWasmCAbiOpt for LayoutCx<'tcx> {
585593
}
586594
}
587595

596+
impl<'tcx> HasX86AbiOpt for LayoutCx<'tcx> {
597+
fn x86_abi_opt(&self) -> X86Abi {
598+
self.calc.cx.x86_abi_opt()
599+
}
600+
}
601+
588602
impl<'tcx> HasTyCtxt<'tcx> for LayoutCx<'tcx> {
589603
fn tcx(&self) -> TyCtxt<'tcx> {
590604
self.calc.cx

compiler/rustc_session/src/options.rs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1978,6 +1978,10 @@ options! {
19781978
"enable queries of the dependency graph for regression testing (default: no)"),
19791979
randomize_layout: bool = (false, parse_bool, [TRACKED],
19801980
"randomize the layout of types (default: no)"),
1981+
regparm: Option<u32> = (None, parse_opt_number, [TRACKED],
1982+
"On x86-32 targets, setting this to N causes the compiler to pass N arguments \
1983+
in registers EAX, EDX, and ECX instead of on the stack.\
1984+
It is UNSOUND to link together crates that use different values for this flag!"),
19811985
relax_elf_relocations: Option<bool> = (None, parse_opt_bool, [TRACKED],
19821986
"whether ELF relocations can be relaxed"),
19831987
remap_cwd_prefix: Option<PathBuf> = (None, parse_opt_pathbuf, [TRACKED],

compiler/rustc_target/src/abi/call/mod.rs

Lines changed: 34 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ use rustc_macros::HashStable_Generic;
55
use rustc_span::Symbol;
66

77
use crate::abi::{self, Abi, Align, FieldsShape, HasDataLayout, Size, TyAbiInterface, TyAndLayout};
8-
use crate::spec::{self, HasTargetSpec, HasWasmCAbiOpt, WasmCAbi};
8+
use crate::spec::{self, HasTargetSpec, HasWasmCAbiOpt, HasX86AbiOpt, WasmCAbi};
99

1010
mod aarch64;
1111
mod amdgpu;
@@ -875,7 +875,7 @@ impl<'a, Ty> FnAbi<'a, Ty> {
875875
) -> Result<(), AdjustForForeignAbiError>
876876
where
877877
Ty: TyAbiInterface<'a, C> + Copy,
878-
C: HasDataLayout + HasTargetSpec + HasWasmCAbiOpt,
878+
C: HasDataLayout + HasTargetSpec + HasWasmCAbiOpt + HasX86AbiOpt,
879879
{
880880
if abi == spec::abi::Abi::X86Interrupt {
881881
if let Some(arg) = self.args.first_mut() {
@@ -888,14 +888,18 @@ impl<'a, Ty> FnAbi<'a, Ty> {
888888
let spec = cx.target_spec();
889889
match &spec.arch[..] {
890890
"x86" => {
891-
let flavor = if let spec::abi::Abi::Fastcall { .. }
892-
| spec::abi::Abi::Vectorcall { .. } = abi
893-
{
894-
x86::Flavor::FastcallOrVectorcall
895-
} else {
896-
x86::Flavor::General
891+
let (flavor, regparm) = match abi {
892+
spec::abi::Abi::Fastcall { .. } | spec::abi::Abi::Vectorcall { .. } => {
893+
(x86::Flavor::FastcallOrVectorcall, None)
894+
}
895+
spec::abi::Abi::C { .. }
896+
| spec::abi::Abi::Cdecl { .. }
897+
| spec::abi::Abi::Stdcall { .. } => {
898+
(x86::Flavor::General, cx.x86_abi_opt().regparm)
899+
}
900+
_ => (x86::Flavor::General, None),
897901
};
898-
x86::compute_abi_info(cx, self, flavor);
902+
x86::compute_abi_info(cx, self, x86::X86Options { flavor, regparm });
899903
}
900904
"x86_64" => match abi {
901905
spec::abi::Abi::SysV64 { .. } => x86_64::compute_abi_info(cx, self),
@@ -961,6 +965,27 @@ impl<'a, Ty> FnAbi<'a, Ty> {
961965

962966
Ok(())
963967
}
968+
969+
pub fn fill_inregs_for_rust_abi<C>(&mut self, cx: &C)
970+
where
971+
Ty: TyAbiInterface<'a, C> + Copy,
972+
C: HasTargetSpec + HasX86AbiOpt,
973+
{
974+
let spec = cx.target_spec();
975+
match &spec.arch[..] {
976+
"x86" => {
977+
x86::fill_inregs(
978+
cx,
979+
self,
980+
x86::X86Options {
981+
flavor: x86::Flavor::General,
982+
regparm: cx.x86_abi_opt().regparm,
983+
},
984+
);
985+
}
986+
_ => {}
987+
}
988+
}
964989
}
965990

966991
impl FromStr for Conv {

compiler/rustc_target/src/abi/call/x86.rs

Lines changed: 53 additions & 40 deletions
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,66 @@ 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);
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>(cx: &C, fn_abi: &mut FnAbi<'a, Ty>, opts: X86Options)
140+
where
141+
Ty: TyAbiInterface<'a, C> + Copy,
142+
{
143+
if opts.flavor != Flavor::FastcallOrVectorcall && !opts.regparm.is_some_and(|x| x > 0) {
144+
return;
145+
}
146+
// Mark arguments as InReg like clang does it,
147+
// so our fastcall/vectorcall is compatible with C/C++ fastcall/vectorcall.
137148

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

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

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-
};
155+
// 2 for fastcall/vectorcall, regparm limited by 3 otherwise
156+
let mut free_regs = opts.regparm.unwrap_or(2).into();
156157

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 {
158+
for arg in fn_abi.args.iter_mut() {
159+
let attrs = match arg.mode {
160+
PassMode::Ignore | PassMode::Indirect { attrs: _, meta_attrs: None, on_stack: _ } => {
161161
continue;
162162
}
163+
PassMode::Direct(ref mut attrs) => attrs,
164+
PassMode::Pair(..)
165+
| PassMode::Indirect { attrs: _, meta_attrs: Some(_), on_stack: _ }
166+
| PassMode::Cast { .. } => {
167+
unreachable!("x86 shouldn't be passing arguments by {:?}", arg.mode)
168+
}
169+
};
163170

164-
let size_in_regs = (arg.layout.size.bits() + 31) / 32;
171+
// At this point we know this must be a primitive of sorts.
172+
let unit = arg.layout.homogeneous_aggregate(cx).unwrap().unit().unwrap();
173+
assert_eq!(unit.size, arg.layout.size);
174+
if unit.kind == RegKind::Float {
175+
continue;
176+
}
165177

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

170-
if size_in_regs > free_regs {
171-
break;
172-
}
180+
if size_in_regs == 0 {
181+
continue;
182+
}
173183

174-
free_regs -= size_in_regs;
184+
if size_in_regs > free_regs {
185+
break;
186+
}
175187

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

180-
if free_regs == 0 {
181-
break;
182-
}
190+
if arg.layout.size.bits() <= 32 && unit.kind == RegKind::Integer {
191+
attrs.set(ArgAttribute::InReg);
192+
}
193+
194+
if free_regs == 0 {
195+
break;
183196
}
184197
}
185198
}

compiler/rustc_target/src/spec/mod.rs

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2050,6 +2050,18 @@ pub trait HasWasmCAbiOpt {
20502050
fn wasm_c_abi_opt(&self) -> WasmCAbi;
20512051
}
20522052

2053+
/// x86 (32-bit) abi options.
2054+
#[derive(Debug, Copy, Clone, Hash, PartialEq, Eq)]
2055+
pub struct X86Abi {
2056+
/// On x86-32 targets, the regparm N causes the compiler to pass arguments
2057+
/// in registers EAX, EDX, and ECX instead of on the stack.
2058+
pub regparm: Option<u32>,
2059+
}
2060+
2061+
pub trait HasX86AbiOpt {
2062+
fn x86_abi_opt(&self) -> X86Abi;
2063+
}
2064+
20532065
type StaticCow<T> = Cow<'static, T>;
20542066

20552067
/// Optional aspects of a target specification.

compiler/rustc_ty_utils/src/abi.rs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -794,6 +794,9 @@ fn fn_abi_adjust_for_abi<'tcx>(
794794
for (arg_idx, arg) in fn_abi.args.iter_mut().enumerate() {
795795
fixup(arg, Some(arg_idx));
796796
}
797+
if tcx.sess.target.arch == "x86" {
798+
fn_abi.fill_inregs_for_rust_abi(cx);
799+
}
797800
} else {
798801
fn_abi
799802
.adjust_for_foreign_abi(cx, abi)

0 commit comments

Comments
 (0)