1747ad3c4Slazypassion //! Naming well-known routines in the runtime library. 2747ad3c4Slazypassion 3747ad3c4Slazypassion use crate::ir::{ 4747ad3c4Slazypassion types, AbiParam, ArgumentPurpose, ExtFuncData, ExternalName, FuncRef, Function, Inst, Opcode, 5747ad3c4Slazypassion Signature, Type, 6747ad3c4Slazypassion }; 7747ad3c4Slazypassion use crate::isa::{CallConv, RegUnit, TargetIsa}; 8747ad3c4Slazypassion use core::fmt; 9747ad3c4Slazypassion use core::str::FromStr; 109e884b44SArtur Jamro #[cfg(feature = "enable-serde")] 119e884b44SArtur Jamro use serde::{Deserialize, Serialize}; 12747ad3c4Slazypassion 13747ad3c4Slazypassion /// The name of a runtime library routine. 14747ad3c4Slazypassion /// 15747ad3c4Slazypassion /// Runtime library calls are generated for Cranelift IR instructions that don't have an equivalent 16747ad3c4Slazypassion /// ISA instruction or an easy macro expansion. A `LibCall` is used as a well-known name to refer to 17747ad3c4Slazypassion /// the runtime library routine. This way, Cranelift doesn't have to know about the naming 18747ad3c4Slazypassion /// convention in the embedding VM's runtime library. 19747ad3c4Slazypassion /// 20747ad3c4Slazypassion /// This list is likely to grow over time. 213293ca6bSPhilip Craig #[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)] 229e884b44SArtur Jamro #[cfg_attr(feature = "enable-serde", derive(Serialize, Deserialize))] 23747ad3c4Slazypassion pub enum LibCall { 24747ad3c4Slazypassion /// probe for stack overflow. These are emitted for functions which need 25*dd497c19SBenjamin Bouvier /// when the `enable_probestack` setting is true. 26747ad3c4Slazypassion Probestack, 27747ad3c4Slazypassion /// ceil.f32 28747ad3c4Slazypassion CeilF32, 29747ad3c4Slazypassion /// ceil.f64 30747ad3c4Slazypassion CeilF64, 31747ad3c4Slazypassion /// floor.f32 32747ad3c4Slazypassion FloorF32, 33747ad3c4Slazypassion /// floor.f64 34747ad3c4Slazypassion FloorF64, 35747ad3c4Slazypassion /// trunc.f32 36747ad3c4Slazypassion TruncF32, 37747ad3c4Slazypassion /// frunc.f64 38747ad3c4Slazypassion TruncF64, 39747ad3c4Slazypassion /// nearest.f32 40747ad3c4Slazypassion NearestF32, 41747ad3c4Slazypassion /// nearest.f64 42747ad3c4Slazypassion NearestF64, 43747ad3c4Slazypassion /// libc.memcpy 44747ad3c4Slazypassion Memcpy, 45747ad3c4Slazypassion /// libc.memset 46747ad3c4Slazypassion Memset, 47747ad3c4Slazypassion /// libc.memmove 48747ad3c4Slazypassion Memmove, 49747ad3c4Slazypassion } 50747ad3c4Slazypassion 51747ad3c4Slazypassion impl fmt::Display for LibCall { 52747ad3c4Slazypassion fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { 53747ad3c4Slazypassion fmt::Debug::fmt(self, f) 54747ad3c4Slazypassion } 55747ad3c4Slazypassion } 56747ad3c4Slazypassion 57747ad3c4Slazypassion impl FromStr for LibCall { 58747ad3c4Slazypassion type Err = (); 59747ad3c4Slazypassion 60747ad3c4Slazypassion fn from_str(s: &str) -> Result<Self, Self::Err> { 61747ad3c4Slazypassion match s { 629f506692SPeter Huene "Probestack" => Ok(Self::Probestack), 639f506692SPeter Huene "CeilF32" => Ok(Self::CeilF32), 649f506692SPeter Huene "CeilF64" => Ok(Self::CeilF64), 659f506692SPeter Huene "FloorF32" => Ok(Self::FloorF32), 669f506692SPeter Huene "FloorF64" => Ok(Self::FloorF64), 679f506692SPeter Huene "TruncF32" => Ok(Self::TruncF32), 689f506692SPeter Huene "TruncF64" => Ok(Self::TruncF64), 699f506692SPeter Huene "NearestF32" => Ok(Self::NearestF32), 709f506692SPeter Huene "NearestF64" => Ok(Self::NearestF64), 719f506692SPeter Huene "Memcpy" => Ok(Self::Memcpy), 729f506692SPeter Huene "Memset" => Ok(Self::Memset), 739f506692SPeter Huene "Memmove" => Ok(Self::Memmove), 74747ad3c4Slazypassion _ => Err(()), 75747ad3c4Slazypassion } 76747ad3c4Slazypassion } 77747ad3c4Slazypassion } 78747ad3c4Slazypassion 79747ad3c4Slazypassion impl LibCall { 80747ad3c4Slazypassion /// Get the well-known library call name to use as a replacement for an instruction with the 81747ad3c4Slazypassion /// given opcode and controlling type variable. 82747ad3c4Slazypassion /// 83747ad3c4Slazypassion /// Returns `None` if no well-known library routine name exists for that instruction. 84747ad3c4Slazypassion pub fn for_inst(opcode: Opcode, ctrl_type: Type) -> Option<Self> { 85747ad3c4Slazypassion Some(match ctrl_type { 86747ad3c4Slazypassion types::F32 => match opcode { 879f506692SPeter Huene Opcode::Ceil => Self::CeilF32, 889f506692SPeter Huene Opcode::Floor => Self::FloorF32, 899f506692SPeter Huene Opcode::Trunc => Self::TruncF32, 909f506692SPeter Huene Opcode::Nearest => Self::NearestF32, 91747ad3c4Slazypassion _ => return None, 92747ad3c4Slazypassion }, 93747ad3c4Slazypassion types::F64 => match opcode { 949f506692SPeter Huene Opcode::Ceil => Self::CeilF64, 959f506692SPeter Huene Opcode::Floor => Self::FloorF64, 969f506692SPeter Huene Opcode::Trunc => Self::TruncF64, 979f506692SPeter Huene Opcode::Nearest => Self::NearestF64, 98747ad3c4Slazypassion _ => return None, 99747ad3c4Slazypassion }, 100747ad3c4Slazypassion _ => return None, 101747ad3c4Slazypassion }) 102747ad3c4Slazypassion } 103747ad3c4Slazypassion } 104747ad3c4Slazypassion 105747ad3c4Slazypassion /// Get a function reference for `libcall` in `func`, following the signature 106747ad3c4Slazypassion /// for `inst`. 107747ad3c4Slazypassion /// 108747ad3c4Slazypassion /// If there is an existing reference, use it, otherwise make a new one. 109747ad3c4Slazypassion pub fn get_libcall_funcref( 110747ad3c4Slazypassion libcall: LibCall, 111d8d36022SBenjamin Bouvier call_conv: CallConv, 112747ad3c4Slazypassion func: &mut Function, 113747ad3c4Slazypassion inst: Inst, 114d7d48d5cSBenjamin Bouvier isa: &dyn TargetIsa, 115747ad3c4Slazypassion ) -> FuncRef { 116d8d36022SBenjamin Bouvier find_funcref(libcall, func) 117d8d36022SBenjamin Bouvier .unwrap_or_else(|| make_funcref_for_inst(libcall, call_conv, func, inst, isa)) 118747ad3c4Slazypassion } 119747ad3c4Slazypassion 120747ad3c4Slazypassion /// Get a function reference for the probestack function in `func`. 121747ad3c4Slazypassion /// 122747ad3c4Slazypassion /// If there is an existing reference, use it, otherwise make a new one. 123747ad3c4Slazypassion pub fn get_probestack_funcref( 124747ad3c4Slazypassion func: &mut Function, 125747ad3c4Slazypassion reg_type: Type, 126747ad3c4Slazypassion arg_reg: RegUnit, 127d7d48d5cSBenjamin Bouvier isa: &dyn TargetIsa, 128747ad3c4Slazypassion ) -> FuncRef { 129747ad3c4Slazypassion find_funcref(LibCall::Probestack, func) 130747ad3c4Slazypassion .unwrap_or_else(|| make_funcref_for_probestack(func, reg_type, arg_reg, isa)) 131747ad3c4Slazypassion } 132747ad3c4Slazypassion 133747ad3c4Slazypassion /// Get the existing function reference for `libcall` in `func` if it exists. 134747ad3c4Slazypassion fn find_funcref(libcall: LibCall, func: &Function) -> Option<FuncRef> { 135747ad3c4Slazypassion // We're assuming that all libcall function decls are at the end. 136747ad3c4Slazypassion // If we get this wrong, worst case we'll have duplicate libcall decls which is harmless. 137747ad3c4Slazypassion for (fref, func_data) in func.dfg.ext_funcs.iter().rev() { 138747ad3c4Slazypassion match func_data.name { 139747ad3c4Slazypassion ExternalName::LibCall(lc) => { 140747ad3c4Slazypassion if lc == libcall { 141747ad3c4Slazypassion return Some(fref); 142747ad3c4Slazypassion } 143747ad3c4Slazypassion } 144747ad3c4Slazypassion _ => break, 145747ad3c4Slazypassion } 146747ad3c4Slazypassion } 147747ad3c4Slazypassion None 148747ad3c4Slazypassion } 149747ad3c4Slazypassion 150747ad3c4Slazypassion /// Create a funcref for `LibCall::Probestack`. 151747ad3c4Slazypassion fn make_funcref_for_probestack( 152747ad3c4Slazypassion func: &mut Function, 153747ad3c4Slazypassion reg_type: Type, 154747ad3c4Slazypassion arg_reg: RegUnit, 155d7d48d5cSBenjamin Bouvier isa: &dyn TargetIsa, 156747ad3c4Slazypassion ) -> FuncRef { 157747ad3c4Slazypassion let mut sig = Signature::new(CallConv::Probestack); 158747ad3c4Slazypassion let rax = AbiParam::special_reg(reg_type, ArgumentPurpose::Normal, arg_reg); 159747ad3c4Slazypassion sig.params.push(rax); 160747ad3c4Slazypassion if !isa.flags().probestack_func_adjusts_sp() { 161747ad3c4Slazypassion sig.returns.push(rax); 162747ad3c4Slazypassion } 163747ad3c4Slazypassion make_funcref(LibCall::Probestack, func, sig, isa) 164747ad3c4Slazypassion } 165747ad3c4Slazypassion 166747ad3c4Slazypassion /// Create a funcref for `libcall` with a signature matching `inst`. 167747ad3c4Slazypassion fn make_funcref_for_inst( 168747ad3c4Slazypassion libcall: LibCall, 169d8d36022SBenjamin Bouvier call_conv: CallConv, 170747ad3c4Slazypassion func: &mut Function, 171747ad3c4Slazypassion inst: Inst, 172d7d48d5cSBenjamin Bouvier isa: &dyn TargetIsa, 173747ad3c4Slazypassion ) -> FuncRef { 174d8d36022SBenjamin Bouvier let mut sig = Signature::new(call_conv); 175747ad3c4Slazypassion for &v in func.dfg.inst_args(inst) { 176747ad3c4Slazypassion sig.params.push(AbiParam::new(func.dfg.value_type(v))); 177747ad3c4Slazypassion } 178747ad3c4Slazypassion for &v in func.dfg.inst_results(inst) { 179747ad3c4Slazypassion sig.returns.push(AbiParam::new(func.dfg.value_type(v))); 180747ad3c4Slazypassion } 181747ad3c4Slazypassion 1822ee35b7eSBenjamin Bouvier if call_conv.extends_baldrdash() { 183d8d36022SBenjamin Bouvier // Adds the special VMContext parameter to the signature. 184d8d36022SBenjamin Bouvier sig.params.push(AbiParam::special( 185d8d36022SBenjamin Bouvier isa.pointer_type(), 186d8d36022SBenjamin Bouvier ArgumentPurpose::VMContext, 187d8d36022SBenjamin Bouvier )); 188d8d36022SBenjamin Bouvier } 189d8d36022SBenjamin Bouvier 190747ad3c4Slazypassion make_funcref(libcall, func, sig, isa) 191747ad3c4Slazypassion } 192747ad3c4Slazypassion 193747ad3c4Slazypassion /// Create a funcref for `libcall`. 194d7d48d5cSBenjamin Bouvier fn make_funcref( 195d7d48d5cSBenjamin Bouvier libcall: LibCall, 196d7d48d5cSBenjamin Bouvier func: &mut Function, 197d7d48d5cSBenjamin Bouvier sig: Signature, 198d7d48d5cSBenjamin Bouvier isa: &dyn TargetIsa, 199d7d48d5cSBenjamin Bouvier ) -> FuncRef { 200747ad3c4Slazypassion let sigref = func.import_signature(sig); 201747ad3c4Slazypassion 202747ad3c4Slazypassion func.import_function(ExtFuncData { 203747ad3c4Slazypassion name: ExternalName::LibCall(libcall), 204747ad3c4Slazypassion signature: sigref, 205*dd497c19SBenjamin Bouvier colocated: isa.flags().use_colocated_libcalls(), 206747ad3c4Slazypassion }) 207747ad3c4Slazypassion } 208747ad3c4Slazypassion 209747ad3c4Slazypassion #[cfg(test)] 210747ad3c4Slazypassion mod tests { 211747ad3c4Slazypassion use super::*; 21210e226f9Sbjorn3 use alloc::string::ToString; 213747ad3c4Slazypassion 214747ad3c4Slazypassion #[test] 215747ad3c4Slazypassion fn display() { 216747ad3c4Slazypassion assert_eq!(LibCall::CeilF32.to_string(), "CeilF32"); 217747ad3c4Slazypassion assert_eq!(LibCall::NearestF64.to_string(), "NearestF64"); 218747ad3c4Slazypassion } 219747ad3c4Slazypassion 220747ad3c4Slazypassion #[test] 221747ad3c4Slazypassion fn parsing() { 222747ad3c4Slazypassion assert_eq!("FloorF32".parse(), Ok(LibCall::FloorF32)); 223747ad3c4Slazypassion } 224747ad3c4Slazypassion } 225