Skip to main content

rustc_abi/
canon_abi.rs

1use std::fmt;
2
3#[cfg(feature = "nightly")]
4use rustc_macros::StableHash;
5
6use crate::ExternAbi;
7
8/// Calling convention to determine codegen
9///
10/// CanonAbi erases certain distinctions ExternAbi preserves, but remains target-dependent.
11/// There are still both target-specific variants and aliasing variants, though much fewer.
12/// The reason for this step is the frontend may wish to show an ExternAbi but implement that ABI
13/// using a different ABI than the string per se, or describe irrelevant differences, e.g.
14/// - extern "system"
15/// - extern "cdecl"
16/// - extern "C-unwind"
17/// In that sense, this erases mere syntactic distinctions to create a canonical *directive*,
18/// rather than picking the "actual" ABI.
19#[derive(#[automatically_derived]
impl ::core::marker::Copy for CanonAbi { }Copy, #[automatically_derived]
impl ::core::clone::Clone for CanonAbi {
    #[inline]
    fn clone(&self) -> CanonAbi {
        let _: ::core::clone::AssertParamIsClone<ArmCall>;
        let _: ::core::clone::AssertParamIsClone<InterruptKind>;
        let _: ::core::clone::AssertParamIsClone<X86Call>;
        *self
    }
}Clone, #[automatically_derived]
impl ::core::fmt::Debug for CanonAbi {
    #[inline]
    fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
        match self {
            CanonAbi::C => ::core::fmt::Formatter::write_str(f, "C"),
            CanonAbi::Rust => ::core::fmt::Formatter::write_str(f, "Rust"),
            CanonAbi::RustCold =>
                ::core::fmt::Formatter::write_str(f, "RustCold"),
            CanonAbi::RustPreserveNone =>
                ::core::fmt::Formatter::write_str(f, "RustPreserveNone"),
            CanonAbi::Custom =>
                ::core::fmt::Formatter::write_str(f, "Custom"),
            CanonAbi::Swift => ::core::fmt::Formatter::write_str(f, "Swift"),
            CanonAbi::Arm(__self_0) =>
                ::core::fmt::Formatter::debug_tuple_field1_finish(f, "Arm",
                    &__self_0),
            CanonAbi::GpuKernel =>
                ::core::fmt::Formatter::write_str(f, "GpuKernel"),
            CanonAbi::Interrupt(__self_0) =>
                ::core::fmt::Formatter::debug_tuple_field1_finish(f,
                    "Interrupt", &__self_0),
            CanonAbi::X86(__self_0) =>
                ::core::fmt::Formatter::debug_tuple_field1_finish(f, "X86",
                    &__self_0),
        }
    }
}Debug)]
20#[derive(#[automatically_derived]
impl ::core::cmp::PartialOrd for CanonAbi {
    #[inline]
    fn partial_cmp(&self, other: &CanonAbi)
        -> ::core::option::Option<::core::cmp::Ordering> {
        let __self_discr = ::core::intrinsics::discriminant_value(self);
        let __arg1_discr = ::core::intrinsics::discriminant_value(other);
        match (self, other) {
            (CanonAbi::Arm(__self_0), CanonAbi::Arm(__arg1_0)) =>
                ::core::cmp::PartialOrd::partial_cmp(__self_0, __arg1_0),
            (CanonAbi::Interrupt(__self_0), CanonAbi::Interrupt(__arg1_0)) =>
                ::core::cmp::PartialOrd::partial_cmp(__self_0, __arg1_0),
            (CanonAbi::X86(__self_0), CanonAbi::X86(__arg1_0)) =>
                ::core::cmp::PartialOrd::partial_cmp(__self_0, __arg1_0),
            _ =>
                ::core::cmp::PartialOrd::partial_cmp(&__self_discr,
                    &__arg1_discr),
        }
    }
}PartialOrd, #[automatically_derived]
impl ::core::cmp::Ord for CanonAbi {
    #[inline]
    fn cmp(&self, other: &CanonAbi) -> ::core::cmp::Ordering {
        let __self_discr = ::core::intrinsics::discriminant_value(self);
        let __arg1_discr = ::core::intrinsics::discriminant_value(other);
        match ::core::cmp::Ord::cmp(&__self_discr, &__arg1_discr) {
            ::core::cmp::Ordering::Equal =>
                match (self, other) {
                    (CanonAbi::Arm(__self_0), CanonAbi::Arm(__arg1_0)) =>
                        ::core::cmp::Ord::cmp(__self_0, __arg1_0),
                    (CanonAbi::Interrupt(__self_0),
                        CanonAbi::Interrupt(__arg1_0)) =>
                        ::core::cmp::Ord::cmp(__self_0, __arg1_0),
                    (CanonAbi::X86(__self_0), CanonAbi::X86(__arg1_0)) =>
                        ::core::cmp::Ord::cmp(__self_0, __arg1_0),
                    _ => ::core::cmp::Ordering::Equal,
                },
            cmp => cmp,
        }
    }
}Ord, #[automatically_derived]
impl ::core::cmp::PartialEq for CanonAbi {
    #[inline]
    fn eq(&self, other: &CanonAbi) -> bool {
        let __self_discr = ::core::intrinsics::discriminant_value(self);
        let __arg1_discr = ::core::intrinsics::discriminant_value(other);
        __self_discr == __arg1_discr &&
            match (self, other) {
                (CanonAbi::Arm(__self_0), CanonAbi::Arm(__arg1_0)) =>
                    __self_0 == __arg1_0,
                (CanonAbi::Interrupt(__self_0), CanonAbi::Interrupt(__arg1_0))
                    => __self_0 == __arg1_0,
                (CanonAbi::X86(__self_0), CanonAbi::X86(__arg1_0)) =>
                    __self_0 == __arg1_0,
                _ => true,
            }
    }
}PartialEq, #[automatically_derived]
impl ::core::cmp::Eq for CanonAbi {
    #[inline]
    #[doc(hidden)]
    #[coverage(off)]
    fn assert_fields_are_eq(&self) {
        let _: ::core::cmp::AssertParamIsEq<ArmCall>;
        let _: ::core::cmp::AssertParamIsEq<InterruptKind>;
        let _: ::core::cmp::AssertParamIsEq<X86Call>;
    }
}Eq, #[automatically_derived]
impl ::core::hash::Hash for CanonAbi {
    #[inline]
    fn hash<__H: ::core::hash::Hasher>(&self, state: &mut __H) {
        let __self_discr = ::core::intrinsics::discriminant_value(self);
        ::core::hash::Hash::hash(&__self_discr, state);
        match self {
            CanonAbi::Arm(__self_0) =>
                ::core::hash::Hash::hash(__self_0, state),
            CanonAbi::Interrupt(__self_0) =>
                ::core::hash::Hash::hash(__self_0, state),
            CanonAbi::X86(__self_0) =>
                ::core::hash::Hash::hash(__self_0, state),
            _ => {}
        }
    }
}Hash)]
21#[cfg_attr(feature = "nightly", derive(const _: () =
    {
        impl ::rustc_data_structures::stable_hash::StableHash for CanonAbi {
            #[inline]
            fn stable_hash<__Hcx: ::rustc_data_structures::stable_hash::StableHashCtxt>(&self,
                __hcx: &mut __Hcx,
                __hasher:
                    &mut ::rustc_data_structures::stable_hash::StableHasher) {
                ::std::mem::discriminant(self).stable_hash(__hcx, __hasher);
                match *self {
                    CanonAbi::C => {}
                    CanonAbi::Rust => {}
                    CanonAbi::RustCold => {}
                    CanonAbi::RustPreserveNone => {}
                    CanonAbi::Custom => {}
                    CanonAbi::Swift => {}
                    CanonAbi::Arm(ref __binding_0) => {
                        { __binding_0.stable_hash(__hcx, __hasher); }
                    }
                    CanonAbi::GpuKernel => {}
                    CanonAbi::Interrupt(ref __binding_0) => {
                        { __binding_0.stable_hash(__hcx, __hasher); }
                    }
                    CanonAbi::X86(ref __binding_0) => {
                        { __binding_0.stable_hash(__hcx, __hasher); }
                    }
                }
            }
        }
    };StableHash))]
