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, I32, I8};
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}