1 //! External function calls.
2 //!
3 //! To a Cranelift function, all functions are "external". Directly called functions must be
4 //! declared in the preamble, and all function calls must have a signature.
5 //!
6 //! This module declares the data types used to represent external functions and call signatures.
7 
8 use crate::ir::{ExternalName, SigRef, Type};
9 use crate::isa::CallConv;
10 use crate::machinst::RelocDistance;
11 use alloc::vec::Vec;
12 use core::fmt;
13 use core::str::FromStr;
14 #[cfg(feature = "enable-serde")]
15 use serde::{Deserialize, Serialize};
16 
17 /// Function signature.
18 ///
19 /// The function signature describes the types of formal parameters and return values along with
20 /// other details that are needed to call a function correctly.
21 ///
22 /// A signature can optionally include ISA-specific ABI information which specifies exactly how
23 /// arguments and return values are passed.
24 #[derive(Clone, Debug, PartialEq, Eq, Hash)]
25 #[cfg_attr(feature = "enable-serde", derive(Serialize, Deserialize))]
26 pub struct Signature {
27     /// The arguments passed to the function.
28     pub params: Vec<AbiParam>,
29     /// Values returned from the function.
30     pub returns: Vec<AbiParam>,
31 
32     /// Calling convention.
33     pub call_conv: CallConv,
34 }
35 
36 impl Signature {
37     /// Create a new blank signature.
38     pub fn new(call_conv: CallConv) -> Self {
39         Self {
40             params: Vec::new(),
41             returns: Vec::new(),
42             call_conv,
43         }
44     }
45 
46     /// Clear the signature so it is identical to a fresh one returned by `new()`.
47     pub fn clear(&mut self, call_conv: CallConv) {
48         self.params.clear();
49         self.returns.clear();
50         self.call_conv = call_conv;
51     }
52 
53     /// Find the index of a presumed unique special-purpose parameter.
54     pub fn special_param_index(&self, purpose: ArgumentPurpose) -> Option<usize> {
55         self.params.iter().rposition(|arg| arg.purpose == purpose)
56     }
57 
58     /// Find the index of a presumed unique special-purpose parameter.
59     pub fn special_return_index(&self, purpose: ArgumentPurpose) -> Option<usize> {
60         self.returns.iter().rposition(|arg| arg.purpose == purpose)
61     }
62 
63     /// Does this signature have a parameter whose `ArgumentPurpose` is
64     /// `purpose`?
65     pub fn uses_special_param(&self, purpose: ArgumentPurpose) -> bool {
66         self.special_param_index(purpose).is_some()
67     }
68 
69     /// Does this signature have a return whose `ArgumentPurpose` is `purpose`?
70     pub fn uses_special_return(&self, purpose: ArgumentPurpose) -> bool {
71         self.special_return_index(purpose).is_some()
72     }
73 
74     /// How many special parameters does this function have?
75     pub fn num_special_params(&self) -> usize {
76         self.params
77             .iter()
78             .filter(|p| p.purpose != ArgumentPurpose::Normal)
79             .count()
80     }
81 
82     /// How many special returns does this function have?
83     pub fn num_special_returns(&self) -> usize {
84         self.returns
85             .iter()
86             .filter(|r| r.purpose != ArgumentPurpose::Normal)
87             .count()
88     }
89 
90     /// Does this signature take an struct return pointer parameter?
91     pub fn uses_struct_return_param(&self) -> bool {
92         self.uses_special_param(ArgumentPurpose::StructReturn)
93     }
94 
95     /// Does this return more than one normal value? (Pre-struct return
96     /// legalization)
97     pub fn is_multi_return(&self) -> bool {
98         self.returns
99             .iter()
100             .filter(|r| r.purpose == ArgumentPurpose::Normal)
101             .count()
102             > 1
103     }
104 }
105 
106 fn write_list(f: &mut fmt::Formatter, args: &[AbiParam]) -> fmt::Result {
107     match args.split_first() {
108         None => {}
109         Some((first, rest)) => {
110             write!(f, "{}", first)?;
111             for arg in rest {
112                 write!(f, ", {}", arg)?;
113             }
114         }
115     }
116     Ok(())
117 }
118 
119 impl fmt::Display for Signature {
120     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
121         write!(f, "(")?;
122         write_list(f, &self.params)?;
123         write!(f, ")")?;
124         if !self.returns.is_empty() {
125             write!(f, " -> ")?;
126             write_list(f, &self.returns)?;
127         }
128         write!(f, " {}", self.call_conv)
129     }
130 }
131 
132 /// Function parameter or return value descriptor.
133 ///
134 /// This describes the value type being passed to or from a function along with flags that affect
135 /// how the argument is passed.
136 #[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)]
137 #[cfg_attr(feature = "enable-serde", derive(Serialize, Deserialize))]
138 pub struct AbiParam {
139     /// Type of the argument value.
140     pub value_type: Type,
141     /// Special purpose of argument, or `Normal`.
142     pub purpose: ArgumentPurpose,
143     /// Method for extending argument to a full register.
144     pub extension: ArgumentExtension,
145 }
146 
147 impl AbiParam {
148     /// Create a parameter with default flags.
149     pub fn new(vt: Type) -> Self {
150         Self {
151             value_type: vt,
152             extension: ArgumentExtension::None,
153             purpose: ArgumentPurpose::Normal,
154         }
155     }
156 
157     /// Create a special-purpose parameter that is not (yet) bound to a specific register.
158     pub fn special(vt: Type, purpose: ArgumentPurpose) -> Self {
159         Self {
160             value_type: vt,
161             extension: ArgumentExtension::None,
162             purpose,
163         }
164     }
165 
166     /// Convert `self` to a parameter with the `uext` flag set.
167     pub fn uext(self) -> Self {
168         debug_assert!(self.value_type.is_int(), "uext on {} arg", self.value_type);
169         Self {
170             extension: ArgumentExtension::Uext,
171             ..self
172         }
173     }
174 
175     /// Convert `self` to a parameter type with the `sext` flag set.
176     pub fn sext(self) -> Self {
177         debug_assert!(self.value_type.is_int(), "sext on {} arg", self.value_type);
178         Self {
179             extension: ArgumentExtension::Sext,
180             ..self
181         }
182     }
183 }
184 
185 impl fmt::Display for AbiParam {
186     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
187         write!(f, "{}", self.value_type)?;
188         match self.extension {
189             ArgumentExtension::None => {}
190             ArgumentExtension::Uext => write!(f, " uext")?,
191             ArgumentExtension::Sext => write!(f, " sext")?,
192         }
193         if self.purpose != ArgumentPurpose::Normal {
194             write!(f, " {}", self.purpose)?;
195         }
196         Ok(())
197     }
198 }
199 
200 /// Function argument extension options.
201 ///
202 /// On some architectures, small integer function arguments and/or return values are extended to
203 /// the width of a general-purpose register.
204 ///
205 /// This attribute specifies how an argument or return value should be extended *if the platform
206 /// and ABI require it*. Because the frontend (CLIF generator) does not know anything about the
207 /// particulars of the target's ABI, and the CLIF should be platform-independent, these attributes
208 /// specify *how* to extend (according to the signedness of the original program) rather than
209 /// *whether* to extend.
210 #[derive(Copy, Clone, PartialEq, Eq, Debug, Hash)]
211 #[cfg_attr(feature = "enable-serde", derive(Serialize, Deserialize))]
212 pub enum ArgumentExtension {
213     /// No extension, high bits are indeterminate.
214     None,
215     /// Unsigned extension: high bits in register are 0.
216     Uext,
217     /// Signed extension: high bits in register replicate sign bit.
218     Sext,
219 }
220 
221 /// The special purpose of a function argument.
222 ///
223 /// Function arguments and return values are used to pass user program values between functions,
224 /// but they are also used to represent special registers with significance to the ABI such as
225 /// frame pointers and callee-saved registers.
226 ///
227 /// The argument purpose is used to indicate any special meaning of an argument or return value.
228 #[derive(Copy, Clone, PartialEq, Eq, Debug, Hash)]
229 #[cfg_attr(feature = "enable-serde", derive(Serialize, Deserialize))]
230 pub enum ArgumentPurpose {
231     /// A normal user program value passed to or from a function.
232     Normal,
233 
234     /// A C struct passed as argument.
235     StructArgument(u32),
236 
237     /// Struct return pointer.
238     ///
239     /// When a function needs to return more data than will fit in registers, the caller passes a
240     /// pointer to a memory location where the return value can be written. In some ABIs, this
241     /// struct return pointer is passed in a specific register.
242     ///
243     /// This argument kind can also appear as a return value for ABIs that require a function with
244     /// a `StructReturn` pointer argument to also return that pointer in a register.
245     StructReturn,
246 
247     /// A VM context pointer.
248     ///
249     /// This is a pointer to a context struct containing details about the current sandbox. It is
250     /// used as a base pointer for `vmctx` global values.
251     VMContext,
252 
253     /// A signature identifier.
254     ///
255     /// This is a special-purpose argument used to identify the calling convention expected by the
256     /// caller in an indirect call. The callee can verify that the expected signature ID matches.
257     SignatureId,
258 
259     /// A stack limit pointer.
260     ///
261     /// This is a pointer to a stack limit. It is used to check the current stack pointer
262     /// against. Can only appear once in a signature.
263     StackLimit,
264 }
265 
266 impl fmt::Display for ArgumentPurpose {
267     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
268         f.write_str(match self {
269             Self::Normal => "normal",
270             Self::StructArgument(size) => return write!(f, "sarg({})", size),
271             Self::StructReturn => "sret",
272             Self::VMContext => "vmctx",
273             Self::SignatureId => "sigid",
274             Self::StackLimit => "stack_limit",
275         })
276     }
277 }
278 
279 impl FromStr for ArgumentPurpose {
280     type Err = ();
281     fn from_str(s: &str) -> Result<Self, ()> {
282         match s {
283             "normal" => Ok(Self::Normal),
284             "sret" => Ok(Self::StructReturn),
285             "vmctx" => Ok(Self::VMContext),
286             "sigid" => Ok(Self::SignatureId),
287             "stack_limit" => Ok(Self::StackLimit),
288             _ if s.starts_with("sarg(") => {
289                 if !s.ends_with(")") {
290                     return Err(());
291                 }
292                 // Parse 'sarg(size)'
293                 let size: u32 = s["sarg(".len()..s.len() - 1].parse().map_err(|_| ())?;
294                 Ok(Self::StructArgument(size))
295             }
296             _ => Err(()),
297         }
298     }
299 }
300 
301 /// An external function.
302 ///
303 /// Information about a function that can be called directly with a direct `call` instruction.
304 #[derive(Clone, Debug)]
305 #[cfg_attr(feature = "enable-serde", derive(Serialize, Deserialize))]
306 pub struct ExtFuncData {
307     /// Name of the external function.
308     pub name: ExternalName,
309     /// Call signature of function.
310     pub signature: SigRef,
311     /// Will this function be defined nearby, such that it will always be a certain distance away,
312     /// after linking? If so, references to it can avoid going through a GOT or PLT. Note that
313     /// symbols meant to be preemptible cannot be considered colocated.
314     ///
315     /// If `true`, some backends may use relocation forms that have limited range. The exact
316     /// distance depends on the code model in use. Currently on AArch64, for example, Cranelift
317     /// uses a custom code model supporting up to +/- 128MB displacements. If it is unknown how
318     /// far away the target will be, it is best not to set the `colocated` flag; in general, this
319     /// flag is best used when the target is known to be in the same unit of code generation, such
320     /// as a Wasm module.
321     ///
322     /// See the documentation for [`RelocDistance`](crate::machinst::RelocDistance) for more details. A
323     /// `colocated` flag value of `true` implies `RelocDistance::Near`.
324     pub colocated: bool,
325 }
326 
327 impl fmt::Display for ExtFuncData {
328     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
329         if self.colocated {
330             write!(f, "colocated ")?;
331         }
332         write!(f, "{} {}", self.name, self.signature)
333     }
334 }
335 
336 impl ExtFuncData {
337     /// Return an estimate of the distance to the referred-to function symbol.
338     pub fn reloc_distance(&self) -> RelocDistance {
339         if self.colocated {
340             RelocDistance::Near
341         } else {
342             RelocDistance::Far
343         }
344     }
345 }
346 
347 #[cfg(test)]
348 mod tests {
349     use super::*;
350     use crate::ir::types::{B8, F32, I32};
351     use alloc::string::ToString;
352 
353     #[test]
354     fn argument_type() {
355         let t = AbiParam::new(I32);
356         assert_eq!(t.to_string(), "i32");
357         let mut t = t.uext();
358         assert_eq!(t.to_string(), "i32 uext");
359         assert_eq!(t.sext().to_string(), "i32 sext");
360         t.purpose = ArgumentPurpose::StructReturn;
361         assert_eq!(t.to_string(), "i32 uext sret");
362     }
363 
364     #[test]
365     fn argument_purpose() {
366         let all_purpose = [
367             (ArgumentPurpose::Normal, "normal"),
368             (ArgumentPurpose::StructReturn, "sret"),
369             (ArgumentPurpose::VMContext, "vmctx"),
370             (ArgumentPurpose::SignatureId, "sigid"),
371             (ArgumentPurpose::StackLimit, "stack_limit"),
372             (ArgumentPurpose::StructArgument(42), "sarg(42)"),
373         ];
374         for &(e, n) in &all_purpose {
375             assert_eq!(e.to_string(), n);
376             assert_eq!(Ok(e), n.parse());
377         }
378     }
379 
380     #[test]
381     fn call_conv() {
382         for &cc in &[
383             CallConv::Fast,
384             CallConv::Cold,
385             CallConv::SystemV,
386             CallConv::WindowsFastcall,
387         ] {
388             assert_eq!(Ok(cc), cc.to_string().parse())
389         }
390     }
391 
392     #[test]
393     fn signatures() {
394         let mut sig = Signature::new(CallConv::WindowsFastcall);
395         assert_eq!(sig.to_string(), "() windows_fastcall");
396         sig.params.push(AbiParam::new(I32));
397         assert_eq!(sig.to_string(), "(i32) windows_fastcall");
398         sig.returns.push(AbiParam::new(F32));
399         assert_eq!(sig.to_string(), "(i32) -> f32 windows_fastcall");
400         sig.params.push(AbiParam::new(I32.by(4).unwrap()));
401         assert_eq!(sig.to_string(), "(i32, i32x4) -> f32 windows_fastcall");
402         sig.returns.push(AbiParam::new(B8));
403         assert_eq!(sig.to_string(), "(i32, i32x4) -> f32, b8 windows_fastcall");
404     }
405 }
406