|
| 1 | +use std::fmt; |
| 2 | + |
| 3 | +#[cfg(feature = "nightly")] |
| 4 | +use rustc_macros::HashStable_Generic; |
| 5 | + |
| 6 | +use 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(Copy, Clone, Debug)] |
| 20 | +#[derive(PartialOrd, Ord, PartialEq, Eq, Hash)] |
| 21 | +#[cfg_attr(feature = "nightly", derive(HashStable_Generic))] |
| 22 | +pub 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 | + |
| 31 | + /// ABIs relevant to 32-bit Arm targets |
| 32 | + Arm(ArmCall), |
| 33 | + /// ABI relevant to GPUs: the entry point for a GPU kernel |
| 34 | + GpuKernel, |
| 35 | + |
| 36 | + /// ABIs relevant to bare-metal interrupt targets |
| 37 | + // FIXME(workingjubilee): a particular reason for this nesting is we might not need these? |
| 38 | + // interrupt ABIs should have the same properties: |
| 39 | + // - uncallable by Rust calls, as LLVM rejects it in most cases |
| 40 | + // - uses a preserve-all-registers *callee* convention |
| 41 | + // - should always return `-> !` (effectively... it can't use normal `ret`) |
| 42 | + // what differs between targets is |
| 43 | + // - allowed arguments: x86 differs slightly, having 2-3 arguments which are handled magically |
| 44 | + // - may need special prologues/epilogues for some interrupts, without affecting "call ABI" |
| 45 | + Interrupt(InterruptKind), |
| 46 | + |
| 47 | + /// ABIs relevant to Windows or x86 targets |
| 48 | + X86(X86Call), |
| 49 | +} |
| 50 | + |
| 51 | +impl fmt::Display for CanonAbi { |
| 52 | + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { |
| 53 | + // convert to the ExternAbi that *shares a string* with this CanonAbi. |
| 54 | + // FIXME: ideally we'd avoid printing `CanonAbi`, and preserve `ExternAbi` everywhere |
| 55 | + // that we need to generate error messages. |
| 56 | + let erased_abi = match self { |
| 57 | + CanonAbi::C => ExternAbi::C { unwind: false }, |
| 58 | + CanonAbi::Rust => ExternAbi::Rust, |
| 59 | + CanonAbi::RustCold => ExternAbi::RustCold, |
| 60 | + CanonAbi::Arm(arm_call) => match arm_call { |
| 61 | + ArmCall::Aapcs => ExternAbi::Aapcs { unwind: false }, |
| 62 | + ArmCall::CCmseNonSecureCall => ExternAbi::CCmseNonSecureCall, |
| 63 | + ArmCall::CCmseNonSecureEntry => ExternAbi::CCmseNonSecureEntry, |
| 64 | + }, |
| 65 | + CanonAbi::GpuKernel => ExternAbi::GpuKernel, |
| 66 | + CanonAbi::Interrupt(interrupt_kind) => match interrupt_kind { |
| 67 | + InterruptKind::Avr => ExternAbi::AvrInterrupt, |
| 68 | + InterruptKind::AvrNonBlocking => ExternAbi::AvrNonBlockingInterrupt, |
| 69 | + InterruptKind::Msp430 => ExternAbi::Msp430Interrupt, |
| 70 | + InterruptKind::RiscvMachine => ExternAbi::RiscvInterruptM, |
| 71 | + InterruptKind::RiscvSupervisor => ExternAbi::RiscvInterruptS, |
| 72 | + InterruptKind::X86 => ExternAbi::X86Interrupt, |
| 73 | + }, |
| 74 | + CanonAbi::X86(x86_call) => match x86_call { |
| 75 | + X86Call::Fastcall => ExternAbi::Fastcall { unwind: false }, |
| 76 | + X86Call::Stdcall => ExternAbi::Stdcall { unwind: false }, |
| 77 | + X86Call::SysV64 => ExternAbi::SysV64 { unwind: false }, |
| 78 | + X86Call::Thiscall => ExternAbi::Thiscall { unwind: false }, |
| 79 | + X86Call::Vectorcall => ExternAbi::Vectorcall { unwind: false }, |
| 80 | + X86Call::Win64 => ExternAbi::Win64 { unwind: false }, |
| 81 | + }, |
| 82 | + }; |
| 83 | + erased_abi.as_str().fmt(f) |
| 84 | + } |
| 85 | +} |
| 86 | + |
| 87 | +/// Callee codegen for interrupts |
| 88 | +/// |
| 89 | +/// This is named differently from the "Call" enums because it is different: |
| 90 | +/// these "ABI" differences are not relevant to callers, since there is "no caller". |
| 91 | +/// These only affect callee codegen. making their categorization as distinct ABIs a bit peculiar. |
| 92 | +#[derive(Copy, Clone, Debug)] |
| 93 | +#[derive(PartialOrd, Ord, PartialEq, Eq, Hash)] |
| 94 | +#[cfg_attr(feature = "nightly", derive(HashStable_Generic))] |
| 95 | +pub enum InterruptKind { |
| 96 | + Avr, |
| 97 | + AvrNonBlocking, |
| 98 | + Msp430, |
| 99 | + RiscvMachine, |
| 100 | + RiscvSupervisor, |
| 101 | + X86, |
| 102 | +} |
| 103 | + |
| 104 | +/// ABIs defined for x86-{32,64} |
| 105 | +/// |
| 106 | +/// One of SysV64 or Win64 may alias the C ABI, and arguably Win64 is cross-platform now? |
| 107 | +#[derive(Clone, Copy, Debug)] |
| 108 | +#[derive(PartialOrd, Ord, PartialEq, Eq, Hash)] |
| 109 | +#[cfg_attr(feature = "nightly", derive(HashStable_Generic))] |
| 110 | +pub enum X86Call { |
| 111 | + /// "fastcall" has both GNU and Windows variants |
| 112 | + Fastcall, |
| 113 | + /// "stdcall" has both GNU and Windows variants |
| 114 | + Stdcall, |
| 115 | + SysV64, |
| 116 | + Thiscall, |
| 117 | + Vectorcall, |
| 118 | + Win64, |
| 119 | +} |
| 120 | + |
| 121 | +/// ABIs defined for 32-bit Arm |
| 122 | +#[derive(Copy, Clone, Debug)] |
| 123 | +#[derive(PartialOrd, Ord, PartialEq, Eq, Hash)] |
| 124 | +#[cfg_attr(feature = "nightly", derive(HashStable_Generic))] |
| 125 | +pub enum ArmCall { |
| 126 | + Aapcs, |
| 127 | + CCmseNonSecureCall, |
| 128 | + CCmseNonSecureEntry, |
| 129 | +} |
0 commit comments