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:
commit
f3284dc3ad
@ -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,
|
||||||
|
|
||||||
|
@ -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,
|
||||||
|
@ -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,
|
||||||
|
@ -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)]
|
||||||
|
@ -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",
|
||||||
|
@ -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,
|
||||||
|
@ -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,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -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"),
|
||||||
|
@ -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) {}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user