1747ad3c4Slazypassion //! Naming well-known routines in the runtime library.
2747ad3c4Slazypassion
38a9b1a90SBenjamin Bouvier use crate::{
4*90ac295eSAlex Crichton ir::{AbiParam, ExternalName, FuncRef, Function, Signature, Type, types},
58a9b1a90SBenjamin Bouvier isa::CallConv,
68a9b1a90SBenjamin Bouvier };
7747ad3c4Slazypassion use core::fmt;
8747ad3c4Slazypassion use core::str::FromStr;
99e884b44SArtur Jamro #[cfg(feature = "enable-serde")]
109ec02f9dSChristopher Serr use serde_derive::{Deserialize, Serialize};
11747ad3c4Slazypassion
12747ad3c4Slazypassion /// The name of a runtime library routine.
13747ad3c4Slazypassion ///
14747ad3c4Slazypassion /// Runtime library calls are generated for Cranelift IR instructions that don't have an equivalent
15747ad3c4Slazypassion /// ISA instruction or an easy macro expansion. A `LibCall` is used as a well-known name to refer to
16747ad3c4Slazypassion /// the runtime library routine. This way, Cranelift doesn't have to know about the naming
17747ad3c4Slazypassion /// convention in the embedding VM's runtime library.
18747ad3c4Slazypassion ///
19747ad3c4Slazypassion /// This list is likely to grow over time.
203293ca6bSPhilip Craig #[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)]
219e884b44SArtur Jamro #[cfg_attr(feature = "enable-serde", derive(Serialize, Deserialize))]
22747ad3c4Slazypassion pub enum LibCall {
23747ad3c4Slazypassion /// probe for stack overflow. These are emitted for functions which need
24dd497c19SBenjamin Bouvier /// when the `enable_probestack` setting is true.
25747ad3c4Slazypassion Probestack,
26747ad3c4Slazypassion /// ceil.f32
27747ad3c4Slazypassion CeilF32,
28747ad3c4Slazypassion /// ceil.f64
29747ad3c4Slazypassion CeilF64,
30747ad3c4Slazypassion /// floor.f32
31747ad3c4Slazypassion FloorF32,
32747ad3c4Slazypassion /// floor.f64
33747ad3c4Slazypassion FloorF64,
34747ad3c4Slazypassion /// trunc.f32
35747ad3c4Slazypassion TruncF32,
36b30157e6SJohn Xu /// trunc.f64
37747ad3c4Slazypassion TruncF64,
38747ad3c4Slazypassion /// nearest.f32
39747ad3c4Slazypassion NearestF32,
40747ad3c4Slazypassion /// nearest.f64
41747ad3c4Slazypassion NearestF64,
42709716bbSAfonso Bordado /// fma.f32
43709716bbSAfonso Bordado FmaF32,
44709716bbSAfonso Bordado /// fma.f64
45709716bbSAfonso Bordado FmaF64,
46747ad3c4Slazypassion /// libc.memcpy
47747ad3c4Slazypassion Memcpy,
48747ad3c4Slazypassion /// libc.memset
49747ad3c4Slazypassion Memset,
50747ad3c4Slazypassion /// libc.memmove
51747ad3c4Slazypassion Memmove,
52c266f7f4SScott McMurray /// libc.memcmp
53c266f7f4SScott McMurray Memcmp,
540a1bb3baSbjorn3
550a1bb3baSbjorn3 /// Elf __tls_get_addr
560a1bb3baSbjorn3 ElfTlsGetAddr,
5750fcab29SUlrich Weigand /// Elf __tls_get_offset
5850fcab29SUlrich Weigand ElfTlsGetOffset,
593dfbfb61SAlex Crichton
603dfbfb61SAlex Crichton /// The `pshufb` on x86 when SSSE3 isn't available.
613dfbfb61SAlex Crichton X86Pshufb,
62eaa2c5b3Sbjorn3 // When adding a new variant make sure to add it to `all_libcalls` too.
63747ad3c4Slazypassion }
64747ad3c4Slazypassion
65747ad3c4Slazypassion impl fmt::Display for LibCall {
fmt(&self, f: &mut fmt::Formatter) -> fmt::Result66747ad3c4Slazypassion fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
67747ad3c4Slazypassion fmt::Debug::fmt(self, f)
68747ad3c4Slazypassion }
69747ad3c4Slazypassion }
70747ad3c4Slazypassion
71747ad3c4Slazypassion impl FromStr for LibCall {
72747ad3c4Slazypassion type Err = ();
73747ad3c4Slazypassion
from_str(s: &str) -> Result<Self, Self::Err>74747ad3c4Slazypassion fn from_str(s: &str) -> Result<Self, Self::Err> {
75747ad3c4Slazypassion match s {
769f506692SPeter Huene "Probestack" => Ok(Self::Probestack),
779f506692SPeter Huene "CeilF32" => Ok(Self::CeilF32),
789f506692SPeter Huene "CeilF64" => Ok(Self::CeilF64),
799f506692SPeter Huene "FloorF32" => Ok(Self::FloorF32),
809f506692SPeter Huene "FloorF64" => Ok(Self::FloorF64),
819f506692SPeter Huene "TruncF32" => Ok(Self::TruncF32),
829f506692SPeter Huene "TruncF64" => Ok(Self::TruncF64),
839f506692SPeter Huene "NearestF32" => Ok(Self::NearestF32),
849f506692SPeter Huene "NearestF64" => Ok(Self::NearestF64),
85709716bbSAfonso Bordado "FmaF32" => Ok(Self::FmaF32),
86709716bbSAfonso Bordado "FmaF64" => Ok(Self::FmaF64),
879f506692SPeter Huene "Memcpy" => Ok(Self::Memcpy),
889f506692SPeter Huene "Memset" => Ok(Self::Memset),
899f506692SPeter Huene "Memmove" => Ok(Self::Memmove),
90c266f7f4SScott McMurray "Memcmp" => Ok(Self::Memcmp),
910a1bb3baSbjorn3
920a1bb3baSbjorn3 "ElfTlsGetAddr" => Ok(Self::ElfTlsGetAddr),
9350fcab29SUlrich Weigand "ElfTlsGetOffset" => Ok(Self::ElfTlsGetOffset),
943dfbfb61SAlex Crichton
953dfbfb61SAlex Crichton "X86Pshufb" => Ok(Self::X86Pshufb),
96747ad3c4Slazypassion _ => Err(()),
97747ad3c4Slazypassion }
98747ad3c4Slazypassion }
99747ad3c4Slazypassion }
100747ad3c4Slazypassion
101747ad3c4Slazypassion impl LibCall {
102eaa2c5b3Sbjorn3 /// Get a list of all known `LibCall`'s.
all_libcalls() -> &'static [LibCall]103eaa2c5b3Sbjorn3 pub fn all_libcalls() -> &'static [LibCall] {
104eaa2c5b3Sbjorn3 use LibCall::*;
105eaa2c5b3Sbjorn3 &[
106eaa2c5b3Sbjorn3 Probestack,
107eaa2c5b3Sbjorn3 CeilF32,
108eaa2c5b3Sbjorn3 CeilF64,
109eaa2c5b3Sbjorn3 FloorF32,
110eaa2c5b3Sbjorn3 FloorF64,
111eaa2c5b3Sbjorn3 TruncF32,
112eaa2c5b3Sbjorn3 TruncF64,
113eaa2c5b3Sbjorn3 NearestF32,
114eaa2c5b3Sbjorn3 NearestF64,
115709716bbSAfonso Bordado FmaF32,
116709716bbSAfonso Bordado FmaF64,
117eaa2c5b3Sbjorn3 Memcpy,
118eaa2c5b3Sbjorn3 Memset,
119eaa2c5b3Sbjorn3 Memmove,
120c266f7f4SScott McMurray Memcmp,
121eaa2c5b3Sbjorn3 ElfTlsGetAddr,
12250fcab29SUlrich Weigand ElfTlsGetOffset,
1233dfbfb61SAlex Crichton X86Pshufb,
124eaa2c5b3Sbjorn3 ]
125eaa2c5b3Sbjorn3 }
126709716bbSAfonso Bordado
127709716bbSAfonso Bordado /// Get a [Signature] for the function targeted by this [LibCall].
signature(&self, call_conv: CallConv, pointer_type: Type) -> Signature1280478ead3Sbjorn3 pub fn signature(&self, call_conv: CallConv, pointer_type: Type) -> Signature {
129709716bbSAfonso Bordado use types::*;
130709716bbSAfonso Bordado let mut sig = Signature::new(call_conv);
131709716bbSAfonso Bordado
132709716bbSAfonso Bordado match self {
133709716bbSAfonso Bordado LibCall::CeilF32 | LibCall::FloorF32 | LibCall::TruncF32 | LibCall::NearestF32 => {
134709716bbSAfonso Bordado sig.params.push(AbiParam::new(F32));
135709716bbSAfonso Bordado sig.returns.push(AbiParam::new(F32));
136709716bbSAfonso Bordado }
137709716bbSAfonso Bordado LibCall::TruncF64 | LibCall::FloorF64 | LibCall::CeilF64 | LibCall::NearestF64 => {
138709716bbSAfonso Bordado sig.params.push(AbiParam::new(F64));
139709716bbSAfonso Bordado sig.returns.push(AbiParam::new(F64));
140709716bbSAfonso Bordado }
141709716bbSAfonso Bordado LibCall::FmaF32 | LibCall::FmaF64 => {
142709716bbSAfonso Bordado let ty = if *self == LibCall::FmaF32 { F32 } else { F64 };
143709716bbSAfonso Bordado
144709716bbSAfonso Bordado sig.params.push(AbiParam::new(ty));
145709716bbSAfonso Bordado sig.params.push(AbiParam::new(ty));
146709716bbSAfonso Bordado sig.params.push(AbiParam::new(ty));
147709716bbSAfonso Bordado sig.returns.push(AbiParam::new(ty));
148709716bbSAfonso Bordado }
1490478ead3Sbjorn3 LibCall::Memcpy | LibCall::Memmove => {
1500478ead3Sbjorn3 // void* memcpy(void *dest, const void *src, size_t count);
1510478ead3Sbjorn3 // void* memmove(void* dest, const void* src, size_t count);
1520478ead3Sbjorn3 sig.params.push(AbiParam::new(pointer_type));
1530478ead3Sbjorn3 sig.params.push(AbiParam::new(pointer_type));
1540478ead3Sbjorn3 sig.params.push(AbiParam::new(pointer_type));
1550478ead3Sbjorn3 sig.returns.push(AbiParam::new(pointer_type));
1560478ead3Sbjorn3 }
1570478ead3Sbjorn3 LibCall::Memset => {
1580478ead3Sbjorn3 // void *memset(void *dest, int ch, size_t count);
1590478ead3Sbjorn3 sig.params.push(AbiParam::new(pointer_type));
1600478ead3Sbjorn3 sig.params.push(AbiParam::new(I32));
1610478ead3Sbjorn3 sig.params.push(AbiParam::new(pointer_type));
1620478ead3Sbjorn3 sig.returns.push(AbiParam::new(pointer_type));
1630478ead3Sbjorn3 }
1640478ead3Sbjorn3 LibCall::Memcmp => {
1650478ead3Sbjorn3 // void* memcpy(void *dest, const void *src, size_t count);
1660478ead3Sbjorn3 sig.params.push(AbiParam::new(pointer_type));
1670478ead3Sbjorn3 sig.params.push(AbiParam::new(pointer_type));
1680478ead3Sbjorn3 sig.params.push(AbiParam::new(pointer_type));
1690478ead3Sbjorn3 sig.returns.push(AbiParam::new(I32))
1700478ead3Sbjorn3 }
1710478ead3Sbjorn3
1720478ead3Sbjorn3 LibCall::Probestack | LibCall::ElfTlsGetAddr | LibCall::ElfTlsGetOffset => {
1730478ead3Sbjorn3 unimplemented!()
1740478ead3Sbjorn3 }
1753dfbfb61SAlex Crichton LibCall::X86Pshufb => {
1763dfbfb61SAlex Crichton sig.params.push(AbiParam::new(I8X16));
1773dfbfb61SAlex Crichton sig.params.push(AbiParam::new(I8X16));
1783dfbfb61SAlex Crichton sig.returns.push(AbiParam::new(I8X16));
1793dfbfb61SAlex Crichton }
180709716bbSAfonso Bordado }
181709716bbSAfonso Bordado
182709716bbSAfonso Bordado sig
183709716bbSAfonso Bordado }
184747ad3c4Slazypassion }
185747ad3c4Slazypassion
186747ad3c4Slazypassion /// Get a function reference for the probestack function in `func`.
187747ad3c4Slazypassion ///
188747ad3c4Slazypassion /// If there is an existing reference, use it, otherwise make a new one.
get_probestack_funcref(func: &mut Function) -> Option<FuncRef>18943a86f14SBenjamin Bouvier pub fn get_probestack_funcref(func: &mut Function) -> Option<FuncRef> {
190747ad3c4Slazypassion find_funcref(LibCall::Probestack, func)
191747ad3c4Slazypassion }
192747ad3c4Slazypassion
193747ad3c4Slazypassion /// Get the existing function reference for `libcall` in `func` if it exists.
find_funcref(libcall: LibCall, func: &Function) -> Option<FuncRef>194747ad3c4Slazypassion fn find_funcref(libcall: LibCall, func: &Function) -> Option<FuncRef> {
195747ad3c4Slazypassion // We're assuming that all libcall function decls are at the end.
196747ad3c4Slazypassion // If we get this wrong, worst case we'll have duplicate libcall decls which is harmless.
197747ad3c4Slazypassion for (fref, func_data) in func.dfg.ext_funcs.iter().rev() {
198747ad3c4Slazypassion match func_data.name {
199747ad3c4Slazypassion ExternalName::LibCall(lc) => {
200747ad3c4Slazypassion if lc == libcall {
201747ad3c4Slazypassion return Some(fref);
202747ad3c4Slazypassion }
203747ad3c4Slazypassion }
204747ad3c4Slazypassion _ => break,
205747ad3c4Slazypassion }
206747ad3c4Slazypassion }
207747ad3c4Slazypassion None
208747ad3c4Slazypassion }
209747ad3c4Slazypassion
210747ad3c4Slazypassion #[cfg(test)]
211747ad3c4Slazypassion mod tests {
212747ad3c4Slazypassion use super::*;
21310e226f9Sbjorn3 use alloc::string::ToString;
214747ad3c4Slazypassion
215747ad3c4Slazypassion #[test]
display()216747ad3c4Slazypassion fn display() {
217747ad3c4Slazypassion assert_eq!(LibCall::CeilF32.to_string(), "CeilF32");
218747ad3c4Slazypassion assert_eq!(LibCall::NearestF64.to_string(), "NearestF64");
219747ad3c4Slazypassion }
220747ad3c4Slazypassion
221747ad3c4Slazypassion #[test]
parsing()222747ad3c4Slazypassion fn parsing() {
223747ad3c4Slazypassion assert_eq!("FloorF32".parse(), Ok(LibCall::FloorF32));
224747ad3c4Slazypassion }
225c266f7f4SScott McMurray
226c266f7f4SScott McMurray #[test]
all_libcalls_to_from_string()227c266f7f4SScott McMurray fn all_libcalls_to_from_string() {
228c266f7f4SScott McMurray for &libcall in LibCall::all_libcalls() {
229c266f7f4SScott McMurray assert_eq!(libcall.to_string().parse(), Ok(libcall));
230c266f7f4SScott McMurray }
231c266f7f4SScott McMurray }
232747ad3c4Slazypassion }
233