1use crate::ir::{ExternalName, SigRef, Type};
9use crate::isa::CallConv;
10use alloc::vec::Vec;
11use core::fmt;
12use core::str::FromStr;
13#[cfg(feature = "enable-serde")]
14use serde_derive::{Deserialize, Serialize};
15
16use super::function::FunctionParameters;
17
18#[derive(Clone, Debug, PartialEq, Eq, Hash)]
26#[cfg_attr(feature = "enable-serde", derive(Serialize, Deserialize))]
27pub struct Signature {
28    pub params: Vec<AbiParam>,
30    pub returns: Vec<AbiParam>,
32
33    pub call_conv: CallConv,
35}
36
37impl Signature {
38    pub fn new(call_conv: CallConv) -> Self {
40        Self {
41            params: Vec::new(),
42            returns: Vec::new(),
43            call_conv,
44        }
45    }
46
47    pub fn clear(&mut self, call_conv: CallConv) {
49        self.params.clear();
50        self.returns.clear();
51        self.call_conv = call_conv;
52    }
53
54    pub fn special_param_index(&self, purpose: ArgumentPurpose) -> Option<usize> {
56        self.params.iter().rposition(|arg| arg.purpose == purpose)
57    }
58
59    pub fn special_return_index(&self, purpose: ArgumentPurpose) -> Option<usize> {
61        self.returns.iter().rposition(|arg| arg.purpose == purpose)
62    }
63
64    pub fn uses_special_param(&self, purpose: ArgumentPurpose) -> bool {
67        self.special_param_index(purpose).is_some()
68    }
69
70    pub fn uses_special_return(&self, purpose: ArgumentPurpose) -> bool {
72        self.special_return_index(purpose).is_some()
73    }
74
75    pub fn num_special_params(&self) -> usize {
77        self.params
78            .iter()
79            .filter(|p| p.purpose != ArgumentPurpose::Normal)
80            .count()
81    }
82
83    pub fn num_special_returns(&self) -> usize {
85        self.returns
86            .iter()
87            .filter(|r| r.purpose != ArgumentPurpose::Normal)
88            .count()
89    }
90
91    pub fn uses_struct_return_param(&self) -> bool {
93        self.uses_special_param(ArgumentPurpose::StructReturn)
94    }
95
96    pub fn is_multi_return(&self) -> bool {
99        self.returns
100            .iter()
101            .filter(|r| r.purpose == ArgumentPurpose::Normal)
102            .count()
103            > 1
104    }
105}
106
107fn write_list(f: &mut fmt::Formatter, args: &[AbiParam]) -> fmt::Result {
108    match args.split_first() {
109        None => {}
110        Some((first, rest)) => {
111            write!(f, "{first}")?;
112            for arg in rest {
113                write!(f, ", {arg}")?;
114            }
115        }
116    }
117    Ok(())
118}
119
120impl fmt::Display for Signature {
121    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
122        write!(f, "(")?;
123        write_list(f, &self.params)?;
124        write!(f, ")")?;
125        if !self.returns.is_empty() {
126            write!(f, " -> ")?;
127            write_list(f, &self.returns)?;
128        }
129        write!(f, " {}", self.call_conv)
130    }
131}
132
133#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)]
138#[cfg_attr(feature = "enable-serde", derive(Serialize, Deserialize))]
139pub struct AbiParam {
140    pub value_type: Type,
142    pub purpose: ArgumentPurpose,
144    pub extension: ArgumentExtension,
146}
147
148impl AbiParam {
149    pub fn new(vt: Type) -> Self {
151        Self {
152            value_type: vt,
153            extension: ArgumentExtension::None,
154            purpose: ArgumentPurpose::Normal,
155        }
156    }
157
158    pub fn special(vt: Type, purpose: ArgumentPurpose) -> Self {
160        Self {
161            value_type: vt,
162            extension: ArgumentExtension::None,
163            purpose,
164        }
165    }
166
167    pub fn uext(self) -> Self {
169        debug_assert!(self.value_type.is_int(), "uext on {} arg", self.value_type);
170        Self {
171            extension: ArgumentExtension::Uext,
172            ..self
173        }
174    }
175
176    pub fn sext(self) -> Self {
178        debug_assert!(self.value_type.is_int(), "sext on {} arg", self.value_type);
179        Self {
180            extension: ArgumentExtension::Sext,
181            ..self
182        }
183    }
184}
185
186impl fmt::Display for AbiParam {
187    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
188        write!(f, "{}", self.value_type)?;
189        match self.extension {
190            ArgumentExtension::None => {}
191            ArgumentExtension::Uext => write!(f, " uext")?,
192            ArgumentExtension::Sext => write!(f, " sext")?,
193        }
194        if self.purpose != ArgumentPurpose::Normal {
195            write!(f, " {}", self.purpose)?;
196        }
197        Ok(())
198    }
199}
200
201#[derive(Copy, Clone, PartialEq, Eq, Debug, Hash)]
212#[cfg_attr(feature = "enable-serde", derive(Serialize, Deserialize))]
213pub enum ArgumentExtension {
214    None,
216    Uext,
218    Sext,
220}
221
222#[derive(Copy, Clone, PartialEq, Eq, Debug, Hash)]
230#[cfg_attr(feature = "enable-serde", derive(Serialize, Deserialize))]
231pub enum ArgumentPurpose {
232    Normal,
234
235    StructArgument(
240        u32,
242    ),
243
244    StructReturn,
253
254    VMContext,
259}
260
261impl fmt::Display for ArgumentPurpose {
262    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
263        f.write_str(match self {
264            Self::Normal => "normal",
265            Self::StructArgument(size) => return write!(f, "sarg({size})"),
266            Self::StructReturn => "sret",
267            Self::VMContext => "vmctx",
268        })
269    }
270}
271
272impl FromStr for ArgumentPurpose {
273    type Err = ();
274    fn from_str(s: &str) -> Result<Self, ()> {
275        match s {
276            "normal" => Ok(Self::Normal),
277            "sret" => Ok(Self::StructReturn),
278            "vmctx" => Ok(Self::VMContext),
279            _ if s.starts_with("sarg(") => {
280                if !s.ends_with(")") {
281                    return Err(());
282                }
283                let size: u32 = s["sarg(".len()..s.len() - 1].parse().map_err(|_| ())?;
285                Ok(Self::StructArgument(size))
286            }
287            _ => Err(()),
288        }
289    }
290}
291
292#[derive(Clone, Debug, PartialEq, Hash)]
296#[cfg_attr(feature = "enable-serde", derive(Serialize, Deserialize))]
297pub struct ExtFuncData {
298    pub name: ExternalName,
300    pub signature: SigRef,
302    pub colocated: bool,
316}
317
318impl ExtFuncData {
319    pub fn display<'a>(
322        &'a self,
323        params: Option<&'a FunctionParameters>,
324    ) -> DisplayableExtFuncData<'a> {
325        DisplayableExtFuncData {
326            ext_func: self,
327            params,
328        }
329    }
330}
331
332pub struct DisplayableExtFuncData<'a> {
334    ext_func: &'a ExtFuncData,
335    params: Option<&'a FunctionParameters>,
336}
337
338impl<'a> fmt::Display for DisplayableExtFuncData<'a> {
339    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
340        if self.ext_func.colocated {
341            write!(f, "colocated ")?;
342        }
343        write!(
344            f,
345            "{} {}",
346            self.ext_func.name.display(self.params),
347            self.ext_func.signature
348        )
349    }
350}
351
352#[cfg(test)]
353mod tests {
354    use super::*;
355    use crate::ir::types::{F32, I8, I32};
356    use alloc::string::ToString;
357
358    #[test]
359    fn argument_type() {
360        let t = AbiParam::new(I32);
361        assert_eq!(t.to_string(), "i32");
362        let mut t = t.uext();
363        assert_eq!(t.to_string(), "i32 uext");
364        assert_eq!(t.sext().to_string(), "i32 sext");
365        t.purpose = ArgumentPurpose::StructReturn;
366        assert_eq!(t.to_string(), "i32 uext sret");
367    }
368
369    #[test]
370    fn argument_purpose() {
371        let all_purpose = [
372            (ArgumentPurpose::Normal, "normal"),
373            (ArgumentPurpose::StructReturn, "sret"),
374            (ArgumentPurpose::VMContext, "vmctx"),
375            (ArgumentPurpose::StructArgument(42), "sarg(42)"),
376        ];
377        for &(e, n) in &all_purpose {
378            assert_eq!(e.to_string(), n);
379            assert_eq!(Ok(e), n.parse());
380        }
381    }
382
383    #[test]
384    fn call_conv() {
385        for &cc in &[
386            CallConv::Fast,
387            CallConv::Cold,
388            CallConv::SystemV,
389            CallConv::WindowsFastcall,
390        ] {
391            assert_eq!(Ok(cc), cc.to_string().parse())
392        }
393    }
394
395    #[test]
396    fn signatures() {
397        let mut sig = Signature::new(CallConv::WindowsFastcall);
398        assert_eq!(sig.to_string(), "() windows_fastcall");
399        sig.params.push(AbiParam::new(I32));
400        assert_eq!(sig.to_string(), "(i32) windows_fastcall");
401        sig.returns.push(AbiParam::new(F32));
402        assert_eq!(sig.to_string(), "(i32) -> f32 windows_fastcall");
403        sig.params.push(AbiParam::new(I32.by(4).unwrap()));
404        assert_eq!(sig.to_string(), "(i32, i32x4) -> f32 windows_fastcall");
405        sig.returns.push(AbiParam::new(I8));
406        assert_eq!(sig.to_string(), "(i32, i32x4) -> f32, i8 windows_fastcall");
407    }
408}