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::SpirV => ArchKind::Spirv,
64            Arch::Wasm32 | Arch::Wasm64 => ArchKind::Wasm,
65            Arch::X86 => ArchKind::X86,
66            Arch::X86_64 => ArchKind::X86_64,
67            _ => ArchKind::Other,
68        };
69
70        let os = if target.is_like_darwin {
71            OsKind::Apple
72        } else if target.is_like_windows {
73            OsKind::Windows
74        } else if target.is_like_vexos {
75            OsKind::VEXos
76        } else {
77            OsKind::Other
78        };
79
80        AbiMap { arch, os }
81    }
82
83    /// lower an [ExternAbi] to a [CanonAbi] if this AbiMap allows
84    pub fn canonize_abi(&self, extern_abi: ExternAbi, has_c_varargs: bool) -> AbiMapping {
85        let AbiMap { os, arch } = *self;
86
87        if extern_abi == ExternAbi::Swift {
88            // Per https://www.swift.org/blog/abi-stability-and-more/, Swift's ABI
89            // is only stable on Apple platforms, so we reject it elsewhere.
90            match os {
91                OsKind::Apple => {}
92                _ => return AbiMapping::Invalid,
93            }
94        }
95
96        let canon_abi = match (extern_abi, arch) {
97            // infallible lowerings
98            (ExternAbi::C { .. }, _) => CanonAbi::C,
99            (ExternAbi::Rust | ExternAbi::RustCall, _) => CanonAbi::Rust,
100
101            // Dummy mapping to prevent reporting an error in the frontend
102            (ExternAbi::Unadjusted, _) => CanonAbi::C,
103
104            (ExternAbi::RustCold, _) if self.os == OsKind::Windows => CanonAbi::Rust,
105            (ExternAbi::RustCold, _) => CanonAbi::RustCold,
106            (ExternAbi::RustPreserveNone, _) => CanonAbi::RustPreserveNone,
107            (ExternAbi::RustTail, _) => CanonAbi::RustTail,
108
109            (ExternAbi::Swift, _) => CanonAbi::Swift,
110
111            (ExternAbi::System { .. }, ArchKind::X86)
112                if os == OsKind::Windows && !has_c_varargs =>
113            {
114                CanonAbi::X86(X86Call::Stdcall)
115            }
116            (ExternAbi::System { .. }, ArchKind::Arm(..)) if self.os == OsKind::VEXos => {
117                // Calls to VEXos APIs do not use VFP registers.
118                CanonAbi::Arm(ArmCall::Aapcs)
119            }
120            (ExternAbi::System { .. }, _) => CanonAbi::C,
121
122            // fallible lowerings
123            /* multi-platform */
124            // always and forever
125            (ExternAbi::RustInvalid, _) => return AbiMapping::Invalid,
126
127            (ExternAbi::Custom, ArchKind::Wasm | ArchKind::Spirv) => return AbiMapping::Invalid,
128            (ExternAbi::Custom, _) => CanonAbi::Custom,
129
130            (ExternAbi::EfiApi, ArchKind::Arm(..)) => CanonAbi::Arm(ArmCall::Aapcs),
131            (ExternAbi::EfiApi, ArchKind::X86_64) => CanonAbi::X86(X86Call::Win64),
132            (
133                ExternAbi::EfiApi,
134                ArchKind::Aarch64 | ArchKind::LoongArch | ArchKind::Riscv | ArchKind::X86,
135            ) => CanonAbi::C,
136            (ExternAbi::EfiApi, _) => return AbiMapping::Invalid,
137
138            /* arm */
139            (ExternAbi::Aapcs { .. }, ArchKind::Arm(..)) => CanonAbi::Arm(ArmCall::Aapcs),
140            (ExternAbi::Aapcs { .. }, _) => return AbiMapping::Invalid,
141
142            (ExternAbi::CmseNonSecureCall, ArchKind::Arm(ArmVer::ThumbV8M)) => {
143                CanonAbi::Arm(ArmCall::CCmseNonSecureCall)
144            }
145            (ExternAbi::CmseNonSecureEntry, ArchKind::Arm(ArmVer::ThumbV8M)) => {
146                CanonAbi::Arm(ArmCall::CCmseNonSecureEntry)
147            }
148            (ExternAbi::CmseNonSecureCall | ExternAbi::CmseNonSecureEntry, ..) => {
149                return AbiMapping::Invalid;
150            }
151
152            /* gpu */
153            (ExternAbi::PtxKernel, ArchKind::Nvptx) => CanonAbi::GpuKernel,
154            (ExternAbi::GpuKernel, ArchKind::Amdgpu | ArchKind::Nvptx) => CanonAbi::GpuKernel,
155            (ExternAbi::PtxKernel | ExternAbi::GpuKernel, _) => return AbiMapping::Invalid,
156
157            /* x86 */
158            (ExternAbi::Cdecl { .. }, ArchKind::X86) => CanonAbi::C,
159            (ExternAbi::Cdecl { .. }, _) => return AbiMapping::Deprecated(CanonAbi::C),
160
161            (ExternAbi::Fastcall { .. }, ArchKind::X86) => CanonAbi::X86(X86Call::Fastcall),
162            (ExternAbi::Fastcall { .. }, _) if os == OsKind::Windows => {
163                return AbiMapping::Deprecated(CanonAbi::C);
164            }
165            (ExternAbi::Fastcall { .. }, _) => return AbiMapping::Invalid,
166
167            (ExternAbi::Stdcall { .. }, ArchKind::X86) => CanonAbi::X86(X86Call::Stdcall),
168            (ExternAbi::Stdcall { .. }, _) if os == OsKind::Windows => {
169                return AbiMapping::Deprecated(CanonAbi::C);
170            }
171            (ExternAbi::Stdcall { .. }, _) => return AbiMapping::Invalid,
172
173            (ExternAbi::Thiscall { .. }, ArchKind::X86) => CanonAbi::X86(X86Call::Thiscall),
174            (ExternAbi::Thiscall { .. }, _) => return AbiMapping::Invalid,
175
176            (ExternAbi::Vectorcall { .. }, ArchKind::X86 | ArchKind::X86_64) => {
177                CanonAbi::X86(X86Call::Vectorcall)
178            }
179            (ExternAbi::Vectorcall { .. }, _) => return AbiMapping::Invalid,
180
181            (ExternAbi::SysV64 { .. }, ArchKind::X86_64) => CanonAbi::X86(X86Call::SysV64),
182            (ExternAbi::Win64 { .. }, ArchKind::X86_64) => CanonAbi::X86(X86Call::Win64),
183            (ExternAbi::SysV64 { .. } | ExternAbi::Win64 { .. }, _) => return AbiMapping::Invalid,
184
185            /* interrupts */
186            (ExternAbi::AvrInterrupt, ArchKind::Avr) => CanonAbi::Interrupt(InterruptKind::Avr),
187            (ExternAbi::AvrNonBlockingInterrupt, ArchKind::Avr) => {
188                CanonAbi::Interrupt(InterruptKind::AvrNonBlocking)
189            }
190            (ExternAbi::Msp430Interrupt, ArchKind::Msp430) => {
191                CanonAbi::Interrupt(InterruptKind::Msp430)
192            }
193            (ExternAbi::RiscvInterruptM, ArchKind::Riscv) => {
194                CanonAbi::Interrupt(InterruptKind::RiscvMachine)
195            }
196            (ExternAbi::RiscvInterruptS, ArchKind::Riscv) => {
197                CanonAbi::Interrupt(InterruptKind::RiscvSupervisor)
198            }
199            (ExternAbi::X86Interrupt, ArchKind::X86 | ArchKind::X86_64) => {
200                CanonAbi::Interrupt(InterruptKind::X86)
201            }
202            (
203                ExternAbi::AvrInterrupt
204                | ExternAbi::AvrNonBlockingInterrupt
205                | ExternAbi::Msp430Interrupt
206                | ExternAbi::RiscvInterruptM
207                | ExternAbi::RiscvInterruptS
208                | ExternAbi::X86Interrupt,
209                _,
210            ) => return AbiMapping::Invalid,
211        };
212
213        AbiMapping::Direct(canon_abi)
214    }
215}
216
217#[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::Wasm => ::core::fmt::Formatter::write_str(f, "Wasm"),
            ArchKind::Spirv => ::core::fmt::Formatter::write_str(f, "Spirv"),
            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)]
218enum ArchKind {
219    Aarch64,
220    Amdgpu,
221    Arm(ArmVer),
222    Avr,
223    LoongArch,
224    Msp430,
225    Nvptx,
226    Riscv,
227    X86,
228    X86_64,
229    Wasm,
230    Spirv,
231    /// Architectures which don't need other considerations for ABI lowering
232    Other,
233}
234
235#[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)]
236enum OsKind {
237    Apple,
238    Windows,
239    VEXos,
240    Other,
241}
242
243#[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)]
244enum ArmVer {
245    ThumbV8M,
246    Other,
247}