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