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
This commit is contained in:
bors 2023-08-29 02:23:43 +00:00
commit f3284dc3ad
9 changed files with 71 additions and 23 deletions

View File

@ -39,7 +39,7 @@ fn clif_sig_from_fn_abi<'tcx>(
pub(crate) fn conv_to_call_conv(sess: &Session, c: Conv, default_call_conv: CallConv) -> CallConv { pub(crate) fn conv_to_call_conv(sess: &Session, c: Conv, default_call_conv: CallConv) -> CallConv {
match c { match c {
Conv::Rust | Conv::C => default_call_conv, Conv::Rust | Conv::C => default_call_conv,
Conv::RustCold => CallConv::Cold, Conv::Cold | Conv::PreserveMost | Conv::PreserveAll => CallConv::Cold,
Conv::X86_64SysV => CallConv::SystemV, Conv::X86_64SysV => CallConv::SystemV,
Conv::X86_64Win64 => CallConv::WindowsFastcall, Conv::X86_64Win64 => CallConv::WindowsFastcall,

View File

@ -571,7 +571,9 @@ impl From<Conv> for llvm::CallConv {
Conv::C | Conv::Rust | Conv::CCmseNonSecureCall | Conv::RiscvInterrupt { .. } => { Conv::C | Conv::Rust | Conv::CCmseNonSecureCall | Conv::RiscvInterrupt { .. } => {
llvm::CCallConv llvm::CCallConv
} }
Conv::RustCold => llvm::ColdCallConv, Conv::Cold => llvm::ColdCallConv,
Conv::PreserveMost => llvm::PreserveMost,
Conv::PreserveAll => llvm::PreserveAll,
Conv::AmdGpuKernel => llvm::AmdGpuKernel, Conv::AmdGpuKernel => llvm::AmdGpuKernel,
Conv::AvrInterrupt => llvm::AvrInterrupt, Conv::AvrInterrupt => llvm::AvrInterrupt,
Conv::AvrNonBlockingInterrupt => llvm::AvrNonBlockingInterrupt, Conv::AvrNonBlockingInterrupt => llvm::AvrNonBlockingInterrupt,

View File

@ -83,12 +83,17 @@ pub enum LLVMModFlagBehavior {
// Consts for the LLVM CallConv type, pre-cast to usize. // Consts for the LLVM CallConv type, pre-cast to usize.
/// LLVM CallingConv::ID. Should we wrap this? /// LLVM CallingConv::ID. Should we wrap this?
///
/// See <https://github.com/llvm/llvm-project/blob/main/llvm/include/llvm/IR/CallingConv.h>
#[derive(Copy, Clone, PartialEq, Debug)] #[derive(Copy, Clone, PartialEq, Debug)]
#[repr(C)] #[repr(C)]
pub enum CallConv { pub enum CallConv {
CCallConv = 0, CCallConv = 0,
FastCallConv = 8, FastCallConv = 8,
ColdCallConv = 9, ColdCallConv = 9,
PreserveMost = 14,
PreserveAll = 15,
Tail = 18,
X86StdcallCallConv = 64, X86StdcallCallConv = 64,
X86FastcallCallConv = 65, X86FastcallCallConv = 65,
ArmAapcsCallConv = 67, ArmAapcsCallConv = 67,

View File

@ -579,10 +579,9 @@ pub enum Conv {
C, C,
Rust, Rust,
/// For things unlikely to be called, where smaller caller codegen is Cold,
/// preferred over raw speed. PreserveMost,
/// Stronger than just `#[cold]` because `fn` pointers might be incompatible. PreserveAll,
RustCold,
// Target-specific calling conventions. // Target-specific calling conventions.
ArmAapcs, ArmAapcs,
@ -605,9 +604,7 @@ pub enum Conv {
AvrInterrupt, AvrInterrupt,
AvrNonBlockingInterrupt, AvrNonBlockingInterrupt,
RiscvInterrupt { RiscvInterrupt { kind: RiscvInterruptKind },
kind: RiscvInterruptKind,
},
} }
#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug, HashStable_Generic)] #[derive(Copy, Clone, PartialEq, Eq, Hash, Debug, HashStable_Generic)]

View File

@ -96,7 +96,9 @@ impl ToJson for crate::abi::call::Conv {
let s = match self { let s = match self {
Self::C => "C", Self::C => "C",
Self::Rust => "Rust", Self::Rust => "Rust",
Self::RustCold => "RustCold", Self::Cold => "Cold",
Self::PreserveMost => "PreserveMost",
Self::PreserveAll => "PreserveAll",
Self::ArmAapcs => "ArmAapcs", Self::ArmAapcs => "ArmAapcs",
Self::CCmseNonSecureCall => "CCmseNonSecureCall", Self::CCmseNonSecureCall => "CCmseNonSecureCall",
Self::Msp430Intr => "Msp430Intr", Self::Msp430Intr => "Msp430Intr",

View File

@ -14,15 +14,33 @@ pub enum Abi {
// hashing tests. These are used in many places, so giving them stable values reduces test // hashing tests. These are used in many places, so giving them stable values reduces test
// churn. The specific values are meaningless. // churn. The specific values are meaningless.
Rust, Rust,
C { unwind: bool }, C {
Cdecl { unwind: bool }, unwind: bool,
Stdcall { unwind: bool }, },
Fastcall { unwind: bool }, Cdecl {
Vectorcall { unwind: bool }, unwind: bool,
Thiscall { unwind: bool }, },
Aapcs { unwind: bool }, Stdcall {
Win64 { unwind: bool }, unwind: bool,
SysV64 { unwind: bool }, },
Fastcall {
unwind: bool,
},
Vectorcall {
unwind: bool,
},
Thiscall {
unwind: bool,
},
Aapcs {
unwind: bool,
},
Win64 {
unwind: bool,
},
SysV64 {
unwind: bool,
},
PtxKernel, PtxKernel,
Msp430Interrupt, Msp430Interrupt,
X86Interrupt, X86Interrupt,
@ -32,11 +50,16 @@ pub enum Abi {
AvrNonBlockingInterrupt, AvrNonBlockingInterrupt,
CCmseNonSecureCall, CCmseNonSecureCall,
Wasm, Wasm,
System { unwind: bool }, System {
unwind: bool,
},
RustIntrinsic, RustIntrinsic,
RustCall, RustCall,
PlatformIntrinsic, PlatformIntrinsic,
Unadjusted, Unadjusted,
/// For things unlikely to be called, where reducing register pressure in
/// `extern "Rust"` callers is worth paying extra cost in the callee.
/// Stronger than just `#[cold]` because `fn` pointers might be incompatible.
RustCold, RustCold,
RiscvInterruptM, RiscvInterruptM,
RiscvInterruptS, RiscvInterruptS,

View File

@ -2276,6 +2276,13 @@ impl Target {
Abi::Vectorcall { .. } if ["x86", "x86_64"].contains(&&self.arch[..]) => abi, Abi::Vectorcall { .. } if ["x86", "x86_64"].contains(&&self.arch[..]) => abi,
Abi::Fastcall { unwind } | Abi::Vectorcall { unwind } => Abi::C { unwind }, Abi::Fastcall { unwind } | Abi::Vectorcall { unwind } => Abi::C { unwind },
// The Windows x64 calling convention we use for `extern "Rust"`
// <https://learn.microsoft.com/en-us/cpp/build/x64-software-conventions#register-volatility-and-preservation>
// expects the callee to save `xmm6` through `xmm15`, but `PreserveMost`
// (that we use by default for `extern "rust-cold"`) doesn't save any of those.
// So to avoid bloating callers, just use the Rust convention here.
Abi::RustCold if self.is_like_windows && self.arch == "x86_64" => Abi::Rust,
abi => abi, abi => abi,
} }
} }

View File

@ -172,7 +172,10 @@ fn conv_from_spec_abi(tcx: TyCtxt<'_>, abi: SpecAbi) -> Conv {
use rustc_target::spec::abi::Abi::*; use rustc_target::spec::abi::Abi::*;
match tcx.sess.target.adjust_abi(abi) { match tcx.sess.target.adjust_abi(abi) {
RustIntrinsic | PlatformIntrinsic | Rust | RustCall => Conv::Rust, RustIntrinsic | PlatformIntrinsic | Rust | RustCall => Conv::Rust,
RustCold => Conv::RustCold,
// This is intentionally not using `Conv::Cold`, as that has to preserve
// even SIMD registers, which is generally not a good trade-off.
RustCold => Conv::PreserveMost,
// It's the ABI's job to select this, not ours. // It's the ABI's job to select this, not ours.
System { .. } => bug!("system abi should be selected elsewhere"), System { .. } => bug!("system abi should be selected elsewhere"),

View File

@ -1,12 +1,21 @@
// revisions: NORMAL WINDOWS
// compile-flags: -C no-prepopulate-passes // compile-flags: -C no-prepopulate-passes
//[NORMAL] ignore-windows
//[WINDOWS] only-windows
//[WINDOWS] only-x86_64
#![crate_type = "lib"] #![crate_type = "lib"]
#![feature(rust_cold_cc)] #![feature(rust_cold_cc)]
// wasm marks the definition as `dso_local`, so allow that as optional. // wasm marks the definition as `dso_local`, so allow that as optional.
// CHECK: define{{( dso_local)?}} coldcc void @this_should_never_happen(i16 // NORMAL: define{{( dso_local)?}} preserve_mostcc void @this_should_never_happen(i16
// CHECK: call coldcc void @this_should_never_happen(i16 // NORMAL: call preserve_mostcc void @this_should_never_happen(i16
// See the comment in `Target::adjust_abi` for why this differs
// WINDOWS: define void @this_should_never_happen(i16
// WINDOWS: call void @this_should_never_happen(i16
#[no_mangle] #[no_mangle]
pub extern "rust-cold" fn this_should_never_happen(x: u16) {} pub extern "rust-cold" fn this_should_never_happen(x: u16) {}