1747ad3c4Slazypassion //! External function calls.
2747ad3c4Slazypassion //!
3747ad3c4Slazypassion //! To a Cranelift function, all functions are "external". Directly called functions must be
4747ad3c4Slazypassion //! declared in the preamble, and all function calls must have a signature.
5747ad3c4Slazypassion //!
6747ad3c4Slazypassion //! This module declares the data types used to represent external functions and call signatures.
7747ad3c4Slazypassion
843a86f14SBenjamin Bouvier use crate::ir::{ExternalName, SigRef, Type};
943a86f14SBenjamin Bouvier use crate::isa::CallConv;
10bb8fa40eSbjorn3 use alloc::vec::Vec;
11747ad3c4Slazypassion use core::fmt;
12747ad3c4Slazypassion use core::str::FromStr;
13b2551bb4SYury Delendik #[cfg(feature = "enable-serde")]
149ec02f9dSChristopher Serr use serde_derive::{Deserialize, Serialize};
15747ad3c4Slazypassion
168a9b1a90SBenjamin Bouvier use super::function::FunctionParameters;
178a9b1a90SBenjamin Bouvier
18747ad3c4Slazypassion /// Function signature.
19747ad3c4Slazypassion ///
20747ad3c4Slazypassion /// The function signature describes the types of formal parameters and return values along with
21747ad3c4Slazypassion /// other details that are needed to call a function correctly.
22747ad3c4Slazypassion ///
23747ad3c4Slazypassion /// A signature can optionally include ISA-specific ABI information which specifies exactly how
24747ad3c4Slazypassion /// arguments and return values are passed.
25747ad3c4Slazypassion #[derive(Clone, Debug, PartialEq, Eq, Hash)]
26b2551bb4SYury Delendik #[cfg_attr(feature = "enable-serde", derive(Serialize, Deserialize))]
27747ad3c4Slazypassion pub struct Signature {
28747ad3c4Slazypassion /// The arguments passed to the function.
29747ad3c4Slazypassion pub params: Vec<AbiParam>,
30747ad3c4Slazypassion /// Values returned from the function.
31747ad3c4Slazypassion pub returns: Vec<AbiParam>,
32747ad3c4Slazypassion
33747ad3c4Slazypassion /// Calling convention.
34747ad3c4Slazypassion pub call_conv: CallConv,
35747ad3c4Slazypassion }
36747ad3c4Slazypassion
37747ad3c4Slazypassion impl Signature {
38747ad3c4Slazypassion /// Create a new blank signature.
new(call_conv: CallConv) -> Self39747ad3c4Slazypassion pub fn new(call_conv: CallConv) -> Self {
40747ad3c4Slazypassion Self {
41747ad3c4Slazypassion params: Vec::new(),
42747ad3c4Slazypassion returns: Vec::new(),
43747ad3c4Slazypassion call_conv,
44747ad3c4Slazypassion }
45747ad3c4Slazypassion }
46747ad3c4Slazypassion
47747ad3c4Slazypassion /// Clear the signature so it is identical to a fresh one returned by `new()`.
clear(&mut self, call_conv: CallConv)48747ad3c4Slazypassion pub fn clear(&mut self, call_conv: CallConv) {
49747ad3c4Slazypassion self.params.clear();
50747ad3c4Slazypassion self.returns.clear();
51747ad3c4Slazypassion self.call_conv = call_conv;
52747ad3c4Slazypassion }
53747ad3c4Slazypassion
54747ad3c4Slazypassion /// Find the index of a presumed unique special-purpose parameter.
special_param_index(&self, purpose: ArgumentPurpose) -> Option<usize>55747ad3c4Slazypassion pub fn special_param_index(&self, purpose: ArgumentPurpose) -> Option<usize> {
56747ad3c4Slazypassion self.params.iter().rposition(|arg| arg.purpose == purpose)
57747ad3c4Slazypassion }
58a4948340SNick Fitzgerald
59a4948340SNick Fitzgerald /// Find the index of a presumed unique special-purpose parameter.
special_return_index(&self, purpose: ArgumentPurpose) -> Option<usize>60a4948340SNick Fitzgerald pub fn special_return_index(&self, purpose: ArgumentPurpose) -> Option<usize> {
61a4948340SNick Fitzgerald self.returns.iter().rposition(|arg| arg.purpose == purpose)
62a4948340SNick Fitzgerald }
63a4948340SNick Fitzgerald
64a4948340SNick Fitzgerald /// Does this signature have a parameter whose `ArgumentPurpose` is
65a4948340SNick Fitzgerald /// `purpose`?
uses_special_param(&self, purpose: ArgumentPurpose) -> bool66a4948340SNick Fitzgerald pub fn uses_special_param(&self, purpose: ArgumentPurpose) -> bool {
67a4948340SNick Fitzgerald self.special_param_index(purpose).is_some()
68a4948340SNick Fitzgerald }
69a4948340SNick Fitzgerald
70a4948340SNick Fitzgerald /// Does this signature have a return whose `ArgumentPurpose` is `purpose`?
uses_special_return(&self, purpose: ArgumentPurpose) -> bool71a4948340SNick Fitzgerald pub fn uses_special_return(&self, purpose: ArgumentPurpose) -> bool {
72a4948340SNick Fitzgerald self.special_return_index(purpose).is_some()
73a4948340SNick Fitzgerald }
74a4948340SNick Fitzgerald
75a4948340SNick Fitzgerald /// How many special parameters does this function have?
num_special_params(&self) -> usize76a4948340SNick Fitzgerald pub fn num_special_params(&self) -> usize {
77a4948340SNick Fitzgerald self.params
78a4948340SNick Fitzgerald .iter()
79a4948340SNick Fitzgerald .filter(|p| p.purpose != ArgumentPurpose::Normal)
80a4948340SNick Fitzgerald .count()
81a4948340SNick Fitzgerald }
82a4948340SNick Fitzgerald
83a4948340SNick Fitzgerald /// How many special returns does this function have?
num_special_returns(&self) -> usize84a4948340SNick Fitzgerald pub fn num_special_returns(&self) -> usize {
85a4948340SNick Fitzgerald self.returns
86a4948340SNick Fitzgerald .iter()
87a4948340SNick Fitzgerald .filter(|r| r.purpose != ArgumentPurpose::Normal)
88a4948340SNick Fitzgerald .count()
89a4948340SNick Fitzgerald }
90a4948340SNick Fitzgerald
91a4948340SNick Fitzgerald /// Does this signature take an struct return pointer parameter?
uses_struct_return_param(&self) -> bool92a4948340SNick Fitzgerald pub fn uses_struct_return_param(&self) -> bool {
93a4948340SNick Fitzgerald self.uses_special_param(ArgumentPurpose::StructReturn)
94a4948340SNick Fitzgerald }
95a4948340SNick Fitzgerald
96a4948340SNick Fitzgerald /// Does this return more than one normal value? (Pre-struct return
97a4948340SNick Fitzgerald /// legalization)
is_multi_return(&self) -> bool98a4948340SNick Fitzgerald pub fn is_multi_return(&self) -> bool {
99a4948340SNick Fitzgerald self.returns
100a4948340SNick Fitzgerald .iter()
101a4948340SNick Fitzgerald .filter(|r| r.purpose == ArgumentPurpose::Normal)
102a4948340SNick Fitzgerald .count()
103a4948340SNick Fitzgerald > 1
104a4948340SNick Fitzgerald }
105747ad3c4Slazypassion }
106747ad3c4Slazypassion
write_list(f: &mut fmt::Formatter, args: &[AbiParam]) -> fmt::Result10743a86f14SBenjamin Bouvier fn write_list(f: &mut fmt::Formatter, args: &[AbiParam]) -> fmt::Result {
108747ad3c4Slazypassion match args.split_first() {
109747ad3c4Slazypassion None => {}
110747ad3c4Slazypassion Some((first, rest)) => {
111a0442ea0SHamir Mahal write!(f, "{first}")?;
112747ad3c4Slazypassion for arg in rest {
113a0442ea0SHamir Mahal write!(f, ", {arg}")?;
114747ad3c4Slazypassion }
115747ad3c4Slazypassion }
116747ad3c4Slazypassion }
117747ad3c4Slazypassion Ok(())
118747ad3c4Slazypassion }
119747ad3c4Slazypassion
120747ad3c4Slazypassion impl fmt::Display for Signature {
fmt(&self, f: &mut fmt::Formatter) -> fmt::Result121747ad3c4Slazypassion fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
12243a86f14SBenjamin Bouvier write!(f, "(")?;
12343a86f14SBenjamin Bouvier write_list(f, &self.params)?;
12443a86f14SBenjamin Bouvier write!(f, ")")?;
12543a86f14SBenjamin Bouvier if !self.returns.is_empty() {
12643a86f14SBenjamin Bouvier write!(f, " -> ")?;
12743a86f14SBenjamin Bouvier write_list(f, &self.returns)?;
12843a86f14SBenjamin Bouvier }
12943a86f14SBenjamin Bouvier write!(f, " {}", self.call_conv)
130747ad3c4Slazypassion }
131747ad3c4Slazypassion }
132747ad3c4Slazypassion
133747ad3c4Slazypassion /// Function parameter or return value descriptor.
134747ad3c4Slazypassion ///
135747ad3c4Slazypassion /// This describes the value type being passed to or from a function along with flags that affect
136747ad3c4Slazypassion /// how the argument is passed.
137747ad3c4Slazypassion #[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)]
138b2551bb4SYury Delendik #[cfg_attr(feature = "enable-serde", derive(Serialize, Deserialize))]
139747ad3c4Slazypassion pub struct AbiParam {
140747ad3c4Slazypassion /// Type of the argument value.
141747ad3c4Slazypassion pub value_type: Type,
142747ad3c4Slazypassion /// Special purpose of argument, or `Normal`.
143747ad3c4Slazypassion pub purpose: ArgumentPurpose,
144747ad3c4Slazypassion /// Method for extending argument to a full register.
145747ad3c4Slazypassion pub extension: ArgumentExtension,
146747ad3c4Slazypassion }
147747ad3c4Slazypassion
148747ad3c4Slazypassion impl AbiParam {
149747ad3c4Slazypassion /// Create a parameter with default flags.
new(vt: Type) -> Self150747ad3c4Slazypassion pub fn new(vt: Type) -> Self {
151747ad3c4Slazypassion Self {
152747ad3c4Slazypassion value_type: vt,
153747ad3c4Slazypassion extension: ArgumentExtension::None,
154747ad3c4Slazypassion purpose: ArgumentPurpose::Normal,
155747ad3c4Slazypassion }
156747ad3c4Slazypassion }
157747ad3c4Slazypassion
158747ad3c4Slazypassion /// Create a special-purpose parameter that is not (yet) bound to a specific register.
special(vt: Type, purpose: ArgumentPurpose) -> Self159747ad3c4Slazypassion pub fn special(vt: Type, purpose: ArgumentPurpose) -> Self {
160747ad3c4Slazypassion Self {
161747ad3c4Slazypassion value_type: vt,
162747ad3c4Slazypassion extension: ArgumentExtension::None,
163747ad3c4Slazypassion purpose,
164747ad3c4Slazypassion }
165747ad3c4Slazypassion }
166747ad3c4Slazypassion
167747ad3c4Slazypassion /// Convert `self` to a parameter with the `uext` flag set.
uext(self) -> Self168747ad3c4Slazypassion pub fn uext(self) -> Self {
169747ad3c4Slazypassion debug_assert!(self.value_type.is_int(), "uext on {} arg", self.value_type);
170747ad3c4Slazypassion Self {
171747ad3c4Slazypassion extension: ArgumentExtension::Uext,
172747ad3c4Slazypassion ..self
173747ad3c4Slazypassion }
174747ad3c4Slazypassion }
175747ad3c4Slazypassion
176747ad3c4Slazypassion /// Convert `self` to a parameter type with the `sext` flag set.
sext(self) -> Self177747ad3c4Slazypassion pub fn sext(self) -> Self {
178747ad3c4Slazypassion debug_assert!(self.value_type.is_int(), "sext on {} arg", self.value_type);
179747ad3c4Slazypassion Self {
180747ad3c4Slazypassion extension: ArgumentExtension::Sext,
181747ad3c4Slazypassion ..self
182747ad3c4Slazypassion }
183747ad3c4Slazypassion }
184747ad3c4Slazypassion }
185747ad3c4Slazypassion
186747ad3c4Slazypassion impl fmt::Display for AbiParam {
fmt(&self, f: &mut fmt::Formatter) -> fmt::Result187747ad3c4Slazypassion fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
18843a86f14SBenjamin Bouvier write!(f, "{}", self.value_type)?;
18943a86f14SBenjamin Bouvier match self.extension {
19043a86f14SBenjamin Bouvier ArgumentExtension::None => {}
19143a86f14SBenjamin Bouvier ArgumentExtension::Uext => write!(f, " uext")?,
19243a86f14SBenjamin Bouvier ArgumentExtension::Sext => write!(f, " sext")?,
19343a86f14SBenjamin Bouvier }
19443a86f14SBenjamin Bouvier if self.purpose != ArgumentPurpose::Normal {
19543a86f14SBenjamin Bouvier write!(f, " {}", self.purpose)?;
19643a86f14SBenjamin Bouvier }
19743a86f14SBenjamin Bouvier Ok(())
198747ad3c4Slazypassion }
199747ad3c4Slazypassion }
200747ad3c4Slazypassion
201747ad3c4Slazypassion /// Function argument extension options.
202747ad3c4Slazypassion ///
203a2bbb198SChris Fallin /// On some architectures, small integer function arguments and/or return values are extended to
204a2bbb198SChris Fallin /// the width of a general-purpose register.
205a2bbb198SChris Fallin ///
206a2bbb198SChris Fallin /// This attribute specifies how an argument or return value should be extended *if the platform
207a2bbb198SChris Fallin /// and ABI require it*. Because the frontend (CLIF generator) does not know anything about the
208a2bbb198SChris Fallin /// particulars of the target's ABI, and the CLIF should be platform-independent, these attributes
209a2bbb198SChris Fallin /// specify *how* to extend (according to the signedness of the original program) rather than
210a2bbb198SChris Fallin /// *whether* to extend.
211747ad3c4Slazypassion #[derive(Copy, Clone, PartialEq, Eq, Debug, Hash)]
212b2551bb4SYury Delendik #[cfg_attr(feature = "enable-serde", derive(Serialize, Deserialize))]
213747ad3c4Slazypassion pub enum ArgumentExtension {
214747ad3c4Slazypassion /// No extension, high bits are indeterminate.
215747ad3c4Slazypassion None,
216747ad3c4Slazypassion /// Unsigned extension: high bits in register are 0.
217747ad3c4Slazypassion Uext,
218747ad3c4Slazypassion /// Signed extension: high bits in register replicate sign bit.
219747ad3c4Slazypassion Sext,
220747ad3c4Slazypassion }
221747ad3c4Slazypassion
222747ad3c4Slazypassion /// The special purpose of a function argument.
223747ad3c4Slazypassion ///
224747ad3c4Slazypassion /// Function arguments and return values are used to pass user program values between functions,
225747ad3c4Slazypassion /// but they are also used to represent special registers with significance to the ABI such as
226747ad3c4Slazypassion /// frame pointers and callee-saved registers.
227747ad3c4Slazypassion ///
228747ad3c4Slazypassion /// The argument purpose is used to indicate any special meaning of an argument or return value.
229747ad3c4Slazypassion #[derive(Copy, Clone, PartialEq, Eq, Debug, Hash)]
230b2551bb4SYury Delendik #[cfg_attr(feature = "enable-serde", derive(Serialize, Deserialize))]
231747ad3c4Slazypassion pub enum ArgumentPurpose {
232747ad3c4Slazypassion /// A normal user program value passed to or from a function.
233747ad3c4Slazypassion Normal,
234747ad3c4Slazypassion
2354431ac11Sbjorn3 /// A C struct passed as argument.
2369a340279SNoah Lev ///
2379a340279SNoah Lev /// Note that this should only be used when interacting with code following
2389a340279SNoah Lev /// a C ABI which is expecting a struct passed *by value*.
2399a340279SNoah Lev StructArgument(
2409a340279SNoah Lev /// The size, in bytes, of the struct.
2419a340279SNoah Lev u32,
2429a340279SNoah Lev ),
2434431ac11Sbjorn3
244747ad3c4Slazypassion /// Struct return pointer.
245747ad3c4Slazypassion ///
246747ad3c4Slazypassion /// When a function needs to return more data than will fit in registers, the caller passes a
247747ad3c4Slazypassion /// pointer to a memory location where the return value can be written. In some ABIs, this
248747ad3c4Slazypassion /// struct return pointer is passed in a specific register.
249747ad3c4Slazypassion ///
250747ad3c4Slazypassion /// This argument kind can also appear as a return value for ABIs that require a function with
251747ad3c4Slazypassion /// a `StructReturn` pointer argument to also return that pointer in a register.
252747ad3c4Slazypassion StructReturn,
253747ad3c4Slazypassion
254747ad3c4Slazypassion /// A VM context pointer.
255747ad3c4Slazypassion ///
256747ad3c4Slazypassion /// This is a pointer to a context struct containing details about the current sandbox. It is
257747ad3c4Slazypassion /// used as a base pointer for `vmctx` global values.
258747ad3c4Slazypassion VMContext,
259747ad3c4Slazypassion }
260747ad3c4Slazypassion
261747ad3c4Slazypassion impl fmt::Display for ArgumentPurpose {
fmt(&self, f: &mut fmt::Formatter) -> fmt::Result262747ad3c4Slazypassion fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
2634431ac11Sbjorn3 f.write_str(match self {
2644431ac11Sbjorn3 Self::Normal => "normal",
265a0442ea0SHamir Mahal Self::StructArgument(size) => return write!(f, "sarg({size})"),
2664431ac11Sbjorn3 Self::StructReturn => "sret",
2674431ac11Sbjorn3 Self::VMContext => "vmctx",
2684431ac11Sbjorn3 })
269747ad3c4Slazypassion }
270747ad3c4Slazypassion }
271747ad3c4Slazypassion
272747ad3c4Slazypassion impl FromStr for ArgumentPurpose {
273747ad3c4Slazypassion type Err = ();
from_str(s: &str) -> Result<Self, ()>274747ad3c4Slazypassion fn from_str(s: &str) -> Result<Self, ()> {
275747ad3c4Slazypassion match s {
2769f506692SPeter Huene "normal" => Ok(Self::Normal),
2779f506692SPeter Huene "sret" => Ok(Self::StructReturn),
2789f506692SPeter Huene "vmctx" => Ok(Self::VMContext),
2794431ac11Sbjorn3 _ if s.starts_with("sarg(") => {
2804431ac11Sbjorn3 if !s.ends_with(")") {
2814431ac11Sbjorn3 return Err(());
2824431ac11Sbjorn3 }
2830d4fa6d3Sbjorn3 // Parse 'sarg(size)'
2844431ac11Sbjorn3 let size: u32 = s["sarg(".len()..s.len() - 1].parse().map_err(|_| ())?;
2854431ac11Sbjorn3 Ok(Self::StructArgument(size))
2864431ac11Sbjorn3 }
287747ad3c4Slazypassion _ => Err(()),
288747ad3c4Slazypassion }
289747ad3c4Slazypassion }
290747ad3c4Slazypassion }
291747ad3c4Slazypassion
292747ad3c4Slazypassion /// An external function.
293747ad3c4Slazypassion ///
294747ad3c4Slazypassion /// Information about a function that can be called directly with a direct `call` instruction.
2958a9b1a90SBenjamin Bouvier #[derive(Clone, Debug, PartialEq, Hash)]
2962fc964eaSbjorn3 #[cfg_attr(feature = "enable-serde", derive(Serialize, Deserialize))]
297747ad3c4Slazypassion pub struct ExtFuncData {
298747ad3c4Slazypassion /// Name of the external function.
299747ad3c4Slazypassion pub name: ExternalName,
300747ad3c4Slazypassion /// Call signature of function.
301747ad3c4Slazypassion pub signature: SigRef,
302747ad3c4Slazypassion /// Will this function be defined nearby, such that it will always be a certain distance away,
303747ad3c4Slazypassion /// after linking? If so, references to it can avoid going through a GOT or PLT. Note that
304747ad3c4Slazypassion /// symbols meant to be preemptible cannot be considered colocated.
305e39b4abaSChris Fallin ///
306e39b4abaSChris Fallin /// If `true`, some backends may use relocation forms that have limited range. The exact
307e39b4abaSChris Fallin /// distance depends on the code model in use. Currently on AArch64, for example, Cranelift
308e39b4abaSChris Fallin /// uses a custom code model supporting up to +/- 128MB displacements. If it is unknown how
309e39b4abaSChris Fallin /// far away the target will be, it is best not to set the `colocated` flag; in general, this
310e39b4abaSChris Fallin /// flag is best used when the target is known to be in the same unit of code generation, such
311e39b4abaSChris Fallin /// as a Wasm module.
312e39b4abaSChris Fallin ///
3133b6544dcSNick Fitzgerald /// See the documentation for `RelocDistance` for more details. A `colocated` flag value of
3143b6544dcSNick Fitzgerald /// `true` implies `RelocDistance::Near`.
315747ad3c4Slazypassion pub colocated: bool,
316*87ed3b60SChris Fallin /// Is this function "patchable"? If so, calls to this function will
317*87ed3b60SChris Fallin /// emit additional metadata indicating how to patch them in or out.
318*87ed3b60SChris Fallin ///
319*87ed3b60SChris Fallin /// Calls to functions of any calling convention may be patchable,
320*87ed3b60SChris Fallin /// *but* only calls with no return values are patchable. This is
321*87ed3b60SChris Fallin /// because every SSA value must always be defined, and return
322*87ed3b60SChris Fallin /// values would not be if the call were patched out.
323*87ed3b60SChris Fallin pub patchable: bool,
324747ad3c4Slazypassion }
325747ad3c4Slazypassion
326e39b4abaSChris Fallin impl ExtFuncData {
3278a9b1a90SBenjamin Bouvier /// Returns a displayable version of the `ExtFuncData`, with or without extra context to
3288a9b1a90SBenjamin Bouvier /// prettify the output.
display<'a>( &'a self, params: Option<&'a FunctionParameters>, ) -> DisplayableExtFuncData<'a>3298a9b1a90SBenjamin Bouvier pub fn display<'a>(
3308a9b1a90SBenjamin Bouvier &'a self,
3318a9b1a90SBenjamin Bouvier params: Option<&'a FunctionParameters>,
3328a9b1a90SBenjamin Bouvier ) -> DisplayableExtFuncData<'a> {
3338a9b1a90SBenjamin Bouvier DisplayableExtFuncData {
3348a9b1a90SBenjamin Bouvier ext_func: self,
3358a9b1a90SBenjamin Bouvier params,
3368a9b1a90SBenjamin Bouvier }
3378a9b1a90SBenjamin Bouvier }
3388a9b1a90SBenjamin Bouvier }
3398a9b1a90SBenjamin Bouvier
3408a9b1a90SBenjamin Bouvier /// A displayable `ExtFuncData`, with extra context to prettify the output.
3418a9b1a90SBenjamin Bouvier pub struct DisplayableExtFuncData<'a> {
3428a9b1a90SBenjamin Bouvier ext_func: &'a ExtFuncData,
3438a9b1a90SBenjamin Bouvier params: Option<&'a FunctionParameters>,
3448a9b1a90SBenjamin Bouvier }
3458a9b1a90SBenjamin Bouvier
3468a9b1a90SBenjamin Bouvier impl<'a> fmt::Display for DisplayableExtFuncData<'a> {
fmt(&self, f: &mut fmt::Formatter) -> fmt::Result3478a9b1a90SBenjamin Bouvier fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
3488a9b1a90SBenjamin Bouvier if self.ext_func.colocated {
3498a9b1a90SBenjamin Bouvier write!(f, "colocated ")?;
3508a9b1a90SBenjamin Bouvier }
351*87ed3b60SChris Fallin if self.ext_func.patchable {
352*87ed3b60SChris Fallin write!(f, "patchable ")?;
353*87ed3b60SChris Fallin }
3548a9b1a90SBenjamin Bouvier write!(
3558a9b1a90SBenjamin Bouvier f,
3568a9b1a90SBenjamin Bouvier "{} {}",
3578a9b1a90SBenjamin Bouvier self.ext_func.name.display(self.params),
3588a9b1a90SBenjamin Bouvier self.ext_func.signature
3598a9b1a90SBenjamin Bouvier )
3608a9b1a90SBenjamin Bouvier }
361e39b4abaSChris Fallin }
362e39b4abaSChris Fallin
363747ad3c4Slazypassion #[cfg(test)]
364747ad3c4Slazypassion mod tests {
365747ad3c4Slazypassion use super::*;
36690ac295eSAlex Crichton use crate::ir::types::{F32, I8, I32};
36710e226f9Sbjorn3 use alloc::string::ToString;
368747ad3c4Slazypassion
369747ad3c4Slazypassion #[test]
argument_type()370747ad3c4Slazypassion fn argument_type() {
371747ad3c4Slazypassion let t = AbiParam::new(I32);
372747ad3c4Slazypassion assert_eq!(t.to_string(), "i32");
373747ad3c4Slazypassion let mut t = t.uext();
374747ad3c4Slazypassion assert_eq!(t.to_string(), "i32 uext");
375747ad3c4Slazypassion assert_eq!(t.sext().to_string(), "i32 sext");
376747ad3c4Slazypassion t.purpose = ArgumentPurpose::StructReturn;
377747ad3c4Slazypassion assert_eq!(t.to_string(), "i32 uext sret");
378747ad3c4Slazypassion }
379747ad3c4Slazypassion
380747ad3c4Slazypassion #[test]
argument_purpose()381747ad3c4Slazypassion fn argument_purpose() {
382747ad3c4Slazypassion let all_purpose = [
3834431ac11Sbjorn3 (ArgumentPurpose::Normal, "normal"),
3844431ac11Sbjorn3 (ArgumentPurpose::StructReturn, "sret"),
3854431ac11Sbjorn3 (ArgumentPurpose::VMContext, "vmctx"),
3864431ac11Sbjorn3 (ArgumentPurpose::StructArgument(42), "sarg(42)"),
387747ad3c4Slazypassion ];
3884431ac11Sbjorn3 for &(e, n) in &all_purpose {
389747ad3c4Slazypassion assert_eq!(e.to_string(), n);
390747ad3c4Slazypassion assert_eq!(Ok(e), n.parse());
391747ad3c4Slazypassion }
392747ad3c4Slazypassion }
393747ad3c4Slazypassion
394747ad3c4Slazypassion #[test]
call_conv()395747ad3c4Slazypassion fn call_conv() {
396747ad3c4Slazypassion for &cc in &[
397747ad3c4Slazypassion CallConv::Fast,
398*87ed3b60SChris Fallin CallConv::PreserveAll,
399*87ed3b60SChris Fallin CallConv::Tail,
400747ad3c4Slazypassion CallConv::SystemV,
401747ad3c4Slazypassion CallConv::WindowsFastcall,
402747ad3c4Slazypassion ] {
403747ad3c4Slazypassion assert_eq!(Ok(cc), cc.to_string().parse())
404747ad3c4Slazypassion }
405747ad3c4Slazypassion }
406747ad3c4Slazypassion
407747ad3c4Slazypassion #[test]
signatures()408747ad3c4Slazypassion fn signatures() {
40943f17652SChris Fallin let mut sig = Signature::new(CallConv::WindowsFastcall);
41043f17652SChris Fallin assert_eq!(sig.to_string(), "() windows_fastcall");
411747ad3c4Slazypassion sig.params.push(AbiParam::new(I32));
41243f17652SChris Fallin assert_eq!(sig.to_string(), "(i32) windows_fastcall");
413747ad3c4Slazypassion sig.returns.push(AbiParam::new(F32));
41443f17652SChris Fallin assert_eq!(sig.to_string(), "(i32) -> f32 windows_fastcall");
415747ad3c4Slazypassion sig.params.push(AbiParam::new(I32.by(4).unwrap()));
41643f17652SChris Fallin assert_eq!(sig.to_string(), "(i32, i32x4) -> f32 windows_fastcall");
41732a7593cSTrevor Elliott sig.returns.push(AbiParam::new(I8));
41832a7593cSTrevor Elliott assert_eq!(sig.to_string(), "(i32, i32x4) -> f32, i8 windows_fastcall");
419747ad3c4Slazypassion }
420747ad3c4Slazypassion }
421