|
| 1 | +use rustc_abi::{ArmCall, CanonAbi, ExternAbi, InterruptKind, X86Call}; |
| 2 | + |
| 3 | +use crate::spec::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(Clone, Debug)] |
| 10 | +pub struct AbiMap { |
| 11 | + arch: Arch, |
| 12 | + os: OsKind, |
| 13 | +} |
| 14 | + |
| 15 | +#[derive(Copy, Clone, Debug)] |
| 16 | +pub enum AbiMapping { |
| 17 | + /// this ABI is exactly mapped for this platform |
| 18 | + Direct(CanonAbi), |
| 19 | + /// we don't yet warn on this, but we will |
| 20 | + Deprecated(CanonAbi), |
| 21 | + Invalid, |
| 22 | +} |
| 23 | + |
| 24 | +impl AbiMapping { |
| 25 | + pub fn into_option(self) -> Option<CanonAbi> { |
| 26 | + match self { |
| 27 | + Self::Direct(abi) | Self::Deprecated(abi) => Some(abi), |
| 28 | + Self::Invalid => None, |
| 29 | + } |
| 30 | + } |
| 31 | + |
| 32 | + pub fn unwrap(self) -> CanonAbi { |
| 33 | + self.into_option().unwrap() |
| 34 | + } |
| 35 | + |
| 36 | + pub fn is_mapped(self) -> bool { |
| 37 | + self.into_option().is_some() |
| 38 | + } |
| 39 | +} |
| 40 | + |
| 41 | +impl AbiMap { |
| 42 | + pub fn from_target(target: &Target) -> Self { |
| 43 | + // the purpose of this little exercise is to force listing what affects these mappings |
| 44 | + let arch = match &*target.arch { |
| 45 | + "aarch64" => Arch::Aarch64, |
| 46 | + "amdgpu" => Arch::Amdgpu, |
| 47 | + "arm" if target.llvm_target.starts_with("thumbv8m") => Arch::Arm(ArmVer::ThumbV8M), |
| 48 | + "arm" => Arch::Arm(ArmVer::Other), |
| 49 | + "avr" => Arch::Avr, |
| 50 | + "msp430" => Arch::Msp430, |
| 51 | + "nvptx64" => Arch::Nvptx, |
| 52 | + "riscv32" | "riscv64" => Arch::Riscv, |
| 53 | + "x86" => Arch::X86, |
| 54 | + "x86_64" => Arch::X86_64, |
| 55 | + _ => Arch::Other, |
| 56 | + }; |
| 57 | + let os = if target.is_like_windows { OsKind::Windows } else { OsKind::Other }; |
| 58 | + AbiMap { arch, os } |
| 59 | + } |
| 60 | + |
| 61 | + pub fn canonize_abi(&self, extern_abi: ExternAbi, has_c_varargs: bool) -> AbiMapping { |
| 62 | + let AbiMap { os, arch } = *self; |
| 63 | + |
| 64 | + let canon_abi = match (extern_abi, arch) { |
| 65 | + // infallible lowerings |
| 66 | + (ExternAbi::C { .. }, _) => CanonAbi::C, |
| 67 | + (ExternAbi::Rust | ExternAbi::RustCall, _) => CanonAbi::Rust, |
| 68 | + (ExternAbi::Unadjusted, _) => CanonAbi::C, |
| 69 | + |
| 70 | + (ExternAbi::RustCold, _) if self.os == OsKind::Windows => CanonAbi::Rust, |
| 71 | + (ExternAbi::RustCold, _) => CanonAbi::RustCold, |
| 72 | + |
| 73 | + (ExternAbi::System { .. }, Arch::X86) if os == OsKind::Windows && !has_c_varargs => { |
| 74 | + CanonAbi::X86(X86Call::Stdcall) |
| 75 | + } |
| 76 | + (ExternAbi::System { .. }, _) => CanonAbi::C, |
| 77 | + |
| 78 | + // fallible lowerings |
| 79 | + (ExternAbi::EfiApi, Arch::Arm(..)) => CanonAbi::Arm(ArmCall::Aapcs), |
| 80 | + (ExternAbi::EfiApi, Arch::X86_64) => CanonAbi::X86(X86Call::Win64), |
| 81 | + (ExternAbi::EfiApi, Arch::Aarch64 | Arch::Riscv | Arch::X86) => CanonAbi::C, |
| 82 | + (ExternAbi::EfiApi, _) => return AbiMapping::Invalid, |
| 83 | + |
| 84 | + (ExternAbi::Aapcs { .. }, Arch::Arm(..)) => CanonAbi::Arm(ArmCall::Aapcs), |
| 85 | + (ExternAbi::Aapcs { .. }, _) => return AbiMapping::Invalid, |
| 86 | + |
| 87 | + (ExternAbi::CCmseNonSecureCall, Arch::Arm(ArmVer::ThumbV8M)) => { |
| 88 | + CanonAbi::Arm(ArmCall::CCmseNonSecureCall) |
| 89 | + } |
| 90 | + (ExternAbi::CCmseNonSecureEntry, Arch::Arm(ArmVer::ThumbV8M)) => { |
| 91 | + CanonAbi::Arm(ArmCall::CCmseNonSecureEntry) |
| 92 | + } |
| 93 | + (ExternAbi::CCmseNonSecureCall | ExternAbi::CCmseNonSecureEntry, ..) => { |
| 94 | + return AbiMapping::Invalid; |
| 95 | + } |
| 96 | + |
| 97 | + (ExternAbi::Cdecl { .. }, Arch::X86) => CanonAbi::C, |
| 98 | + (ExternAbi::Cdecl { .. }, _) => return AbiMapping::Deprecated(CanonAbi::C), |
| 99 | + |
| 100 | + (ExternAbi::Fastcall { .. }, Arch::X86) => CanonAbi::X86(X86Call::Fastcall), |
| 101 | + (ExternAbi::Fastcall { .. }, _) if os == OsKind::Windows => { |
| 102 | + return AbiMapping::Deprecated(CanonAbi::C); |
| 103 | + } |
| 104 | + (ExternAbi::Fastcall { .. }, _) => return AbiMapping::Invalid, |
| 105 | + |
| 106 | + (ExternAbi::Stdcall { .. }, Arch::X86) => CanonAbi::X86(X86Call::Stdcall), |
| 107 | + (ExternAbi::Stdcall { .. }, _) if os == OsKind::Windows => { |
| 108 | + return AbiMapping::Deprecated(CanonAbi::C); |
| 109 | + } |
| 110 | + (ExternAbi::Stdcall { .. }, _) => return AbiMapping::Invalid, |
| 111 | + |
| 112 | + (ExternAbi::Thiscall { .. }, Arch::X86) => CanonAbi::X86(X86Call::Thiscall), |
| 113 | + (ExternAbi::Thiscall { .. }, _) => return AbiMapping::Invalid, |
| 114 | + |
| 115 | + (ExternAbi::Vectorcall { .. }, Arch::X86 | Arch::X86_64) => { |
| 116 | + CanonAbi::X86(X86Call::Vectorcall) |
| 117 | + } |
| 118 | + (ExternAbi::Vectorcall { .. }, _) if os == OsKind::Windows => { |
| 119 | + return AbiMapping::Deprecated(CanonAbi::C); |
| 120 | + } |
| 121 | + (ExternAbi::Vectorcall { .. }, _) => return AbiMapping::Invalid, |
| 122 | + |
| 123 | + (ExternAbi::SysV64 { .. }, Arch::X86_64) => CanonAbi::X86(X86Call::SysV64), |
| 124 | + (ExternAbi::Win64 { .. }, Arch::X86_64) => CanonAbi::X86(X86Call::Win64), |
| 125 | + (ExternAbi::SysV64 { .. } | ExternAbi::Win64 { .. }, _) => return AbiMapping::Invalid, |
| 126 | + |
| 127 | + (ExternAbi::PtxKernel, Arch::Nvptx) => CanonAbi::GpuKernel, |
| 128 | + (ExternAbi::GpuKernel, Arch::Amdgpu | Arch::Nvptx) => CanonAbi::GpuKernel, |
| 129 | + (ExternAbi::PtxKernel | ExternAbi::GpuKernel, _) => return AbiMapping::Invalid, |
| 130 | + |
| 131 | + (ExternAbi::AvrInterrupt, Arch::Avr) => CanonAbi::Interrupt(InterruptKind::Avr), |
| 132 | + (ExternAbi::AvrNonBlockingInterrupt, Arch::Avr) => { |
| 133 | + CanonAbi::Interrupt(InterruptKind::AvrNonBlocking) |
| 134 | + } |
| 135 | + (ExternAbi::Msp430Interrupt, Arch::Msp430) => { |
| 136 | + CanonAbi::Interrupt(InterruptKind::Msp430) |
| 137 | + } |
| 138 | + (ExternAbi::RiscvInterruptM, Arch::Riscv) => { |
| 139 | + CanonAbi::Interrupt(InterruptKind::RiscvMachine) |
| 140 | + } |
| 141 | + (ExternAbi::RiscvInterruptS, Arch::Riscv) => { |
| 142 | + CanonAbi::Interrupt(InterruptKind::RiscvSupervisor) |
| 143 | + } |
| 144 | + (ExternAbi::X86Interrupt, Arch::X86 | Arch::X86_64) => { |
| 145 | + CanonAbi::Interrupt(InterruptKind::X86) |
| 146 | + } |
| 147 | + ( |
| 148 | + ExternAbi::AvrInterrupt |
| 149 | + | ExternAbi::AvrNonBlockingInterrupt |
| 150 | + | ExternAbi::Msp430Interrupt |
| 151 | + | ExternAbi::RiscvInterruptM |
| 152 | + | ExternAbi::RiscvInterruptS |
| 153 | + | ExternAbi::X86Interrupt, |
| 154 | + _, |
| 155 | + ) => return AbiMapping::Invalid, |
| 156 | + }; |
| 157 | + |
| 158 | + AbiMapping::Direct(canon_abi) |
| 159 | + } |
| 160 | +} |
| 161 | + |
| 162 | +#[derive(Debug, PartialEq, Copy, Clone)] |
| 163 | +enum Arch { |
| 164 | + Aarch64, |
| 165 | + Amdgpu, |
| 166 | + Arm(ArmVer), |
| 167 | + Avr, |
| 168 | + Msp430, |
| 169 | + Nvptx, |
| 170 | + Riscv, |
| 171 | + X86, |
| 172 | + X86_64, |
| 173 | + /// Architectures which don't need other considerations for ABI lowering |
| 174 | + Other, |
| 175 | +} |
| 176 | + |
| 177 | +#[derive(Debug, PartialEq, Copy, Clone)] |
| 178 | +enum OsKind { |
| 179 | + Windows, |
| 180 | + Other, |
| 181 | +} |
| 182 | + |
| 183 | +#[derive(Debug, PartialEq, Copy, Clone)] |
| 184 | +enum ArmVer { |
| 185 | + ThumbV8M, |
| 186 | + Other, |
| 187 | +} |
0 commit comments