Skip to content

Commit f3284dc

Browse files
committed
Auto merge of #115260 - scottmcm:not-quite-so-cold, r=WaffleLapkin
Use `preserve_mostcc` for `extern "rust-cold"` As experimentation in #115242 has shown looks better than `coldcc`. Notably, clang exposes `preserve_most` (https://clang.llvm.org/docs/AttributeReference.html#preserve-most) but not `cold`, so this change should put us on a better-supported path. And *don't* use a different convention for cold on Windows, because that actually ends up making things worse. (See comment in the code.) cc tracking issue #97544
2 parents fef2f59 + 754f488 commit f3284dc

File tree

9 files changed

+71
-23
lines changed

9 files changed

+71
-23
lines changed

compiler/rustc_codegen_cranelift/src/abi/mod.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,7 @@ fn clif_sig_from_fn_abi<'tcx>(
3939
pub(crate) fn conv_to_call_conv(sess: &Session, c: Conv, default_call_conv: CallConv) -> CallConv {
4040
match c {
4141
Conv::Rust | Conv::C => default_call_conv,
42-
Conv::RustCold => CallConv::Cold,
42+
Conv::Cold | Conv::PreserveMost | Conv::PreserveAll => CallConv::Cold,
4343
Conv::X86_64SysV => CallConv::SystemV,
4444
Conv::X86_64Win64 => CallConv::WindowsFastcall,
4545

compiler/rustc_codegen_llvm/src/abi.rs

+3-1
Original file line numberDiff line numberDiff line change
@@ -571,7 +571,9 @@ impl From<Conv> for llvm::CallConv {
571571
Conv::C | Conv::Rust | Conv::CCmseNonSecureCall | Conv::RiscvInterrupt { .. } => {
572572
llvm::CCallConv
573573
}
574-
Conv::RustCold => llvm::ColdCallConv,
574+
Conv::Cold => llvm::ColdCallConv,
575+
Conv::PreserveMost => llvm::PreserveMost,
576+
Conv::PreserveAll => llvm::PreserveAll,
575577
Conv::AmdGpuKernel => llvm::AmdGpuKernel,
576578
Conv::AvrInterrupt => llvm::AvrInterrupt,
577579
Conv::AvrNonBlockingInterrupt => llvm::AvrNonBlockingInterrupt,

compiler/rustc_codegen_llvm/src/llvm/ffi.rs

+5
Original file line numberDiff line numberDiff line change
@@ -83,12 +83,17 @@ pub enum LLVMModFlagBehavior {
8383
// Consts for the LLVM CallConv type, pre-cast to usize.
8484

8585
/// LLVM CallingConv::ID. Should we wrap this?
86+
///
87+
/// See <https://github.com/llvm/llvm-project/blob/main/llvm/include/llvm/IR/CallingConv.h>
8688
#[derive(Copy, Clone, PartialEq, Debug)]
8789
#[repr(C)]
8890
pub enum CallConv {
8991
CCallConv = 0,
9092
FastCallConv = 8,
9193
ColdCallConv = 9,
94+
PreserveMost = 14,
95+
PreserveAll = 15,
96+
Tail = 18,
9297
X86StdcallCallConv = 64,
9398
X86FastcallCallConv = 65,
9499
ArmAapcsCallConv = 67,

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

+4-7
Original file line numberDiff line numberDiff line change
@@ -579,10 +579,9 @@ pub enum Conv {
579579
C,
580580
Rust,
581581

582-
/// For things unlikely to be called, where smaller caller codegen is
583-
/// preferred over raw speed.
584-
/// Stronger than just `#[cold]` because `fn` pointers might be incompatible.
585-
RustCold,
582+
Cold,
583+
PreserveMost,
584+
PreserveAll,
586585

587586
// Target-specific calling conventions.
588587
ArmAapcs,
@@ -605,9 +604,7 @@ pub enum Conv {
605604
AvrInterrupt,
606605
AvrNonBlockingInterrupt,
607606

608-
RiscvInterrupt {
609-
kind: RiscvInterruptKind,
610-
},
607+
RiscvInterrupt { kind: RiscvInterruptKind },
611608
}
612609

613610
#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug, HashStable_Generic)]

compiler/rustc_target/src/json.rs

+3-1
Original file line numberDiff line numberDiff line change
@@ -96,7 +96,9 @@ impl ToJson for crate::abi::call::Conv {
9696
let s = match self {
9797
Self::C => "C",
9898
Self::Rust => "Rust",
99-
Self::RustCold => "RustCold",
99+
Self::Cold => "Cold",
100+
Self::PreserveMost => "PreserveMost",
101+
Self::PreserveAll => "PreserveAll",
100102
Self::ArmAapcs => "ArmAapcs",
101103
Self::CCmseNonSecureCall => "CCmseNonSecureCall",
102104
Self::Msp430Intr => "Msp430Intr",

compiler/rustc_target/src/spec/abi.rs

+33-10
Original file line numberDiff line numberDiff line change
@@ -14,15 +14,33 @@ pub enum Abi {
1414
// hashing tests. These are used in many places, so giving them stable values reduces test
1515
// churn. The specific values are meaningless.
1616
Rust,
17-
C { unwind: bool },
18-
Cdecl { unwind: bool },
19-
Stdcall { unwind: bool },
20-
Fastcall { unwind: bool },
21-
Vectorcall { unwind: bool },
22-
Thiscall { unwind: bool },
23-
Aapcs { unwind: bool },
24-
Win64 { unwind: bool },
25-
SysV64 { unwind: bool },
17+
C {
18+
unwind: bool,
19+
},
20+
Cdecl {
21+
unwind: bool,
22+
},
23+
Stdcall {
24+
unwind: bool,
25+
},
26+
Fastcall {
27+
unwind: bool,
28+
},
29+
Vectorcall {
30+
unwind: bool,
31+
},
32+
Thiscall {
33+
unwind: bool,
34+
},
35+
Aapcs {
36+
unwind: bool,
37+
},
38+
Win64 {
39+
unwind: bool,
40+
},
41+
SysV64 {
42+
unwind: bool,
43+
},
2644
PtxKernel,
2745
Msp430Interrupt,
2846
X86Interrupt,
@@ -32,11 +50,16 @@ pub enum Abi {
3250
AvrNonBlockingInterrupt,
3351
CCmseNonSecureCall,
3452
Wasm,
35-
System { unwind: bool },
53+
System {
54+
unwind: bool,
55+
},
3656
RustIntrinsic,
3757
RustCall,
3858
PlatformIntrinsic,
3959
Unadjusted,
60+
/// For things unlikely to be called, where reducing register pressure in
61+
/// `extern "Rust"` callers is worth paying extra cost in the callee.
62+
/// Stronger than just `#[cold]` because `fn` pointers might be incompatible.
4063
RustCold,
4164
RiscvInterruptM,
4265
RiscvInterruptS,

compiler/rustc_target/src/spec/mod.rs

+7
Original file line numberDiff line numberDiff line change
@@ -2276,6 +2276,13 @@ impl Target {
22762276
Abi::Vectorcall { .. } if ["x86", "x86_64"].contains(&&self.arch[..]) => abi,
22772277
Abi::Fastcall { unwind } | Abi::Vectorcall { unwind } => Abi::C { unwind },
22782278

2279+
// The Windows x64 calling convention we use for `extern "Rust"`
2280+
// <https://learn.microsoft.com/en-us/cpp/build/x64-software-conventions#register-volatility-and-preservation>
2281+
// expects the callee to save `xmm6` through `xmm15`, but `PreserveMost`
2282+
// (that we use by default for `extern "rust-cold"`) doesn't save any of those.
2283+
// So to avoid bloating callers, just use the Rust convention here.
2284+
Abi::RustCold if self.is_like_windows && self.arch == "x86_64" => Abi::Rust,
2285+
22792286
abi => abi,
22802287
}
22812288
}

compiler/rustc_ty_utils/src/abi.rs

+4-1
Original file line numberDiff line numberDiff line change
@@ -172,7 +172,10 @@ fn conv_from_spec_abi(tcx: TyCtxt<'_>, abi: SpecAbi) -> Conv {
172172
use rustc_target::spec::abi::Abi::*;
173173
match tcx.sess.target.adjust_abi(abi) {
174174
RustIntrinsic | PlatformIntrinsic | Rust | RustCall => Conv::Rust,
175-
RustCold => Conv::RustCold,
175+
176+
// This is intentionally not using `Conv::Cold`, as that has to preserve
177+
// even SIMD registers, which is generally not a good trade-off.
178+
RustCold => Conv::PreserveMost,
176179

177180
// It's the ABI's job to select this, not ours.
178181
System { .. } => bug!("system abi should be selected elsewhere"),

tests/codegen/cold-call-declare-and-call.rs

+11-2
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,21 @@
1+
// revisions: NORMAL WINDOWS
12
// compile-flags: -C no-prepopulate-passes
3+
//[NORMAL] ignore-windows
4+
//[WINDOWS] only-windows
5+
//[WINDOWS] only-x86_64
26

37
#![crate_type = "lib"]
48
#![feature(rust_cold_cc)]
59

610
// wasm marks the definition as `dso_local`, so allow that as optional.
711

8-
// CHECK: define{{( dso_local)?}} coldcc void @this_should_never_happen(i16
9-
// CHECK: call coldcc void @this_should_never_happen(i16
12+
// NORMAL: define{{( dso_local)?}} preserve_mostcc void @this_should_never_happen(i16
13+
// NORMAL: call preserve_mostcc void @this_should_never_happen(i16
14+
15+
// See the comment in `Target::adjust_abi` for why this differs
16+
17+
// WINDOWS: define void @this_should_never_happen(i16
18+
// WINDOWS: call void @this_should_never_happen(i16
1019

1120
#[no_mangle]
1221
pub extern "rust-cold" fn this_should_never_happen(x: u16) {}

0 commit comments

Comments
 (0)