1use crate::ir::{ExternalName, SigRef, Type};
9use crate::isa::CallConv;
10use crate::machinst::RelocDistance;
11use alloc::vec::Vec;
12use core::fmt;
13use core::str::FromStr;
14#[cfg(feature = "enable-serde")]
15use serde::{Deserialize, Serialize};
16
17use super::function::FunctionParameters;
18
19#[derive(Clone, Debug, PartialEq, Eq, Hash)]
27#[cfg_attr(feature = "enable-serde", derive(Serialize, Deserialize))]
28pub struct Signature {
29 pub params: Vec<AbiParam>,
31 pub returns: Vec<AbiParam>,
33
34 pub call_conv: CallConv,
36}
37
38impl Signature {
39 pub fn new(call_conv: CallConv) -> Self {
41 Self {
42 params: Vec::new(),
43 returns: Vec::new(),
44 call_conv,
45 }
46 }
47
48 pub fn clear(&mut self, call_conv: CallConv) {
50 self.params.clear();
51 self.returns.clear();
52 self.call_conv = call_conv;
53 }
54
55 pub fn special_param_index(&self, purpose: ArgumentPurpose) -> Option<usize> {
57 self.params.iter().rposition(|arg| arg.purpose == purpose)
58 }
59
60 pub fn special_return_index(&self, purpose: ArgumentPurpose) -> Option<usize> {
62 self.returns.iter().rposition(|arg| arg.purpose == purpose)
63 }
64
65 pub fn uses_special_param(&self, purpose: ArgumentPurpose) -> bool {
68 self.special_param_index(purpose).is_some()
69 }
70
71 pub fn uses_special_return(&self, purpose: ArgumentPurpose) -> bool {
73 self.special_return_index(purpose).is_some()
74 }
75
76 pub fn num_special_params(&self) -> usize {
78 self.params
79 .iter()
80 .filter(|p| p.purpose != ArgumentPurpose::Normal)
81 .count()
82 }
83
84 pub fn num_special_returns(&self) -> usize {
86 self.returns
87 .iter()
88 .filter(|r| r.purpose != ArgumentPurpose::Normal)
89 .count()
90 }
91
92 pub fn uses_struct_return_param(&self) -> bool {
94 self.uses_special_param(ArgumentPurpose::StructReturn)
95 }
96
97 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
108fn write_list(f: &mut fmt::Formatter, args: &[AbiParam]) -> fmt::Result {
109 match args.split_first() {
110 None => {}
111 Some((first, rest)) => {
112 write!(f, "{}", first)?;
113 for arg in rest {
114 write!(f, ", {}", arg)?;
115 }
116 }
117 }
118 Ok(())
119}
120
121impl fmt::Display for Signature {
122 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
123 write!(f, "(")?;
124 write_list(f, &self.params)?;
125 write!(f, ")")?;
126 if !self.returns.is_empty() {
127 write!(f, " -> ")?;
128 write_list(f, &self.returns)?;
129 }
130 write!(f, " {}", self.call_conv)
131 }
132}
133
134#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)]
139#[cfg_attr(feature = "enable-serde", derive(Serialize, Deserialize))]
140pub struct AbiParam {
141 pub value_type: Type,
143 pub purpose: ArgumentPurpose,
145 pub extension: ArgumentExtension,
147}
148
149impl AbiParam {
150 pub fn new(vt: Type) -> Self {
152 Self {
153 value_type: vt,
154 extension: ArgumentExtension::None,
155 purpose: ArgumentPurpose::Normal,
156 }
157 }
158
159 pub fn special(vt: Type, purpose: ArgumentPurpose) -> Self {
161 Self {
162 value_type: vt,
163 extension: ArgumentExtension::None,
164 purpose,
165 }
166 }
167
168 pub fn uext(self) -> Self {
170 debug_assert!(self.value_type.is_int(), "uext on {} arg", self.value_type);
171 Self {
172 extension: ArgumentExtension::Uext,
173 ..self
174 }
175 }
176
177 pub fn sext(self) -> Self {
179 debug_assert!(self.value_type.is_int(), "sext on {} arg", self.value_type);
180 Self {
181 extension: ArgumentExtension::Sext,
182 ..self
183 }
184 }
185}
186
187impl fmt::Display for AbiParam {
188 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
189 write!(f, "{}", self.value_type)?;
190 match self.extension {
191 ArgumentExtension::None => {}
192 ArgumentExtension::Uext => write!(f, " uext")?,
193 ArgumentExtension::Sext => write!(f, " sext")?,
194 }
195 if self.purpose != ArgumentPurpose::Normal {
196 write!(f, " {}", self.purpose)?;
197 }
198 Ok(())
199 }
200}
201
202#[derive(Copy, Clone, PartialEq, Eq, Debug, Hash)]
213#[cfg_attr(feature = "enable-serde", derive(Serialize, Deserialize))]
214pub enum ArgumentExtension {
215 None,
217 Uext,
219 Sext,
221}
222
223#[derive(Copy, Clone, PartialEq, Eq, Debug, Hash)]
231#[cfg_attr(feature = "enable-serde", derive(Serialize, Deserialize))]
232pub enum ArgumentPurpose {
233 Normal,
235
236 StructArgument(u32),
238
239 StructReturn,
248
249 VMContext,
254
255 StackLimit,
260}
261
262impl fmt::Display for ArgumentPurpose {
263 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
264 f.write_str(match self {
265 Self::Normal => "normal",
266 Self::StructArgument(size) => return write!(f, "sarg({})", size),
267 Self::StructReturn => "sret",
268 Self::VMContext => "vmctx",
269 Self::StackLimit => "stack_limit",
270 })
271 }
272}
273
274impl FromStr for ArgumentPurpose {
275 type Err = ();
276 fn from_str(s: &str) -> Result<Self, ()> {
277 match s {
278 "normal" => Ok(Self::Normal),
279 "sret" => Ok(Self::StructReturn),
280 "vmctx" => Ok(Self::VMContext),
281 "stack_limit" => Ok(Self::StackLimit),
282 _ if s.starts_with("sarg(") => {
283 if !s.ends_with(")") {
284 return Err(());
285 }
286 let size: u32 = s["sarg(".len()..s.len() - 1].parse().map_err(|_| ())?;
288 Ok(Self::StructArgument(size))
289 }
290 _ => Err(()),
291 }
292 }
293}
294
295#[derive(Clone, Debug, PartialEq, Hash)]
299#[cfg_attr(feature = "enable-serde", derive(Serialize, Deserialize))]
300pub struct ExtFuncData {
301 pub name: ExternalName,
303 pub signature: SigRef,
305 pub colocated: bool,
319}
320
321impl ExtFuncData {
322 pub fn reloc_distance(&self) -> RelocDistance {
324 if self.colocated {
325 RelocDistance::Near
326 } else {
327 RelocDistance::Far
328 }
329 }
330
331 pub fn display<'a>(
334 &'a self,
335 params: Option<&'a FunctionParameters>,
336 ) -> DisplayableExtFuncData<'a> {
337 DisplayableExtFuncData {
338 ext_func: self,
339 params,
340 }
341 }
342}
343
344pub struct DisplayableExtFuncData<'a> {
346 ext_func: &'a ExtFuncData,
347 params: Option<&'a FunctionParameters>,
348}
349
350impl<'a> fmt::Display for DisplayableExtFuncData<'a> {
351 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
352 if self.ext_func.colocated {
353 write!(f, "colocated ")?;
354 }
355 write!(
356 f,
357 "{} {}",
358 self.ext_func.name.display(self.params),
359 self.ext_func.signature
360 )
361 }
362}
363
364#[cfg(test)]
365mod tests {
366 use super::*;
367 use crate::ir::types::{F32, I32, I8};
368 use alloc::string::ToString;
369
370 #[test]
371 fn argument_type() {
372 let t = AbiParam::new(I32);
373 assert_eq!(t.to_string(), "i32");
374 let mut t = t.uext();
375 assert_eq!(t.to_string(), "i32 uext");
376 assert_eq!(t.sext().to_string(), "i32 sext");
377 t.purpose = ArgumentPurpose::StructReturn;
378 assert_eq!(t.to_string(), "i32 uext sret");
379 }
380
381 #[test]
382 fn argument_purpose() {
383 let all_purpose = [
384 (ArgumentPurpose::Normal, "normal"),
385 (ArgumentPurpose::StructReturn, "sret"),
386 (ArgumentPurpose::VMContext, "vmctx"),
387 (ArgumentPurpose::StackLimit, "stack_limit"),
388 (ArgumentPurpose::StructArgument(42), "sarg(42)"),
389 ];
390 for &(e, n) in &all_purpose {
391 assert_eq!(e.to_string(), n);
392 assert_eq!(Ok(e), n.parse());
393 }
394 }
395
396 #[test]
397 fn call_conv() {
398 for &cc in &[
399 CallConv::Fast,
400 CallConv::Cold,
401 CallConv::SystemV,
402 CallConv::WindowsFastcall,
403 ] {
404 assert_eq!(Ok(cc), cc.to_string().parse())
405 }
406 }
407
408 #[test]
409 fn signatures() {
410 let mut sig = Signature::new(CallConv::WindowsFastcall);
411 assert_eq!(sig.to_string(), "() windows_fastcall");
412 sig.params.push(AbiParam::new(I32));
413 assert_eq!(sig.to_string(), "(i32) windows_fastcall");
414 sig.returns.push(AbiParam::new(F32));
415 assert_eq!(sig.to_string(), "(i32) -> f32 windows_fastcall");
416 sig.params.push(AbiParam::new(I32.by(4).unwrap()));
417 assert_eq!(sig.to_string(), "(i32, i32x4) -> f32 windows_fastcall");
418 sig.returns.push(AbiParam::new(I8));
419 assert_eq!(sig.to_string(), "(i32, i32x4) -> f32, i8 windows_fastcall");
420 }
421}