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