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::{ArgumentLoc, ExternalName, SigRef, Type};
9 use crate::isa::{CallConv, RegInfo, RegUnit};
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     /// Return an object that can display `self` with correct register names.
54     pub fn display<'a, R: Into<Option<&'a RegInfo>>>(&'a self, regs: R) -> DisplaySignature<'a> {
55         DisplaySignature(self, regs.into())
56     }
57 
58     /// Find the index of a presumed unique special-purpose parameter.
59     pub fn special_param_index(&self, purpose: ArgumentPurpose) -> Option<usize> {
60         self.params.iter().rposition(|arg| arg.purpose == purpose)
61     }
62 
63     /// Find the index of a presumed unique special-purpose parameter.
64     pub fn special_return_index(&self, purpose: ArgumentPurpose) -> Option<usize> {
65         self.returns.iter().rposition(|arg| arg.purpose == purpose)
66     }
67 
68     /// Does this signature have a parameter whose `ArgumentPurpose` is
69     /// `purpose`?
70     pub fn uses_special_param(&self, purpose: ArgumentPurpose) -> bool {
71         self.special_param_index(purpose).is_some()
72     }
73 
74     /// Does this signature have a return whose `ArgumentPurpose` is `purpose`?
75     pub fn uses_special_return(&self, purpose: ArgumentPurpose) -> bool {
76         self.special_return_index(purpose).is_some()
77     }
78 
79     /// How many special parameters does this function have?
80     pub fn num_special_params(&self) -> usize {
81         self.params
82             .iter()
83             .filter(|p| p.purpose != ArgumentPurpose::Normal)
84             .count()
85     }
86 
87     /// How many special returns does this function have?
88     pub fn num_special_returns(&self) -> usize {
89         self.returns
90             .iter()
91             .filter(|r| r.purpose != ArgumentPurpose::Normal)
92             .count()
93     }
94 
95     /// Does this signature take an struct return pointer parameter?
96     pub fn uses_struct_return_param(&self) -> bool {
97         self.uses_special_param(ArgumentPurpose::StructReturn)
98     }
99 
100     /// Does this return more than one normal value? (Pre-struct return
101     /// legalization)
102     pub fn is_multi_return(&self) -> bool {
103         self.returns
104             .iter()
105             .filter(|r| r.purpose == ArgumentPurpose::Normal)
106             .count()
107             > 1
108     }
109 }
110 
111 /// Wrapper type capable of displaying a `Signature` with correct register names.
112 pub struct DisplaySignature<'a>(&'a Signature, Option<&'a RegInfo>);
113 
114 fn write_list(f: &mut fmt::Formatter, args: &[AbiParam], regs: Option<&RegInfo>) -> fmt::Result {
115     match args.split_first() {
116         None => {}
117         Some((first, rest)) => {
118             write!(f, "{}", first.display(regs))?;
119             for arg in rest {
120                 write!(f, ", {}", arg.display(regs))?;
121             }
122         }
123     }
124     Ok(())
125 }
126 
127 impl<'a> fmt::Display for DisplaySignature<'a> {
128     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
129         write!(f, "(")?;
130         write_list(f, &self.0.params, self.1)?;
131         write!(f, ")")?;
132         if !self.0.returns.is_empty() {
133             write!(f, " -> ")?;
134             write_list(f, &self.0.returns, self.1)?;
135         }
136         write!(f, " {}", self.0.call_conv)
137     }
138 }
139 
140 impl fmt::Display for Signature {
141     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
142         self.display(None).fmt(f)
143     }
144 }
145 
146 /// Function parameter or return value descriptor.
147 ///
148 /// This describes the value type being passed to or from a function along with flags that affect
149 /// how the argument is passed.
150 #[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)]
151 #[cfg_attr(feature = "enable-serde", derive(Serialize, Deserialize))]
152 pub struct AbiParam {
153     /// Type of the argument value.
154     pub value_type: Type,
155     /// Special purpose of argument, or `Normal`.
156     pub purpose: ArgumentPurpose,
157     /// Method for extending argument to a full register.
158     pub extension: ArgumentExtension,
159 
160     /// ABI-specific location of this argument, or `Unassigned` for arguments that have not yet
161     /// been legalized.
162     pub location: ArgumentLoc,
163     /// Was the argument converted to pointer during legalization?
164     pub legalized_to_pointer: bool,
165 }
166 
167 impl AbiParam {
168     /// Create a parameter with default flags.
169     pub fn new(vt: Type) -> Self {
170         Self {
171             value_type: vt,
172             extension: ArgumentExtension::None,
173             purpose: ArgumentPurpose::Normal,
174             location: Default::default(),
175             legalized_to_pointer: false,
176         }
177     }
178 
179     /// Create a special-purpose parameter that is not (yet) bound to a specific register.
180     pub fn special(vt: Type, purpose: ArgumentPurpose) -> Self {
181         Self {
182             value_type: vt,
183             extension: ArgumentExtension::None,
184             purpose,
185             location: Default::default(),
186             legalized_to_pointer: false,
187         }
188     }
189 
190     /// Create a parameter for a special-purpose register.
191     pub fn special_reg(vt: Type, purpose: ArgumentPurpose, regunit: RegUnit) -> Self {
192         Self {
193             value_type: vt,
194             extension: ArgumentExtension::None,
195             purpose,
196             location: ArgumentLoc::Reg(regunit),
197             legalized_to_pointer: false,
198         }
199     }
200 
201     /// Convert `self` to a parameter with the `uext` flag set.
202     pub fn uext(self) -> Self {
203         debug_assert!(self.value_type.is_int(), "uext on {} arg", self.value_type);
204         Self {
205             extension: ArgumentExtension::Uext,
206             ..self
207         }
208     }
209 
210     /// Convert `self` to a parameter type with the `sext` flag set.
211     pub fn sext(self) -> Self {
212         debug_assert!(self.value_type.is_int(), "sext on {} arg", self.value_type);
213         Self {
214             extension: ArgumentExtension::Sext,
215             ..self
216         }
217     }
218 
219     /// Return an object that can display `self` with correct register names.
220     pub fn display<'a, R: Into<Option<&'a RegInfo>>>(&'a self, regs: R) -> DisplayAbiParam<'a> {
221         DisplayAbiParam(self, regs.into())
222     }
223 }
224 
225 /// Wrapper type capable of displaying a `AbiParam` with correct register names.
226 pub struct DisplayAbiParam<'a>(&'a AbiParam, Option<&'a RegInfo>);
227 
228 impl<'a> fmt::Display for DisplayAbiParam<'a> {
229     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
230         write!(f, "{}", self.0.value_type)?;
231         if self.0.legalized_to_pointer {
232             write!(f, " ptr")?;
233         }
234         match self.0.extension {
235             ArgumentExtension::None => {}
236             ArgumentExtension::Uext => write!(f, " uext")?,
237             ArgumentExtension::Sext => write!(f, " sext")?,
238         }
239         if self.0.purpose != ArgumentPurpose::Normal {
240             write!(f, " {}", self.0.purpose)?;
241         }
242 
243         if self.0.location.is_assigned() {
244             write!(f, " [{}]", self.0.location.display(self.1))?;
245         }
246 
247         Ok(())
248     }
249 }
250 
251 impl fmt::Display for AbiParam {
252     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
253         self.display(None).fmt(f)
254     }
255 }
256 
257 /// Function argument extension options.
258 ///
259 /// On some architectures, small integer function arguments and/or return values are extended to
260 /// the width of a general-purpose register.
261 ///
262 /// This attribute specifies how an argument or return value should be extended *if the platform
263 /// and ABI require it*. Because the frontend (CLIF generator) does not know anything about the
264 /// particulars of the target's ABI, and the CLIF should be platform-independent, these attributes
265 /// specify *how* to extend (according to the signedness of the original program) rather than
266 /// *whether* to extend.
267 ///
268 /// For example, on x86-64, the SystemV ABI does not require extensions of narrow values, so these
269 /// `ArgumentExtension` attributes are ignored; but in the Baldrdash (SpiderMonkey) ABI on the same
270 /// platform, all narrow values *are* extended, so these attributes may lead to extra
271 /// zero/sign-extend instructions in the generated machine code.
272 #[derive(Copy, Clone, PartialEq, Eq, Debug, Hash)]
273 #[cfg_attr(feature = "enable-serde", derive(Serialize, Deserialize))]
274 pub enum ArgumentExtension {
275     /// No extension, high bits are indeterminate.
276     None,
277     /// Unsigned extension: high bits in register are 0.
278     Uext,
279     /// Signed extension: high bits in register replicate sign bit.
280     Sext,
281 }
282 
283 /// The special purpose of a function argument.
284 ///
285 /// Function arguments and return values are used to pass user program values between functions,
286 /// but they are also used to represent special registers with significance to the ABI such as
287 /// frame pointers and callee-saved registers.
288 ///
289 /// The argument purpose is used to indicate any special meaning of an argument or return value.
290 #[derive(Copy, Clone, PartialEq, Eq, Debug, Hash)]
291 #[cfg_attr(feature = "enable-serde", derive(Serialize, Deserialize))]
292 pub enum ArgumentPurpose {
293     /// A normal user program value passed to or from a function.
294     Normal,
295 
296     /// A C struct passed as argument.
297     StructArgument(u32),
298 
299     /// Struct return pointer.
300     ///
301     /// When a function needs to return more data than will fit in registers, the caller passes a
302     /// pointer to a memory location where the return value can be written. In some ABIs, this
303     /// struct return pointer is passed in a specific register.
304     ///
305     /// This argument kind can also appear as a return value for ABIs that require a function with
306     /// a `StructReturn` pointer argument to also return that pointer in a register.
307     StructReturn,
308 
309     /// The link register.
310     ///
311     /// Most RISC architectures implement calls by saving the return address in a designated
312     /// register rather than pushing it on the stack. This is represented with a `Link` argument.
313     ///
314     /// Similarly, some return instructions expect the return address in a register represented as
315     /// a `Link` return value.
316     Link,
317 
318     /// The frame pointer.
319     ///
320     /// This indicates the frame pointer register which has a special meaning in some ABIs.
321     ///
322     /// The frame pointer appears as an argument and as a return value since it is a callee-saved
323     /// register.
324     FramePointer,
325 
326     /// A callee-saved register.
327     ///
328     /// Some calling conventions have registers that must be saved by the callee. These registers
329     /// are represented as `CalleeSaved` arguments and return values.
330     CalleeSaved,
331 
332     /// A VM context pointer.
333     ///
334     /// This is a pointer to a context struct containing details about the current sandbox. It is
335     /// used as a base pointer for `vmctx` global values.
336     VMContext,
337 
338     /// A signature identifier.
339     ///
340     /// This is a special-purpose argument used to identify the calling convention expected by the
341     /// caller in an indirect call. The callee can verify that the expected signature ID matches.
342     SignatureId,
343 
344     /// A stack limit pointer.
345     ///
346     /// This is a pointer to a stack limit. It is used to check the current stack pointer
347     /// against. Can only appear once in a signature.
348     StackLimit,
349 
350     /// A callee TLS value.
351     ///
352     /// In the Baldrdash-2020 calling convention, the stack upon entry to the callee contains the
353     /// TLS-register values for the caller and the callee. This argument is used to provide the
354     /// value for the callee.
355     CalleeTLS,
356 
357     /// A caller TLS value.
358     ///
359     /// In the Baldrdash-2020 calling convention, the stack upon entry to the callee contains the
360     /// TLS-register values for the caller and the callee. This argument is used to provide the
361     /// value for the caller.
362     CallerTLS,
363 }
364 
365 impl fmt::Display for ArgumentPurpose {
366     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
367         f.write_str(match self {
368             Self::Normal => "normal",
369             Self::StructArgument(size) => return write!(f, "sarg({})", size),
370             Self::StructReturn => "sret",
371             Self::Link => "link",
372             Self::FramePointer => "fp",
373             Self::CalleeSaved => "csr",
374             Self::VMContext => "vmctx",
375             Self::SignatureId => "sigid",
376             Self::StackLimit => "stack_limit",
377             Self::CalleeTLS => "callee_tls",
378             Self::CallerTLS => "caller_tls",
379         })
380     }
381 }
382 
383 impl FromStr for ArgumentPurpose {
384     type Err = ();
385     fn from_str(s: &str) -> Result<Self, ()> {
386         match s {
387             "normal" => Ok(Self::Normal),
388             "sret" => Ok(Self::StructReturn),
389             "link" => Ok(Self::Link),
390             "fp" => Ok(Self::FramePointer),
391             "csr" => Ok(Self::CalleeSaved),
392             "vmctx" => Ok(Self::VMContext),
393             "sigid" => Ok(Self::SignatureId),
394             "stack_limit" => Ok(Self::StackLimit),
395             _ if s.starts_with("sarg(") => {
396                 if !s.ends_with(")") {
397                     return Err(());
398                 }
399                 // Parse 'sarg(size)'
400                 let size: u32 = s["sarg(".len()..s.len() - 1].parse().map_err(|_| ())?;
401                 Ok(Self::StructArgument(size))
402             }
403             _ => Err(()),
404         }
405     }
406 }
407 
408 /// An external function.
409 ///
410 /// Information about a function that can be called directly with a direct `call` instruction.
411 #[derive(Clone, Debug)]
412 #[cfg_attr(feature = "enable-serde", derive(Serialize, Deserialize))]
413 pub struct ExtFuncData {
414     /// Name of the external function.
415     pub name: ExternalName,
416     /// Call signature of function.
417     pub signature: SigRef,
418     /// Will this function be defined nearby, such that it will always be a certain distance away,
419     /// after linking? If so, references to it can avoid going through a GOT or PLT. Note that
420     /// symbols meant to be preemptible cannot be considered colocated.
421     ///
422     /// If `true`, some backends may use relocation forms that have limited range. The exact
423     /// distance depends on the code model in use. Currently on AArch64, for example, Cranelift
424     /// uses a custom code model supporting up to +/- 128MB displacements. If it is unknown how
425     /// far away the target will be, it is best not to set the `colocated` flag; in general, this
426     /// flag is best used when the target is known to be in the same unit of code generation, such
427     /// as a Wasm module.
428     ///
429     /// See the documentation for [`RelocDistance`](crate::machinst::RelocDistance) for more details. A
430     /// `colocated` flag value of `true` implies `RelocDistance::Near`.
431     pub colocated: bool,
432 }
433 
434 impl fmt::Display for ExtFuncData {
435     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
436         if self.colocated {
437             write!(f, "colocated ")?;
438         }
439         write!(f, "{} {}", self.name, self.signature)
440     }
441 }
442 
443 impl ExtFuncData {
444     /// Return an estimate of the distance to the referred-to function symbol.
445     pub fn reloc_distance(&self) -> RelocDistance {
446         if self.colocated {
447             RelocDistance::Near
448         } else {
449             RelocDistance::Far
450         }
451     }
452 }
453 
454 #[cfg(test)]
455 mod tests {
456     use super::*;
457     use crate::ir::types::{B8, F32, I32};
458     use alloc::string::ToString;
459 
460     #[test]
461     fn argument_type() {
462         let t = AbiParam::new(I32);
463         assert_eq!(t.to_string(), "i32");
464         let mut t = t.uext();
465         assert_eq!(t.to_string(), "i32 uext");
466         assert_eq!(t.sext().to_string(), "i32 sext");
467         t.purpose = ArgumentPurpose::StructReturn;
468         assert_eq!(t.to_string(), "i32 uext sret");
469         t.legalized_to_pointer = true;
470         assert_eq!(t.to_string(), "i32 ptr uext sret");
471     }
472 
473     #[test]
474     fn argument_purpose() {
475         let all_purpose = [
476             (ArgumentPurpose::Normal, "normal"),
477             (ArgumentPurpose::StructReturn, "sret"),
478             (ArgumentPurpose::Link, "link"),
479             (ArgumentPurpose::FramePointer, "fp"),
480             (ArgumentPurpose::CalleeSaved, "csr"),
481             (ArgumentPurpose::VMContext, "vmctx"),
482             (ArgumentPurpose::SignatureId, "sigid"),
483             (ArgumentPurpose::StackLimit, "stack_limit"),
484             (ArgumentPurpose::StructArgument(42), "sarg(42)"),
485         ];
486         for &(e, n) in &all_purpose {
487             assert_eq!(e.to_string(), n);
488             assert_eq!(Ok(e), n.parse());
489         }
490     }
491 
492     #[test]
493     fn call_conv() {
494         for &cc in &[
495             CallConv::Fast,
496             CallConv::Cold,
497             CallConv::SystemV,
498             CallConv::WindowsFastcall,
499             CallConv::BaldrdashSystemV,
500             CallConv::BaldrdashWindows,
501             CallConv::Baldrdash2020,
502         ] {
503             assert_eq!(Ok(cc), cc.to_string().parse())
504         }
505     }
506 
507     #[test]
508     fn signatures() {
509         let mut sig = Signature::new(CallConv::BaldrdashSystemV);
510         assert_eq!(sig.to_string(), "() baldrdash_system_v");
511         sig.params.push(AbiParam::new(I32));
512         assert_eq!(sig.to_string(), "(i32) baldrdash_system_v");
513         sig.returns.push(AbiParam::new(F32));
514         assert_eq!(sig.to_string(), "(i32) -> f32 baldrdash_system_v");
515         sig.params.push(AbiParam::new(I32.by(4).unwrap()));
516         assert_eq!(sig.to_string(), "(i32, i32x4) -> f32 baldrdash_system_v");
517         sig.returns.push(AbiParam::new(B8));
518         assert_eq!(
519             sig.to_string(),
520             "(i32, i32x4) -> f32, b8 baldrdash_system_v"
521         );
522 
523         // Order does not matter.
524         sig.params[0].location = ArgumentLoc::Stack(24);
525         sig.params[1].location = ArgumentLoc::Stack(8);
526 
527         // Writing ABI-annotated signatures.
528         assert_eq!(
529             sig.to_string(),
530             "(i32 [24], i32x4 [8]) -> f32, b8 baldrdash_system_v"
531         );
532     }
533 }
534