cranelift_codegen/ir/
extfunc.rs

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