22pub enum CanonAbi {
23    // NOTE: the use of nested variants for some ABIs is for many targets they don't matter,
24    // and this pushes the complexity of their reasoning to target-specific code,
25    // allowing a `match` to easily exhaustively ignore these subcategories of variants.
26    // Otherwise it is very tempting to avoid matching exhaustively!
27    C,
28    Rust,
29    RustCold,
30    RustPreserveNone,
31
32    /// An ABI that rustc does not know how to call or define.
33    Custom,
34
35    /// Swift calling convention, exposed via LLVM's `swiftcc`. Cross-platform
36    /// and not tied to a specific target architecture.
37    Swift,
38
39    /// ABIs relevant to 32-bit Arm targets
40    Arm(ArmCall),
41    /// ABI relevant to GPUs: the entry point for a GPU kernel
42    GpuKernel,
43
44    /// ABIs relevant to bare-metal interrupt targets
45    // FIXME(workingjubilee): a particular reason for this nesting is we might not need these?
46    // interrupt ABIs should have the same properties:
47    // - uncallable by Rust calls, as LLVM rejects it in most cases
48    // - uses a preserve-all-registers *callee* convention
49    // - should always return `-> !` (effectively... it can't use normal `ret`)
50    // what differs between targets is
51    // - allowed arguments: x86 differs slightly, having 2-3 arguments which are handled magically
52    // - may need special prologues/epilogues for some interrupts, without affecting "call ABI"
53    Interrupt(InterruptKind),
54
55    /// ABIs relevant to Windows or x86 targets
56    X86(X86Call),
57}
58
59impl CanonAbi {
60    pub fn is_rustic_abi(self) -> bool {
61        match self {
62            CanonAbi::Rust | CanonAbi::RustCold | CanonAbi::RustPreserveNone => true,
63            CanonAbi::C
64            | CanonAbi::Custom
65            | CanonAbi::Swift
66            | CanonAbi::Arm(_)
67            | CanonAbi::GpuKernel
68            | CanonAbi::Interrupt(_)
69            | CanonAbi::X86(_) => false,
70        }
71    }
72}
73
74impl fmt::Display for CanonAbi {
75    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
76        // convert to the ExternAbi that *shares a string* with this CanonAbi.
77        // FIXME: ideally we'd avoid printing `CanonAbi`, and preserve `ExternAbi` everywhere
78        // that we need to generate error messages.
79        let erased_abi = match self {
80            CanonAbi::C => ExternAbi::C { unwind: false },
81            CanonAbi::Rust => ExternAbi::Rust,
82            CanonAbi::RustCold => ExternAbi::RustCold,
83            CanonAbi::RustPreserveNone => ExternAbi::RustPreserveNone,
84            CanonAbi::Custom => ExternAbi::Custom,
85            CanonAbi::Swift => ExternAbi::Swift,
86            CanonAbi::Arm(arm_call) => match arm_call {
87                ArmCall::Aapcs => ExternAbi::Aapcs { unwind: false },
88                ArmCall::CCmseNonSecureCall => ExternAbi::CmseNonSecureCall,
89                ArmCall::CCmseNonSecureEntry => ExternAbi::CmseNonSecureEntry,
90            },
91            CanonAbi::GpuKernel => ExternAbi::GpuKernel,
92            CanonAbi::Interrupt(interrupt_kind) => match interrupt_kind {
93                InterruptKind::Avr => ExternAbi::AvrInterrupt,
94                InterruptKind::AvrNonBlocking => ExternAbi::AvrNonBlockingInterrupt,
95                InterruptKind::Msp430 => ExternAbi::Msp430Interrupt,
96                InterruptKind::RiscvMachine => ExternAbi::RiscvInterruptM,
97                InterruptKind::RiscvSupervisor => ExternAbi::RiscvInterruptS,
98                InterruptKind::X86 => ExternAbi::X86Interrupt,
99            },
100            CanonAbi::X86(x86_call) => match x86_call {
101                X86Call::Fastcall => ExternAbi::Fastcall { unwind: false },
102                X86Call::Stdcall => ExternAbi::Stdcall { unwind: false },
103                X86Call::SysV64 => ExternAbi::SysV64 { unwind: false },
104                X86Call::Thiscall => ExternAbi::Thiscall { unwind: false },
105                X86Call::Vectorcall => ExternAbi::Vectorcall { unwind: false },
106                X86Call::Win64 => ExternAbi::Win64 { unwind: false },
107            },
108        };
109        erased_abi.as_str().fmt(f)
110    }
111}
112
113/// Callee codegen for interrupts
114///
115/// This is named differently from the "Call" enums because it is different:
116/// these "ABI" differences are not relevant to callers, since there is "no caller".
117/// These only affect callee codegen. making their categorization as distinct ABIs a bit peculiar.
118#[derive(#[automatically_derived]
impl ::core::marker::Copy for InterruptKind { }Copy, #[automatically_derived]
impl ::core::clone::Clone for InterruptKind {
    #[inline]
    fn clone(&self) -> InterruptKind { *self }
}Clone, #[automatically_derived]
impl ::core::fmt::Debug for InterruptKind {
    #[inline]
    fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
        ::core::fmt::Formatter::write_str(f,
            match self {
                InterruptKind::Avr => "Avr",
                InterruptKind::AvrNonBlocking => "AvrNonBlocking",
                InterruptKind::Msp430 => "Msp430",
                InterruptKind::RiscvMachine => "RiscvMachine",
                InterruptKind::RiscvSupervisor => "RiscvSupervisor",
                InterruptKind::X86 => "X86",
            })
    }
}Debug)]
119#[derive(#[automatically_derived]
impl ::core::cmp::PartialOrd for InterruptKind {
    #[inline]
    fn partial_cmp(&self, other: &InterruptKind)
        -> ::core::option::Option<::core::cmp::Ordering> {
        let __self_discr = ::core::intrinsics::discriminant_value(self);
        let __arg1_discr = ::core::intrinsics::discriminant_value(other);
        ::core::cmp::PartialOrd::partial_cmp(&__self_discr, &__arg1_discr)
    }
}PartialOrd, #[automatically_derived]
impl ::core::cmp::Ord for InterruptKind {
    #[inline]
    fn cmp(&self, other: &InterruptKind) -> ::core::cmp::Ordering {
        let __self_discr = ::core::intrinsics::discriminant_value(self);
        let __arg1_discr = ::core::intrinsics::discriminant_value(other);
        ::core::cmp::Ord::cmp(&__self_discr, &__arg1_discr)
    }
}Ord, #[automatically_derived]
impl ::core::cmp::PartialEq for InterruptKind {
    #[inline]
    fn eq(&self, other: &InterruptKind) -> bool {
        let __self_discr = ::core::intrinsics::discriminant_value(self);
        let __arg1_discr = ::core::intrinsics::discriminant_value(other);
        __self_discr == __arg1_discr
    }
}PartialEq, #[automatically_derived]
impl ::core::cmp::Eq for InterruptKind {
    #[inline]
    #[doc(hidden)]
    #[coverage(off)]
    fn assert_fields_are_eq(&self) {}
}Eq, #[automatically_derived]
impl ::core::hash::Hash for InterruptKind {
    #[inline]
    fn hash<__H: ::core::hash::Hasher>(&self, state: &mut __H) {
        let __self_discr = ::core::intrinsics::discriminant_value(self);
        ::core::hash::Hash::hash(&__self_discr, state)
    }
}Hash)]
120#[cfg_attr(feature = "nightly", derive(const _: () =
    {
        impl ::rustc_data_structures::stable_hash::StableHash for
            InterruptKind {
            #[inline]
            fn stable_hash<__Hcx: ::rustc_data_structures::stable_hash::StableHashCtxt>(&self,
                __hcx: &mut __Hcx,
                __hasher:
                    &mut ::rustc_data_structures::stable_hash::StableHasher) {
                ::std::mem::discriminant(self).stable_hash(__hcx, __hasher);
                match *self {
                    InterruptKind::Avr => {}
                    InterruptKind::AvrNonBlocking => {}
                    InterruptKind::Msp430 => {}
                    InterruptKind::RiscvMachine => {}
                    InterruptKind::RiscvSupervisor => {}
                    InterruptKind::X86 => {}
                }
            }
        }
    };StableHash))]
