Path: blob/main/cranelift/codegen/src/ir/libcall.rs
1693 views
//! Naming well-known routines in the runtime library.12use crate::{3ir::{AbiParam, ExternalName, FuncRef, Function, Signature, Type, types},4isa::CallConv,5};6use core::fmt;7use core::str::FromStr;8#[cfg(feature = "enable-serde")]9use serde_derive::{Deserialize, Serialize};1011/// The name of a runtime library routine.12///13/// Runtime library calls are generated for Cranelift IR instructions that don't have an equivalent14/// ISA instruction or an easy macro expansion. A `LibCall` is used as a well-known name to refer to15/// the runtime library routine. This way, Cranelift doesn't have to know about the naming16/// convention in the embedding VM's runtime library.17///18/// This list is likely to grow over time.19#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)]20#[cfg_attr(feature = "enable-serde", derive(Serialize, Deserialize))]21pub enum LibCall {22/// probe for stack overflow. These are emitted for functions which need23/// when the `enable_probestack` setting is true.24Probestack,25/// ceil.f3226CeilF32,27/// ceil.f6428CeilF64,29/// floor.f3230FloorF32,31/// floor.f6432FloorF64,33/// trunc.f3234TruncF32,35/// trunc.f6436TruncF64,37/// nearest.f3238NearestF32,39/// nearest.f6440NearestF64,41/// fma.f3242FmaF32,43/// fma.f6444FmaF64,45/// libc.memcpy46Memcpy,47/// libc.memset48Memset,49/// libc.memmove50Memmove,51/// libc.memcmp52Memcmp,5354/// Elf __tls_get_addr55ElfTlsGetAddr,56/// Elf __tls_get_offset57ElfTlsGetOffset,5859/// The `pshufb` on x86 when SSSE3 isn't available.60X86Pshufb,61// When adding a new variant make sure to add it to `all_libcalls` too.62}6364impl fmt::Display for LibCall {65fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {66fmt::Debug::fmt(self, f)67}68}6970impl FromStr for LibCall {71type Err = ();7273fn from_str(s: &str) -> Result<Self, Self::Err> {74match s {75"Probestack" => Ok(Self::Probestack),76"CeilF32" => Ok(Self::CeilF32),77"CeilF64" => Ok(Self::CeilF64),78"FloorF32" => Ok(Self::FloorF32),79"FloorF64" => Ok(Self::FloorF64),80"TruncF32" => Ok(Self::TruncF32),81"TruncF64" => Ok(Self::TruncF64),82"NearestF32" => Ok(Self::NearestF32),83"NearestF64" => Ok(Self::NearestF64),84"FmaF32" => Ok(Self::FmaF32),85"FmaF64" => Ok(Self::FmaF64),86"Memcpy" => Ok(Self::Memcpy),87"Memset" => Ok(Self::Memset),88"Memmove" => Ok(Self::Memmove),89"Memcmp" => Ok(Self::Memcmp),9091"ElfTlsGetAddr" => Ok(Self::ElfTlsGetAddr),92"ElfTlsGetOffset" => Ok(Self::ElfTlsGetOffset),9394"X86Pshufb" => Ok(Self::X86Pshufb),95_ => Err(()),96}97}98}99100impl LibCall {101/// Get a list of all known `LibCall`'s.102pub fn all_libcalls() -> &'static [LibCall] {103use LibCall::*;104&[105Probestack,106CeilF32,107CeilF64,108FloorF32,109FloorF64,110TruncF32,111TruncF64,112NearestF32,113NearestF64,114FmaF32,115FmaF64,116Memcpy,117Memset,118Memmove,119Memcmp,120ElfTlsGetAddr,121ElfTlsGetOffset,122X86Pshufb,123]124}125126/// Get a [Signature] for the function targeted by this [LibCall].127pub fn signature(&self, call_conv: CallConv, pointer_type: Type) -> Signature {128use types::*;129let mut sig = Signature::new(call_conv);130131match self {132LibCall::CeilF32 | LibCall::FloorF32 | LibCall::TruncF32 | LibCall::NearestF32 => {133sig.params.push(AbiParam::new(F32));134sig.returns.push(AbiParam::new(F32));135}136LibCall::TruncF64 | LibCall::FloorF64 | LibCall::CeilF64 | LibCall::NearestF64 => {137sig.params.push(AbiParam::new(F64));138sig.returns.push(AbiParam::new(F64));139}140LibCall::FmaF32 | LibCall::FmaF64 => {141let ty = if *self == LibCall::FmaF32 { F32 } else { F64 };142143sig.params.push(AbiParam::new(ty));144sig.params.push(AbiParam::new(ty));145sig.params.push(AbiParam::new(ty));146sig.returns.push(AbiParam::new(ty));147}148LibCall::Memcpy | LibCall::Memmove => {149// void* memcpy(void *dest, const void *src, size_t count);150// void* memmove(void* dest, const void* src, size_t count);151sig.params.push(AbiParam::new(pointer_type));152sig.params.push(AbiParam::new(pointer_type));153sig.params.push(AbiParam::new(pointer_type));154sig.returns.push(AbiParam::new(pointer_type));155}156LibCall::Memset => {157// void *memset(void *dest, int ch, size_t count);158sig.params.push(AbiParam::new(pointer_type));159sig.params.push(AbiParam::new(I32));160sig.params.push(AbiParam::new(pointer_type));161sig.returns.push(AbiParam::new(pointer_type));162}163LibCall::Memcmp => {164// void* memcpy(void *dest, const void *src, size_t count);165sig.params.push(AbiParam::new(pointer_type));166sig.params.push(AbiParam::new(pointer_type));167sig.params.push(AbiParam::new(pointer_type));168sig.returns.push(AbiParam::new(I32))169}170171LibCall::Probestack | LibCall::ElfTlsGetAddr | LibCall::ElfTlsGetOffset => {172unimplemented!()173}174LibCall::X86Pshufb => {175sig.params.push(AbiParam::new(I8X16));176sig.params.push(AbiParam::new(I8X16));177sig.returns.push(AbiParam::new(I8X16));178}179}180181sig182}183}184185/// Get a function reference for the probestack function in `func`.186///187/// If there is an existing reference, use it, otherwise make a new one.188pub fn get_probestack_funcref(func: &mut Function) -> Option<FuncRef> {189find_funcref(LibCall::Probestack, func)190}191192/// Get the existing function reference for `libcall` in `func` if it exists.193fn find_funcref(libcall: LibCall, func: &Function) -> Option<FuncRef> {194// We're assuming that all libcall function decls are at the end.195// If we get this wrong, worst case we'll have duplicate libcall decls which is harmless.196for (fref, func_data) in func.dfg.ext_funcs.iter().rev() {197match func_data.name {198ExternalName::LibCall(lc) => {199if lc == libcall {200return Some(fref);201}202}203_ => break,204}205}206None207}208209#[cfg(test)]210mod tests {211use super::*;212use alloc::string::ToString;213214#[test]215fn display() {216assert_eq!(LibCall::CeilF32.to_string(), "CeilF32");217assert_eq!(LibCall::NearestF64.to_string(), "NearestF64");218}219220#[test]221fn parsing() {222assert_eq!("FloorF32".parse(), Ok(LibCall::FloorF32));223}224225#[test]226fn all_libcalls_to_from_string() {227for &libcall in LibCall::all_libcalls() {228assert_eq!(libcall.to_string().parse(), Ok(libcall));229}230}231}232233234