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     /// Was the argument converted to pointer during legalization?
147     pub legalized_to_pointer: bool,
148 }
149 
150 impl AbiParam {
151     /// Create a parameter with default flags.
152     pub fn new(vt: Type) -> Self {
153         Self {
154             value_type: vt,
155             extension: ArgumentExtension::None,
156             purpose: ArgumentPurpose::Normal,
157             legalized_to_pointer: false,
158         }
159     }
160 
161     /// Create a special-purpose parameter that is not (yet) bound to a specific register.
162     pub fn special(vt: Type, purpose: ArgumentPurpose) -> Self {
163         Self {
164             value_type: vt,
165             extension: ArgumentExtension::None,
166             purpose,
167             legalized_to_pointer: false,
168         }
169     }
170 
171     /// Convert `self` to a parameter with the `uext` flag set.
172     pub fn uext(self) -> Self {
173         debug_assert!(self.value_type.is_int(), "uext on {} arg", self.value_type);
174         Self {
175             extension: ArgumentExtension::Uext,
176             ..self
177         }
178     }
179 
180     /// Convert `self` to a parameter type with the `sext` flag set.
181     pub fn sext(self) -> Self {
182         debug_assert!(self.value_type.is_int(), "sext on {} arg", self.value_type);
183         Self {
184             extension: ArgumentExtension::Sext,
185             ..self
186         }
187     }
188 }
189 
190 impl fmt::Display for AbiParam {
191     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
192         write!(f, "{}", self.value_type)?;
193         if self.legalized_to_pointer {
194             write!(f, " ptr")?;
195         }
196         match self.extension {
197             ArgumentExtension::None => {}
198             ArgumentExtension::Uext => write!(f, " uext")?,
199             ArgumentExtension::Sext => write!(f, " sext")?,
200         }
201         if self.purpose != ArgumentPurpose::Normal {
202             write!(f, " {}", self.purpose)?;
203         }
204         Ok(())
205     }
206 }
207 
208 /// Function argument extension options.
209 ///
210 /// On some architectures, small integer function arguments and/or return values are extended to
211 /// the width of a general-purpose register.
212 ///
213 /// This attribute specifies how an argument or return value should be extended *if the platform
214 /// and ABI require it*. Because the frontend (CLIF generator) does not know anything about the
215 /// particulars of the target's ABI, and the CLIF should be platform-independent, these attributes
216 /// specify *how* to extend (according to the signedness of the original program) rather than
217 /// *whether* to extend.
218 ///
219 /// For example, on x86-64, the SystemV ABI does not require extensions of narrow values, so these
220 /// `ArgumentExtension` attributes are ignored; but in the Baldrdash (SpiderMonkey) ABI on the same
221 /// platform, all narrow values *are* extended, so these attributes may lead to extra
222 /// zero/sign-extend instructions in the generated machine code.
223 #[derive(Copy, Clone, PartialEq, Eq, Debug, Hash)]
224 #[cfg_attr(feature = "enable-serde", derive(Serialize, Deserialize))]
225 pub enum ArgumentExtension {
226     /// No extension, high bits are indeterminate.
227     None,
228     /// Unsigned extension: high bits in register are 0.
229     Uext,
230     /// Signed extension: high bits in register replicate sign bit.
231     Sext,
232 }
233 
234 /// The special purpose of a function argument.
235 ///
236 /// Function arguments and return values are used to pass user program values between functions,
237 /// but they are also used to represent special registers with significance to the ABI such as
238 /// frame pointers and callee-saved registers.
239 ///
240 /// The argument purpose is used to indicate any special meaning of an argument or return value.
241 #[derive(Copy, Clone, PartialEq, Eq, Debug, Hash)]
242 #[cfg_attr(feature = "enable-serde", derive(Serialize, Deserialize))]
243 pub enum ArgumentPurpose {
244     /// A normal user program value passed to or from a function.
245     Normal,
246 
247     /// A C struct passed as argument.
248     StructArgument(u32),
249 
250     /// Struct return pointer.
251     ///
252     /// When a function needs to return more data than will fit in registers, the caller passes a
253     /// pointer to a memory location where the return value can be written. In some ABIs, this
254     /// struct return pointer is passed in a specific register.
255     ///
256     /// This argument kind can also appear as a return value for ABIs that require a function with
257     /// a `StructReturn` pointer argument to also return that pointer in a register.
258     StructReturn,
259 
260     /// The link register.
261     ///
262     /// Most RISC architectures implement calls by saving the return address in a designated
263     /// register rather than pushing it on the stack. This is represented with a `Link` argument.
264     ///
265     /// Similarly, some return instructions expect the return address in a register represented as
266     /// a `Link` return value.
267     Link,
268 
269     /// The frame pointer.
270     ///
271     /// This indicates the frame pointer register which has a special meaning in some ABIs.
272     ///
273     /// The frame pointer appears as an argument and as a return value since it is a callee-saved
274     /// register.
275     FramePointer,
276 
277     /// A callee-saved register.
278     ///
279     /// Some calling conventions have registers that must be saved by the callee. These registers
280     /// are represented as `CalleeSaved` arguments and return values.
281     CalleeSaved,
282 
283     /// A VM context pointer.
284     ///
285     /// This is a pointer to a context struct containing details about the current sandbox. It is
286     /// used as a base pointer for `vmctx` global values.
287     VMContext,
288 
289     /// A signature identifier.
290     ///
291     /// This is a special-purpose argument used to identify the calling convention expected by the
292     /// caller in an indirect call. The callee can verify that the expected signature ID matches.
293     SignatureId,
294 
295     /// A stack limit pointer.
296     ///
297     /// This is a pointer to a stack limit. It is used to check the current stack pointer
298     /// against. Can only appear once in a signature.
299     StackLimit,
300 
301     /// A callee TLS value.
302     ///
303     /// In the Baldrdash-2020 calling convention, the stack upon entry to the callee contains the
304     /// TLS-register values for the caller and the callee. This argument is used to provide the
305     /// value for the callee.
306     CalleeTLS,
307 
308     /// A caller TLS value.
309     ///
310     /// In the Baldrdash-2020 calling convention, the stack upon entry to the callee contains the
311     /// TLS-register values for the caller and the callee. This argument is used to provide the
312     /// value for the caller.
313     CallerTLS,
314 }
315 
316 impl fmt::Display for ArgumentPurpose {
317     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
318         f.write_str(match self {
319             Self::Normal => "normal",
320             Self::StructArgument(size) => return write!(f, "sarg({})", size),
321             Self::StructReturn => "sret",
322             Self::Link => "link",
323             Self::FramePointer => "fp",
324             Self::CalleeSaved => "csr",
325             Self::VMContext => "vmctx",
326             Self::SignatureId => "sigid",
327             Self::StackLimit => "stack_limit",
328             Self::CalleeTLS => "callee_tls",
329             Self::CallerTLS => "caller_tls",
330         })
331     }
332 }
333 
334 impl FromStr for ArgumentPurpose {
335     type Err = ();
336     fn from_str(s: &str) -> Result<Self, ()> {
337         match s {
338             "normal" => Ok(Self::Normal),
339             "sret" => Ok(Self::StructReturn),
340             "link" => Ok(Self::Link),
341             "fp" => Ok(Self::FramePointer),
342             "csr" => Ok(Self::CalleeSaved),
343             "vmctx" => Ok(Self::VMContext),
344             "sigid" => Ok(Self::SignatureId),
345             "stack_limit" => Ok(Self::StackLimit),
346             _ if s.starts_with("sarg(") => {
347                 if !s.ends_with(")") {
348                     return Err(());
349                 }
350                 // Parse 'sarg(size)'
351                 let size: u32 = s["sarg(".len()..s.len() - 1].parse().map_err(|_| ())?;
352                 Ok(Self::StructArgument(size))
353             }
354             _ => Err(()),
355         }
356     }
357 }
358 
359 /// An external function.
360 ///
361 /// Information about a function that can be called directly with a direct `call` instruction.
362 #[derive(Clone, Debug)]
363 #[cfg_attr(feature = "enable-serde", derive(Serialize, Deserialize))]
364 pub struct ExtFuncData {
365     /// Name of the external function.
366     pub name: ExternalName,
367     /// Call signature of function.
368     pub signature: SigRef,
369     /// Will this function be defined nearby, such that it will always be a certain distance away,
370     /// after linking? If so, references to it can avoid going through a GOT or PLT. Note that
371     /// symbols meant to be preemptible cannot be considered colocated.
372     ///
373     /// If `true`, some backends may use relocation forms that have limited range. The exact
374     /// distance depends on the code model in use. Currently on AArch64, for example, Cranelift
375     /// uses a custom code model supporting up to +/- 128MB displacements. If it is unknown how
376     /// far away the target will be, it is best not to set the `colocated` flag; in general, this
377     /// flag is best used when the target is known to be in the same unit of code generation, such
378     /// as a Wasm module.
379     ///
380     /// See the documentation for [`RelocDistance`](crate::machinst::RelocDistance) for more details. A
381     /// `colocated` flag value of `true` implies `RelocDistance::Near`.
382     pub colocated: bool,
383 }
384 
385 impl fmt::Display for ExtFuncData {
386     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
387         if self.colocated {
388             write!(f, "colocated ")?;
389         }
390         write!(f, "{} {}", self.name, self.signature)
391     }
392 }
393 
394 impl ExtFuncData {
395     /// Return an estimate of the distance to the referred-to function symbol.
396     pub fn reloc_distance(&self) -> RelocDistance {
397         if self.colocated {
398             RelocDistance::Near
399         } else {
400             RelocDistance::Far
401         }
402     }
403 }
404 
405 #[cfg(test)]
406 mod tests {
407     use super::*;
408     use crate::ir::types::{B8, F32, I32};
409     use alloc::string::ToString;
410 
411     #[test]
412     fn argument_type() {
413         let t = AbiParam::new(I32);
414         assert_eq!(t.to_string(), "i32");
415         let mut t = t.uext();
416         assert_eq!(t.to_string(), "i32 uext");
417         assert_eq!(t.sext().to_string(), "i32 sext");
418         t.purpose = ArgumentPurpose::StructReturn;
419         assert_eq!(t.to_string(), "i32 uext sret");
420         t.legalized_to_pointer = true;
421         assert_eq!(t.to_string(), "i32 ptr uext sret");
422     }
423 
424     #[test]
425     fn argument_purpose() {
426         let all_purpose = [
427             (ArgumentPurpose::Normal, "normal"),
428             (ArgumentPurpose::StructReturn, "sret"),
429             (ArgumentPurpose::Link, "link"),
430             (ArgumentPurpose::FramePointer, "fp"),
431             (ArgumentPurpose::CalleeSaved, "csr"),
432             (ArgumentPurpose::VMContext, "vmctx"),
433             (ArgumentPurpose::SignatureId, "sigid"),
434             (ArgumentPurpose::StackLimit, "stack_limit"),
435             (ArgumentPurpose::StructArgument(42), "sarg(42)"),
436         ];
437         for &(e, n) in &all_purpose {
438             assert_eq!(e.to_string(), n);
439             assert_eq!(Ok(e), n.parse());
440         }
441     }
442 
443     #[test]
444     fn call_conv() {
445         for &cc in &[
446             CallConv::Fast,
447             CallConv::Cold,
448             CallConv::SystemV,
449             CallConv::WindowsFastcall,
450             CallConv::BaldrdashSystemV,
451             CallConv::BaldrdashWindows,
452             CallConv::Baldrdash2020,
453         ] {
454             assert_eq!(Ok(cc), cc.to_string().parse())
455         }
456     }
457 
458     #[test]
459     fn signatures() {
460         let mut sig = Signature::new(CallConv::BaldrdashSystemV);
461         assert_eq!(sig.to_string(), "() baldrdash_system_v");
462         sig.params.push(AbiParam::new(I32));
463         assert_eq!(sig.to_string(), "(i32) baldrdash_system_v");
464         sig.returns.push(AbiParam::new(F32));
465         assert_eq!(sig.to_string(), "(i32) -> f32 baldrdash_system_v");
466         sig.params.push(AbiParam::new(I32.by(4).unwrap()));
467         assert_eq!(sig.to_string(), "(i32, i32x4) -> f32 baldrdash_system_v");
468         sig.returns.push(AbiParam::new(B8));
469         assert_eq!(
470             sig.to_string(),
471             "(i32, i32x4) -> f32, b8 baldrdash_system_v"
472         );
473     }
474 }
475