1 use crate::settings::{self, LibcallCallConv}; 2 use core::fmt; 3 use core::str; 4 use target_lexicon::{CallingConvention, Triple}; 5 6 #[cfg(feature = "enable-serde")] 7 use serde_derive::{Deserialize, Serialize}; 8 9 /// Calling convention identifiers. 10 #[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)] 11 #[cfg_attr(feature = "enable-serde", derive(Serialize, Deserialize))] 12 pub enum CallConv { 13 /// Best performance, not ABI-stable. 14 Fast, 15 /// Smallest caller code size, not ABI-stable. 16 Cold, 17 /// Supports tail calls, not ABI-stable. 18 // 19 // Currently, this is basically sys-v except that callees pop stack 20 // arguments, rather than callers. Expected to change even more in the 21 // future, however! 22 Tail, 23 /// System V-style convention used on many platforms. 24 SystemV, 25 /// Windows "fastcall" convention, also used for x64 and ARM. 26 WindowsFastcall, 27 /// Mac aarch64 calling convention, which is a tweaked aarch64 ABI. 28 AppleAarch64, 29 /// Specialized convention for the probestack function. 30 Probestack, 31 /// The winch calling convention, not ABI-stable. 32 /// 33 /// The main difference to SystemV is that the winch calling convention 34 /// defines no callee-save registers, and restricts the number of return 35 /// registers to one integer, and one floating point. 36 Winch, 37 } 38 39 impl CallConv { 40 /// Return the default calling convention for the given target triple. 41 pub fn triple_default(triple: &Triple) -> Self { 42 match triple.default_calling_convention() { 43 // Default to System V for unknown targets because most everything 44 // uses System V. 45 Ok(CallingConvention::SystemV) | Err(()) => Self::SystemV, 46 Ok(CallingConvention::AppleAarch64) => Self::AppleAarch64, 47 Ok(CallingConvention::WindowsFastcall) => Self::WindowsFastcall, 48 Ok(unimp) => unimplemented!("calling convention: {:?}", unimp), 49 } 50 } 51 52 /// Returns the calling convention used for libcalls according to the current flags. 53 pub fn for_libcall(flags: &settings::Flags, default_call_conv: CallConv) -> Self { 54 match flags.libcall_call_conv() { 55 LibcallCallConv::IsaDefault => default_call_conv, 56 LibcallCallConv::Fast => Self::Fast, 57 LibcallCallConv::Cold => Self::Cold, 58 LibcallCallConv::SystemV => Self::SystemV, 59 LibcallCallConv::WindowsFastcall => Self::WindowsFastcall, 60 LibcallCallConv::AppleAarch64 => Self::AppleAarch64, 61 LibcallCallConv::Probestack => Self::Probestack, 62 } 63 } 64 65 /// Does this calling convention support tail calls? 66 pub fn supports_tail_calls(&self) -> bool { 67 match self { 68 CallConv::Tail => true, 69 _ => false, 70 } 71 } 72 } 73 74 impl fmt::Display for CallConv { 75 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { 76 f.write_str(match *self { 77 Self::Fast => "fast", 78 Self::Cold => "cold", 79 Self::Tail => "tail", 80 Self::SystemV => "system_v", 81 Self::WindowsFastcall => "windows_fastcall", 82 Self::AppleAarch64 => "apple_aarch64", 83 Self::Probestack => "probestack", 84 Self::Winch => "winch", 85 }) 86 } 87 } 88 89 impl str::FromStr for CallConv { 90 type Err = (); 91 fn from_str(s: &str) -> Result<Self, Self::Err> { 92 match s { 93 "fast" => Ok(Self::Fast), 94 "cold" => Ok(Self::Cold), 95 "tail" => Ok(Self::Tail), 96 "system_v" => Ok(Self::SystemV), 97 "windows_fastcall" => Ok(Self::WindowsFastcall), 98 "apple_aarch64" => Ok(Self::AppleAarch64), 99 "probestack" => Ok(Self::Probestack), 100 "winch" => Ok(Self::Winch), 101 _ => Err(()), 102 } 103 } 104 } 105