Skip to content

Commit 664c1fc

Browse files
committed
abi: add a rust-preserve-none calling convention
This is the conceptual opposite of the rust-cold calling convention and is particularly useful in combination with the new `explicit_tail_calls` feature. For relatively tight loops implemented with tail calling (`become`) each of the function with the regular calling convention is still responsible for restoring the initial value of the preserved registers. So it is not unusual to end up with a situation where each step in the tail call loop is spilling and reloading registers, along the lines of: foo: push r12 ; do things pop r12 jmp next_step This adds up quickly, especially when most of the clobberable registers are already used to pass arguments or other uses. I was thinking of making the name of this ABI a little less LLVM-derived and more like a conceptual inverse of `rust-cold`, but could not come with a great name (`rust-cold` is itself not a great name: cold in what context? from which perspective? is it supposed to mean that the function is rarely called?)
1 parent b2a322b commit 664c1fc

File tree

26 files changed

+215
-5
lines changed

26 files changed

+215
-5
lines changed

compiler/rustc_abi/src/canon_abi.rs

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@ pub enum CanonAbi {
2727
C,
2828
Rust,
2929
RustCold,
30+
RustPreserveNone,
3031

3132
/// An ABI that rustc does not know how to call or define.
3233
Custom,
@@ -54,7 +55,7 @@ pub enum CanonAbi {
5455
impl CanonAbi {
5556
pub fn is_rustic_abi(self) -> bool {
5657
match self {
57-
CanonAbi::Rust | CanonAbi::RustCold => true,
58+
CanonAbi::Rust | CanonAbi::RustCold | CanonAbi::RustPreserveNone => true,
5859
CanonAbi::C
5960
| CanonAbi::Custom
6061
| CanonAbi::Arm(_)
@@ -74,6 +75,7 @@ impl fmt::Display for CanonAbi {
7475
CanonAbi::C => ExternAbi::C { unwind: false },
7576
CanonAbi::Rust => ExternAbi::Rust,
7677
CanonAbi::RustCold => ExternAbi::RustCold,
78+
CanonAbi::RustPreserveNone => ExternAbi::RustPreserveNone,
7779
CanonAbi::Custom => ExternAbi::Custom,
7880
CanonAbi::Arm(arm_call) => match arm_call {
7981
ArmCall::Aapcs => ExternAbi::Aapcs { unwind: false },

compiler/rustc_abi/src/extern_abi.rs

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -109,6 +109,13 @@ pub enum ExternAbi {
109109
Win64 {
110110
unwind: bool,
111111
},
112+
113+
/// Preserves no registers.
114+
///
115+
/// Note, that this ABI is not stable in the registers it uses, is intended as an optimization
116+
/// and may fall-back to a more conservative calling convention if the backend does not support
117+
/// forcing callers to save all registers.
118+
RustPreserveNone,
112119
}
113120

114121
macro_rules! abi_impls {
@@ -177,6 +184,7 @@ abi_impls! {
177184
Win64 { unwind: false } =><= "win64",
178185
Win64 { unwind: true } =><= "win64-unwind",
179186
X86Interrupt =><= "x86-interrupt",
187+
RustPreserveNone =><= "rust-preserve-none",
180188
}
181189
}
182190

@@ -243,7 +251,7 @@ impl ExternAbi {
243251
/// - are subject to change between compiler versions
244252
pub fn is_rustic_abi(self) -> bool {
245253
use ExternAbi::*;
246-
matches!(self, Rust | RustCall | RustCold)
254+
matches!(self, Rust | RustCall | RustCold | RustPreserveNone)
247255
}
248256

249257
/// Returns whether the ABI supports C variadics. This only controls whether we allow *imports*
@@ -315,7 +323,8 @@ impl ExternAbi {
315323
| Self::Thiscall { .. }
316324
| Self::Vectorcall { .. }
317325
| Self::SysV64 { .. }
318-
| Self::Win64 { .. } => true,
326+
| Self::Win64 { .. }
327+
| Self::RustPreserveNone => true,
319328
}
320329
}
321330
}

compiler/rustc_ast_lowering/src/stability.rs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -96,6 +96,11 @@ pub fn extern_abi_stability(abi: ExternAbi) -> Result<(), UnstableAbi> {
9696
ExternAbi::RustCold => {
9797
Err(UnstableAbi { abi, feature: sym::rust_cold_cc, explain: GateReason::Experimental })
9898
}
99+
ExternAbi::RustPreserveNone => Err(UnstableAbi {
100+
abi,
101+
feature: sym::rust_preserve_none_cc,
102+
explain: GateReason::Experimental,
103+
}),
99104
ExternAbi::RustInvalid => {
100105
Err(UnstableAbi { abi, feature: sym::rustc_attrs, explain: GateReason::ImplDetail })
101106
}

compiler/rustc_ast_passes/src/ast_validation.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -400,6 +400,7 @@ impl<'a> AstValidator<'a> {
400400
CanonAbi::C
401401
| CanonAbi::Rust
402402
| CanonAbi::RustCold
403+
| CanonAbi::RustPreserveNone
403404
| CanonAbi::Arm(_)
404405
| CanonAbi::X86(_) => { /* nothing to check */ }
405406

compiler/rustc_codegen_cranelift/src/abi/mod.rs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,9 @@ pub(crate) fn conv_to_call_conv(
5656
CanonAbi::Rust | CanonAbi::C => default_call_conv,
5757
CanonAbi::RustCold => CallConv::Cold,
5858

59+
// Cranelift doesn't currently have anything for this.
60+
CanonAbi::RustPreserveNone => default_call_conv,
61+
5962
// Functions with this calling convention can only be called from assembly, but it is
6063
// possible to declare an `extern "custom"` block, so the backend still needs a calling
6164
// convention for declaring foreign functions.

compiler/rustc_codegen_gcc/src/abi.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -243,6 +243,8 @@ impl<'gcc, 'tcx> FnAbiGccExt<'gcc, 'tcx> for FnAbi<'tcx, Ty<'tcx>> {
243243
pub fn conv_to_fn_attribute<'gcc>(conv: CanonAbi, arch: &Arch) -> Option<FnAttribute<'gcc>> {
244244
let attribute = match conv {
245245
CanonAbi::C | CanonAbi::Rust => return None,
246+
// gcc/gccjit does not have anything for this.
247+
CanonAbi::RustPreserveNone => return None,
246248
CanonAbi::RustCold => FnAttribute::Cold,
247249
// Functions with this calling convention can only be called from assembly, but it is
248250
// possible to declare an `extern "custom"` block, so the backend still needs a calling

compiler/rustc_codegen_llvm/src/abi.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -694,6 +694,7 @@ pub(crate) fn to_llvm_calling_convention(sess: &Session, abi: CanonAbi) -> llvm:
694694
match abi {
695695
CanonAbi::C | CanonAbi::Rust => llvm::CCallConv,
696696
CanonAbi::RustCold => llvm::PreserveMost,
697+
CanonAbi::RustPreserveNone => llvm::PreserveNone,
697698
// Functions with this calling convention can only be called from assembly, but it is
698699
// possible to declare an `extern "custom"` block, so the backend still needs a calling
699700
// convention for declaring foreign functions.

compiler/rustc_codegen_llvm/src/attributes.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -369,7 +369,7 @@ fn create_alloc_family_attr(llcx: &llvm::Context) -> &llvm::Attribute {
369369
llvm::CreateAttrStringValue(llcx, "alloc-family", "__rust_alloc")
370370
}
371371

372-
/// Helper for `FnAbi::apply_attrs_llfn`:
372+
/// Helper for `FnAbiLlvmExt::apply_attrs_llfn`:
373373
/// Composite function which sets LLVM attributes for function depending on its AST (`#[attribute]`)
374374
/// attributes.
375375
pub(crate) fn llfn_attrs_from_instance<'ll, 'tcx>(

compiler/rustc_codegen_llvm/src/llvm/ffi.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -167,6 +167,7 @@ pub(crate) enum CallConv {
167167
PreserveMost = 14,
168168
PreserveAll = 15,
169169
Tail = 18,
170+
PreserveNone = 21,
170171
X86StdcallCallConv = 64,
171172
X86FastcallCallConv = 65,
172173
ArmAapcsCallConv = 67,

compiler/rustc_feature/src/unstable.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -632,6 +632,8 @@ declare_features! (
632632
(unstable, rtm_target_feature, "1.35.0", Some(150258)),
633633
/// Allows `extern "rust-cold"`.
634634
(unstable, rust_cold_cc, "1.63.0", Some(97544)),
635+
/// Allows `extern "rust-preserve-none"`.
636+
(unstable, rust_preserve_none_cc, "CURRENT_RUSTC_VERSION", Some(151401)),
635637
/// Target features on s390x.
636638
(unstable, s390x_target_feature, "1.82.0", Some(150259)),
637639
/// Allows the use of the `sanitize` attribute.

0 commit comments

Comments
 (0)