cranelift_codegen/ir/
libcall.rs1use crate::{
4 ir::{types, AbiParam, ExternalName, FuncRef, Function, Signature, Type},
5 isa::CallConv,
6};
7use core::fmt;
8use core::str::FromStr;
9#[cfg(feature = "enable-serde")]
10use serde_derive::{Deserialize, Serialize};
11
12#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)]
21#[cfg_attr(feature = "enable-serde", derive(Serialize, Deserialize))]
22pub enum LibCall {
23 Probestack,
26 CeilF32,
28 CeilF64,
30 FloorF32,
32 FloorF64,
34 TruncF32,
36 TruncF64,
38 NearestF32,
40 NearestF64,
42 FmaF32,
44 FmaF64,
46 Memcpy,
48 Memset,
50 Memmove,
52 Memcmp,
54
55 ElfTlsGetAddr,
57 ElfTlsGetOffset,
59
60 X86Pshufb,
62 }
64
65impl fmt::Display for LibCall {
66 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
67 fmt::Debug::fmt(self, f)
68 }
69}
70
71impl FromStr for LibCall {
72 type Err = ();
73
74 fn from_str(s: &str) -> Result<Self, Self::Err> {
75 match s {
76 "Probestack" => Ok(Self::Probestack),
77 "CeilF32" => Ok(Self::CeilF32),
78 "CeilF64" => Ok(Self::CeilF64),
79 "FloorF32" => Ok(Self::FloorF32),
80 "FloorF64" => Ok(Self::FloorF64),
81 "TruncF32" => Ok(Self::TruncF32),
82 "TruncF64" => Ok(Self::TruncF64),
83 "NearestF32" => Ok(Self::NearestF32),
84 "NearestF64" => Ok(Self::NearestF64),
85 "FmaF32" => Ok(Self::FmaF32),
86 "FmaF64" => Ok(Self::FmaF64),
87 "Memcpy" => Ok(Self::Memcpy),
88 "Memset" => Ok(Self::Memset),
89 "Memmove" => Ok(Self::Memmove),
90 "Memcmp" => Ok(Self::Memcmp),
91
92 "ElfTlsGetAddr" => Ok(Self::ElfTlsGetAddr),
93 "ElfTlsGetOffset" => Ok(Self::ElfTlsGetOffset),
94
95 "X86Pshufb" => Ok(Self::X86Pshufb),
96 _ => Err(()),
97 }
98 }
99}
100
101impl LibCall {
102 pub fn all_libcalls() -> &'static [LibCall] {
104 use LibCall::*;
105 &[
106 Probestack,
107 CeilF32,
108 CeilF64,
109 FloorF32,
110 FloorF64,
111 TruncF32,
112 TruncF64,
113 NearestF32,
114 NearestF64,
115 FmaF32,
116 FmaF64,
117 Memcpy,
118 Memset,
119 Memmove,
120 Memcmp,
121 ElfTlsGetAddr,
122 ElfTlsGetOffset,
123 X86Pshufb,
124 ]
125 }
126
127 pub fn signature(&self, call_conv: CallConv, pointer_type: Type) -> Signature {
129 use types::*;
130 let mut sig = Signature::new(call_conv);
131
132 match self {
133 LibCall::CeilF32 | LibCall::FloorF32 | LibCall::TruncF32 | LibCall::NearestF32 => {
134 sig.params.push(AbiParam::new(F32));
135 sig.returns.push(AbiParam::new(F32));
136 }
137 LibCall::TruncF64 | LibCall::FloorF64 | LibCall::CeilF64 | LibCall::NearestF64 => {
138 sig.params.push(AbiParam::new(F64));
139 sig.returns.push(AbiParam::new(F64));
140 }
141 LibCall::FmaF32 | LibCall::FmaF64 => {
142 let ty = if *self == LibCall::FmaF32 { F32 } else { F64 };
143
144 sig.params.push(AbiParam::new(ty));
145 sig.params.push(AbiParam::new(ty));
146 sig.params.push(AbiParam::new(ty));
147 sig.returns.push(AbiParam::new(ty));
148 }
149 LibCall::Memcpy | LibCall::Memmove => {
150 sig.params.push(AbiParam::new(pointer_type));
153 sig.params.push(AbiParam::new(pointer_type));
154 sig.params.push(AbiParam::new(pointer_type));
155 sig.returns.push(AbiParam::new(pointer_type));
156 }
157 LibCall::Memset => {
158 sig.params.push(AbiParam::new(pointer_type));
160 sig.params.push(AbiParam::new(I32));
161 sig.params.push(AbiParam::new(pointer_type));
162 sig.returns.push(AbiParam::new(pointer_type));
163 }
164 LibCall::Memcmp => {
165 sig.params.push(AbiParam::new(pointer_type));
167 sig.params.push(AbiParam::new(pointer_type));
168 sig.params.push(AbiParam::new(pointer_type));
169 sig.returns.push(AbiParam::new(I32))
170 }
171
172 LibCall::Probestack | LibCall::ElfTlsGetAddr | LibCall::ElfTlsGetOffset => {
173 unimplemented!()
174 }
175 LibCall::X86Pshufb => {
176 sig.params.push(AbiParam::new(I8X16));
177 sig.params.push(AbiParam::new(I8X16));
178 sig.returns.push(AbiParam::new(I8X16));
179 }
180 }
181
182 sig
183 }
184}
185
186pub fn get_probestack_funcref(func: &mut Function) -> Option<FuncRef> {
190 find_funcref(LibCall::Probestack, func)
191}
192
193fn find_funcref(libcall: LibCall, func: &Function) -> Option<FuncRef> {
195 for (fref, func_data) in func.dfg.ext_funcs.iter().rev() {
198 match func_data.name {
199 ExternalName::LibCall(lc) => {
200 if lc == libcall {
201 return Some(fref);
202 }
203 }
204 _ => break,
205 }
206 }
207 None
208}
209
210#[cfg(test)]
211mod tests {
212 use super::*;
213 use alloc::string::ToString;
214
215 #[test]
216 fn display() {
217 assert_eq!(LibCall::CeilF32.to_string(), "CeilF32");
218 assert_eq!(LibCall::NearestF64.to_string(), "NearestF64");
219 }
220
221 #[test]
222 fn parsing() {
223 assert_eq!("FloorF32".parse(), Ok(LibCall::FloorF32));
224 }
225
226 #[test]
227 fn all_libcalls_to_from_string() {
228 for &libcall in LibCall::all_libcalls() {
229 assert_eq!(libcall.to_string().parse(), Ok(libcall));
230 }
231 }
232}