121pub enum InterruptKind {
122    Avr,
123    AvrNonBlocking,
124    Msp430,
125    RiscvMachine,
126    RiscvSupervisor,
127    X86,
128}
129
130/// ABIs defined for x86-{32,64}
131///
132/// One of SysV64 or Win64 may alias the C ABI, and arguably Win64 is cross-platform now?
133#[derive(#[automatically_derived]
impl ::core::clone::Clone for X86Call {
    #[inline]
    fn clone(&self) -> X86Call { *self }
}Clone, #[automatically_derived]
impl ::core::marker::Copy for X86Call { }Copy, #[automatically_derived]
impl ::core::fmt::Debug for X86Call {
    #[inline]
    fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
        ::core::fmt::Formatter::write_str(f,
            match self {
                X86Call::Fastcall => "Fastcall",
                X86Call::Stdcall => "Stdcall",
                X86Call::SysV64 => "SysV64",
                X86Call::Thiscall => "Thiscall",
                X86Call::Vectorcall => "Vectorcall",
                X86Call::Win64 => "Win64",
            })
    }
}Debug)]
134#[derive(#[automatically_derived]
impl ::core::cmp::PartialOrd for X86Call {
    #[inline]
    fn partial_cmp(&self, other: &X86Call)
        -> ::core::option::Option<::core::cmp::Ordering> {
        let __self_discr = ::core::intrinsics::discriminant_value(self);
        let __arg1_discr = ::core::intrinsics::discriminant_value(other);
        ::core::cmp::PartialOrd::partial_cmp(&__self_discr, &__arg1_discr)
    }
}PartialOrd, #[automatically_derived]
impl ::core::cmp::Ord for X86Call {
    #[inline]
    fn cmp(&self, other: &X86Call) -> ::core::cmp::Ordering {
        let __self_discr = ::core::intrinsics::discriminant_value(self);
        let __arg1_discr = ::core::intrinsics::discriminant_value(other);
        ::core::cmp::Ord::cmp(&__self_discr, &__arg1_discr)
    }
}Ord, #[automatically_derived]
impl ::core::cmp::PartialEq for X86Call {
    #[inline]
    fn eq(&self, other: &X86Call) -> bool {
        let __self_discr = ::core::intrinsics::discriminant_value(self);
        let __arg1_discr = ::core::intrinsics::discriminant_value(other);
        __self_discr == __arg1_discr
    }
}PartialEq, #[automatically_derived]
impl ::core::cmp::Eq for X86Call {
    #[inline]
    #[doc(hidden)]
    #[coverage(off)]
    fn assert_fields_are_eq(&self) {}
}Eq, #[automatically_derived]
impl ::core::hash::Hash for X86Call {
    #[inline]
    fn hash<__H: ::core::hash::Hasher>(&self, state: &mut __H) {
        let __self_discr = ::core::intrinsics::discriminant_value(self);
        ::core::hash::Hash::hash(&__self_discr, state)
    }
}Hash)]
135#[cfg_attr(feature = "nightly", derive(const _: () =
    {
        impl ::rustc_data_structures::stable_hash::StableHash for X86Call {
            #[inline]
            fn stable_hash<__Hcx: ::rustc_data_structures::stable_hash::StableHashCtxt>(&self,
                __hcx: &mut __Hcx,
                __hasher:
                    &mut ::rustc_data_structures::stable_hash::StableHasher) {
                ::std::mem::discriminant(self).stable_hash(__hcx, __hasher);
                match *self {
                    X86Call::Fastcall => {}
                    X86Call::Stdcall => {}
                    X86Call::SysV64 => {}
                    X86Call::Thiscall => {}
                    X86Call::Vectorcall => {}
                    X86Call::Win64 => {}
                }
            }
        }
    };StableHash))]
