Skip to main content

rustc_target/spec/
abi_map.rs

1use rustc_abi::{ArmCall, CanonAbi, ExternAbi, InterruptKind, X86Call};
2
3use crate::spec::{Arch, Target};
4
5/// Mapping for ExternAbi to CanonAbi according to a Target
6///
7/// A maybe-transitional structure circa 2025 for hosting future experiments in
8/// encapsulating arch-specific ABI lowering details to make them more testable.
9#[derive(#[automatically_derived]
impl ::core::clone::Clone for AbiMap {
    #[inline]
    fn clone(&self) -> AbiMap {
        AbiMap {
            arch: ::core::clone::Clone::clone(&self.arch),
            os: ::core::clone::Clone::clone(&self.os),
        }
    }
}Clone, #[automatically_derived]
impl ::core::fmt::Debug for AbiMap {
    #[inline]
    fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
        ::core::fmt::Formatter::debug_struct_field2_finish(f, "AbiMap",
            "arch", &self.arch, "os", &&self.os)
    }
}Debug)]
10pub struct AbiMap {
11    arch: ArchKind,
12    os: OsKind,
13}
14
15/// result from trying to map an ABI
16#[derive(#[automatically_derived]
impl ::core::marker::Copy for AbiMapping { }Copy, #[automatically_derived]
impl ::core::clone::Clone for AbiMapping {
    #[inline]
    fn clone(&self) -> AbiMapping {
        let _: ::core::clone::AssertParamIsClone<CanonAbi>;
        *self
    }
}Clone, #[automatically_derived]
impl ::core::fmt::Debug for AbiMapping {
    #[inline]
    fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
        match self {
            AbiMapping::Direct(__self_0) =>
                ::core::fmt::Formatter::debug_tuple_field1_finish(f, "Direct",
                    &__self_0),
            AbiMapping::Deprecated(__self_0) =>
                ::core::fmt::Formatter::debug_tuple_field1_finish(f,
                    "Deprecated", &__self_0),
            AbiMapping::Invalid =>
                ::core::fmt::Formatter::write_str(f, "Invalid"),
        }
    }
}Debug)]
17pub enum AbiMapping {
18    /// this ABI is exactly mapped for this platform
19    Direct(CanonAbi),
20    /// we don't yet warn on this, but we will
21    Deprecated(CanonAbi),
22    /// ABI we do not map for this platform: it must not reach codegen
23    Invalid,
24}
25
26impl AbiMapping {
27    /// optionally get a [CanonAbi], even if Deprecated
28    pub fn into_option(self) -> Option<CanonAbi> {
29        match self {
30            Self::Direct(abi) | Self::Deprecated(abi) => Some(abi),
31            Self::Invalid => None,
32        }
33    }
34
35    /// get a [CanonAbi] even if Deprecated, panicking if Invalid
36    #[track_caller]
37    pub fn unwrap(self) -> CanonAbi {
38        self.into_option().unwrap()
39    }
40
41    pub fn is_mapped(self) -> bool {
42        self.into_option().is_some()
43    }
44}
45
46impl AbiMap {
47    /// create an AbiMap according to arbitrary fields on the [Target]
48    pub fn from_target(target: &Target) -> Self {
49        // the purpose of this little exercise is to force listing what affects these mappings
50        let arch = match target.arch {
51            Arch::AArch64 => ArchKind::Aarch64,
52            Arch::AmdGpu => ArchKind::Amdgpu,
53            Arch::Arm => ArchKind::Arm(if target.llvm_target.starts_with("thumbv8m") {
54                ArmVer::ThumbV8M
55            } else {
56                ArmVer::Other
57            }),
58            Arch::Avr => ArchKind::Avr,
59            Arch::LoongArch32 | Arch::LoongArch64 => ArchKind::LoongArch,
60            Arch::Msp430 => ArchKind::Msp430,
61            Arch::Nvptx64 => ArchKind::Nvptx,
62            Arch::RiscV32 | Arch::RiscV64 => ArchKind::Riscv,
63            Arch::X86 => ArchKind::X86,
64            Arch::X86_64 => ArchKind::X86_64,
65            _ => ArchKind::Other,
66        };
67
68        let os = if target.is_like_darwin {
69            OsKind::Apple
70        } else if target.is_like_windows {
71            OsKind::Windows
72        } else if target.is_like_vexos {
73            OsKind::VEXos
74        } else {
75            OsKind::Other
76        };
77
78        AbiMap { arch, os }
79    }
80
81    /// lower an [ExternAbi] to a [CanonAbi] if this AbiMap allows
82    pub fn canonize_abi(&self, extern_abi: ExternAbi, has_c_varargs: bool) -> AbiMapping {
83        let AbiMap { os, arch } = *self;
84
85        if extern_abi == ExternAbi::Swift {
86            // Per https://www.swift.org/blog/abi-stability-and-more/, Swift's ABI
87            // is only stable on Apple platforms, so we reject it elsewhere.
88            match os {
89                OsKind::Apple => {}
90                _ => return AbiMapping::Invalid,
91            }
92        }
93
94        let canon_abi = match (extern_abi, arch) {
95            // infallible lowerings
96            (ExternAbi::C { .. }, _) => CanonAbi::C,
97            (ExternAbi::Rust | ExternAbi::RustCall, _) => CanonAbi::Rust,
98            (ExternAbi::Unadjusted, _) => CanonAbi::C,
99
100            (ExternAbi::RustCold, _) if self.os == OsKind::Windows => CanonAbi::Rust,
101            (ExternAbi::RustCold, _) => CanonAbi::RustCold,
102            (ExternAbi::RustPreserveNone, _) => CanonAbi::RustPreserveNone,
103
104            (ExternAbi::Custom, _) => CanonAbi::Custom,
105
106            (ExternAbi::Swift, _) => CanonAbi::Swift,
107
108            (ExternAbi::System { .. }, ArchKind::X86)
109                if os == OsKind::Windows && !has_c_varargs =>
110            {
111                CanonAbi::X86(X86Call::Stdcall)
112            }
113            (ExternAbi::System { .. }, ArchKind::Arm(..)) if self.os == OsKind::VEXos => {
114                // Calls to VEXos APIs do not use VFP registers.
115                CanonAbi::Arm(ArmCall::Aapcs)
116            }
117            (ExternAbi::System { .. }, _) => CanonAbi::C,
118
119            // fallible lowerings
120            /* multi-platform */
121            // always and forever
122            (ExternAbi::RustInvalid, _) => return AbiMapping::Invalid,
123
124            (ExternAbi::EfiApi, ArchKind::Arm(..)) => CanonAbi::Arm(ArmCall::Aapcs),
125            (ExternAbi::EfiApi, ArchKind::X86_64) => CanonAbi::X86(X86Call::Win64),
126            (
127                ExternAbi::EfiApi,
128                ArchKind::Aarch64 | ArchKind::LoongArch | ArchKind::Riscv | ArchKind::X86,
129            ) => CanonAbi::C,
130            (ExternAbi::EfiApi, _) => return AbiMapping::Invalid,
131
132            /* arm */
133            (ExternAbi::Aapcs { .. }, ArchKind::Arm(..)) => CanonAbi::Arm(ArmCall::Aapcs),
134            (ExternAbi::Aapcs { .. }, _) => return AbiMapping::Invalid,
135
136            (ExternAbi::CmseNonSecureCall, ArchKind::Arm(ArmVer::ThumbV8M)) => {
137                CanonAbi::Arm(ArmCall::CCmseNonSecureCall)
138            }
139            (ExternAbi::CmseNonSecureEntry, ArchKind::Arm(ArmVer::ThumbV8M)) => {
140                CanonAbi::Arm(ArmCall::CCmseNonSecureEntry)
141            }
142            (ExternAbi::CmseNonSecureCall | ExternAbi::CmseNonSecureEntry, ..) => {
143                return AbiMapping::Invalid;
144            }
145
146            /* gpu */
147            (ExternAbi::PtxKernel, ArchKind::Nvptx) => CanonAbi::GpuKernel,
148            (ExternAbi::GpuKernel, ArchKind::Amdgpu | ArchKind::Nvptx) => CanonAbi::GpuKernel,
149            (ExternAbi::PtxKernel | ExternAbi::GpuKernel, _) => return AbiMapping::Invalid,
150
151            /* x86 */
152            (ExternAbi::Cdecl { .. }, ArchKind::X86) => CanonAbi::C,
153            (ExternAbi::Cdecl { .. }, _) => return AbiMapping::Deprecated(CanonAbi::C),
154
155            (ExternAbi::Fastcall { .. }, ArchKind::X86) => CanonAbi::X86(X86Call::Fastcall),
156            (ExternAbi::Fastcall { .. }, _) if os == OsKind::Windows => {
157                return AbiMapping::Deprecated(CanonAbi::C);
158            }
159            (ExternAbi::Fastcall { .. }, _) => return AbiMapping::Invalid,
160
161            (ExternAbi::Stdcall { .. }, ArchKind::X86) => CanonAbi::X86(X86Call::Stdcall),
162            (ExternAbi::Stdcall { .. }, _) if os == OsKind::Windows => {
163                return AbiMapping::Deprecated(CanonAbi::C);
164            }
165            (ExternAbi::Stdcall { .. }, _) => return AbiMapping::Invalid,
166
167            (ExternAbi::Thiscall { .. }, ArchKind::X86) => CanonAbi::X86(X86Call::Thiscall),
168            (ExternAbi::Thiscall { .. }, _) => return AbiMapping::Invalid,
169
170            (ExternAbi::Vectorcall { .. }, ArchKind::X86 | ArchKind::X86_64) => {
171                CanonAbi::X86(X86Call::Vectorcall)
172            }
173            (ExternAbi::Vectorcall { .. }, _) => return AbiMapping::Invalid,
174
175            (ExternAbi::SysV64 { .. }, ArchKind::X86_64) => CanonAbi::X86(X86Call::SysV64),
176            (ExternAbi::Win64 { .. }, ArchKind::X86_64) => CanonAbi::X86(X86Call::Win64),
177            (ExternAbi::SysV64 { .. } | ExternAbi::Win64 { .. }, _) => return AbiMapping::Invalid,
178
179            /* interrupts */
180            (ExternAbi::AvrInterrupt, ArchKind::Avr) => CanonAbi::Interrupt(InterruptKind::Avr),
181            (ExternAbi::AvrNonBlockingInterrupt, ArchKind::Avr) => {
182                CanonAbi::Interrupt(InterruptKind::AvrNonBlocking)
183            }
184            (ExternAbi::Msp430Interrupt, ArchKind::Msp430) => {
185                CanonAbi::Interrupt(InterruptKind::Msp430)
186            }
187            (ExternAbi::RiscvInterruptM, ArchKind::Riscv) => {
188                CanonAbi::Interrupt(InterruptKind::RiscvMachine)
189            }
190            (ExternAbi::RiscvInterruptS, ArchKind::Riscv) => {
191                CanonAbi::Interrupt(InterruptKind::RiscvSupervisor)
192            }
193            (ExternAbi::X86Interrupt, ArchKind::X86 | ArchKind::X86_64) => {
194                CanonAbi::Interrupt(InterruptKind::X86)
195            }
196            (
197                ExternAbi::AvrInterrupt
198                | ExternAbi::AvrNonBlockingInterrupt
199                | ExternAbi::Msp430Interrupt
200                | ExternAbi::RiscvInterruptM
201                | ExternAbi::RiscvInterruptS
202                | ExternAbi::X86Interrupt,
203                _,
204            ) => return AbiMapping::Invalid,
205        };
206
207        AbiMapping::Direct(canon_abi)
208    }
209}
210
211#[derive(#[automatically_derived]
impl ::core::fmt::Debug for ArchKind {
    #[inline]
    fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
        match self {
            ArchKind::Aarch64 =>
                ::core::fmt::Formatter::write_str(f, "Aarch64"),
            ArchKind::Amdgpu =>
                ::core::fmt::Formatter::write_str(f, "Amdgpu"),
            ArchKind::Arm(__self_0) =>
                ::core::fmt::Formatter::debug_tuple_field1_finish(f, "Arm",
                    &__self_0),
            ArchKind::Avr => ::core::fmt::Formatter::write_str(f, "Avr"),
            ArchKind::LoongArch =>
                ::core::fmt::Formatter::write_str(f, "LoongArch"),
            ArchKind::Msp430 =>
                ::core::fmt::Formatter::write_str(f, "Msp430"),
            ArchKind::Nvptx => ::core::fmt::Formatter::write_str(f, "Nvptx"),
            ArchKind::Riscv => ::core::fmt::Formatter::write_str(f, "Riscv"),
            ArchKind::X86 => ::core::fmt::Formatter::write_str(f, "X86"),
            ArchKind::X86_64 =>
                ::core::fmt::Formatter::write_str(f, "X86_64"),
            ArchKind::Other => ::core::fmt::Formatter::write_str(f, "Other"),
        }
    }
}Debug, #[automatically_derived]
impl ::core::cmp::PartialEq for ArchKind {
    #[inline]
    fn eq(&self, other: &ArchKind) -> bool {
        let __self_discr = ::core::intrinsics::discriminant_value(self);
        let __arg1_discr = ::core::intrinsics::discriminant_value(other);
        __self_discr == __arg1_discr &&
            match (self, other) {
                (ArchKind::Arm(__self_0), ArchKind::Arm(__arg1_0)) =>
                    __self_0 == __arg1_0,
                _ => true,
            }
    }
}PartialEq, #[automatically_derived]
impl ::core::marker::Copy for ArchKind { }Copy, #[automatically_derived]
impl ::core::clone::Clone for ArchKind {
    #[inline]
    fn clone(&self) -> ArchKind {
        let _: ::core::clone::AssertParamIsClone<ArmVer>;
        *self
    }
}Clone)]
212enum ArchKind {
213    Aarch64,
214    Amdgpu,
215    Arm(ArmVer),
216    Avr,
217    LoongArch,
218    Msp430,
219    Nvptx,
220    Riscv,
221    X86,
222    X86_64,
223    /// Architectures which don't need other considerations for ABI lowering
224    Other,
225}
226
227#[derive(#[automatically_derived]
impl ::core::fmt::Debug for OsKind {
    #[inline]
    fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
        ::core::fmt::Formatter::write_str(f,
            match self {
                OsKind::Apple => "Apple",
                OsKind::Windows => "Windows",
                OsKind::VEXos => "VEXos",
                OsKind::Other => "Other",
            })
    }
}Debug, #[automatically_derived]
impl ::core::cmp::PartialEq for OsKind {
    #[inline]
    fn eq(&self, other: &OsKind) -> 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::marker::Copy for OsKind { }Copy, #[automatically_derived]
impl ::core::clone::Clone for OsKind {
    #[inline]
    fn clone(&self) -> OsKind { *self }
}Clone)]
228enum OsKind {
229    Apple,
230    Windows,
231    VEXos,
232    Other,
233}
234
235#[derive(#[automatically_derived]
impl ::core::fmt::Debug for ArmVer {
    #[inline]
    fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
        ::core::fmt::Formatter::write_str(f,
            match self {
                ArmVer::ThumbV8M => "ThumbV8M",
                ArmVer::Other => "Other",
            })
    }
}Debug, #[automatically_derived]
impl ::core::cmp::PartialEq for ArmVer {
    #[inline]
    fn eq(&self, other: &ArmVer) -> 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::marker::Copy for ArmVer { }Copy, #[automatically_derived]
impl ::core::clone::Clone for ArmVer {
    #[inline]
    fn clone(&self) -> ArmVer { *self }
}Clone)]
236enum ArmVer {
237    ThumbV8M,
238    Other,
239}