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 /// Wasmtime equivalent of SystemV, not ABI-stable. 32 /// 33 /// FIXME: remove this when Wasmtime uses the "tail" calling convention for 34 /// all wasm functions. 35 WasmtimeSystemV, 36 } 37 38 impl CallConv { 39 /// Return the default calling convention for the given target triple. 40 pub fn triple_default(triple: &Triple) -> Self { 41 match triple.default_calling_convention() { 42 // Default to System V for unknown targets because most everything 43 // uses System V. 44 Ok(CallingConvention::SystemV) | Err(()) => Self::SystemV, 45 Ok(CallingConvention::AppleAarch64) => Self::AppleAarch64, 46 Ok(CallingConvention::WindowsFastcall) => Self::WindowsFastcall, 47 Ok(unimp) => unimplemented!("calling convention: {:?}", unimp), 48 } 49 } 50 51 /// Returns the calling convention used for libcalls according to the current flags. 52 pub fn for_libcall(flags: &settings::Flags, default_call_conv: CallConv) -> Self { 53 match flags.libcall_call_conv() { 54 LibcallCallConv::IsaDefault => default_call_conv, 55 LibcallCallConv::Fast => Self::Fast, 56 LibcallCallConv::Cold => Self::Cold, 57 LibcallCallConv::SystemV => Self::SystemV, 58 LibcallCallConv::WindowsFastcall => Self::WindowsFastcall, 59 LibcallCallConv::AppleAarch64 => Self::AppleAarch64, 60 LibcallCallConv::Probestack => Self::Probestack, 61 } 62 } 63 64 /// Does this calling convention support tail calls? 65 pub fn supports_tail_calls(&self) -> bool { 66 match self { 67 CallConv::Tail => true, 68 _ => false, 69 } 70 } 71 72 /// Is the calling convention extending the Windows Fastcall ABI? 73 pub fn extends_windows_fastcall(self) -> bool { 74 match self { 75 Self::WindowsFastcall => true, 76 _ => false, 77 } 78 } 79 80 /// Is the calling convention extending the Apple aarch64 ABI? 81 pub fn extends_apple_aarch64(self) -> bool { 82 match self { 83 Self::AppleAarch64 => true, 84 _ => false, 85 } 86 } 87 } 88 89 impl fmt::Display for CallConv { 90 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { 91 f.write_str(match *self { 92 Self::Fast => "fast", 93 Self::Cold => "cold", 94 Self::Tail => "tail", 95 Self::SystemV => "system_v", 96 Self::WindowsFastcall => "windows_fastcall", 97 Self::AppleAarch64 => "apple_aarch64", 98 Self::Probestack => "probestack", 99 Self::WasmtimeSystemV => "wasmtime_system_v", 100 }) 101 } 102 } 103 104 impl str::FromStr for CallConv { 105 type Err = (); 106 fn from_str(s: &str) -> Result<Self, Self::Err> { 107 match s { 108 "fast" => Ok(Self::Fast), 109 "cold" => Ok(Self::Cold), 110 "tail" => Ok(Self::Tail), 111 "system_v" => Ok(Self::SystemV), 112 "windows_fastcall" => Ok(Self::WindowsFastcall), 113 "apple_aarch64" => Ok(Self::AppleAarch64), 114 "probestack" => Ok(Self::Probestack), 115 "wasmtime_system_v" => Ok(Self::WasmtimeSystemV), 116 _ => Err(()), 117 } 118 } 119 } 120