136pub enum X86Call {
137    /// "fastcall" has both GNU and Windows variants
138    Fastcall,
139    /// "stdcall" has both GNU and Windows variants
140    Stdcall,
141    SysV64,
142    Thiscall,
143    Vectorcall,
144    Win64,
145}
146
147/// ABIs defined for 32-bit Arm
148#[derive(#[automatically_derived]
impl ::core::marker::Copy for ArmCall { }Copy, #[automatically_derived]
impl ::core::clone::Clone for ArmCall {
    #[inline]
    fn clone(&self) -> ArmCall { *self }
}Clone, #[automatically_derived]
impl ::core::fmt::Debug for ArmCall {
    #[inline]
    fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
        ::core::fmt::Formatter::write_str(f,
            match self {
                ArmCall::Aapcs => "Aapcs",
                ArmCall::CCmseNonSecureCall => "CCmseNonSecureCall",
                ArmCall::CCmseNonSecureEntry => "CCmseNonSecureEntry",
            })
    }
}Debug)]
149#[derive(#[automatically_derived]
impl ::core::cmp::PartialOrd for ArmCall {
    #[inline]
    fn partial_cmp(&self, other: &ArmCall)
        -> ::core::option::Option<::core::cmp::Ordering> {
        let __self_discr = ::core::intrinsics::discriminant_value(self);
        let __arg1_discr = ::core::intrinsics::discriminant_value(other);
        ::core::cmp::PartialOrd::partial_cmp(&__self_discr, &__arg1_discr)
    }
}PartialOrd, #[automatically_derived]
impl ::core::cmp::Ord for ArmCall {
    #[inline]
    fn cmp(&self, other: &ArmCall) -> ::core::cmp::Ordering {
        let __self_discr = ::core::intrinsics::discriminant_value(self);
        let __arg1_discr = ::core::intrinsics::discriminant_value(other);
        ::core::cmp::Ord::cmp(&__self_discr, &__arg1_discr)
    }
}Ord, #[automatically_derived]
impl ::core::cmp::PartialEq for ArmCall {
    #[inline]
    fn eq(&self, other: &ArmCall) -> bool {
        let __self_discr = ::core::intrinsics::discriminant_value(self);
        let __arg1_discr = ::core::intrinsics::discriminant_value(other);
        __self_discr == __arg1_discr
    }
}PartialEq, #[automatically_derived]
impl ::core::cmp::Eq for ArmCall {
    #[inline]
    #[doc(hidden)]
    #[coverage(off)]
    fn assert_fields_are_eq(&self) {}
}Eq, #[automatically_derived]
impl ::core::hash::Hash for ArmCall {
    #[inline]
    fn hash<__H: ::core::hash::Hasher>(&self, state: &mut __H) {
        let __self_discr = ::core::intrinsics::discriminant_value(self);
        ::core::hash::Hash::hash(&__self_discr, state)
    }
}Hash)]
150#[cfg_attr(feature = "nightly", derive(const _: () =
    {
        impl ::rustc_data_structures::stable_hash::StableHash for ArmCall {
            #[inline]
            fn stable_hash<__Hcx: ::rustc_data_structures::stable_hash::StableHashCtxt>(&self,
                __hcx: &mut __Hcx,
                __hasher:
                    &mut ::rustc_data_structures::stable_hash::StableHasher) {
                ::std::mem::discriminant(self).stable_hash(__hcx, __hasher);
                match *self {
                    ArmCall::Aapcs => {}
                    ArmCall::CCmseNonSecureCall => {}
                    ArmCall::CCmseNonSecureEntry => {}
                }
            }
        }
    };StableHash))]
151pub enum ArmCall {
152    Aapcs,
153    CCmseNonSecureCall,
154    CCmseNonSecureEntry,
155}