1use 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#[derive(Clone, Debug, PartialEq, Eq, Hash)]
22pub struct Signature {
23 pub params: Vec<AbiParam>,
25 pub returns: Vec<AbiParam>,
27
28 pub call_conv: CallConv,
30}
31
32impl Signature {
33 pub fn new(call_conv: CallConv) -> Self {
35 Self {
36 params: Vec::new(),
37 returns: Vec::new(),
38 call_conv,
39 }
40 }
41
42 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 pub fn display<'a, R: Into<Option<&'a RegInfo>>>(&'a self, regs: R) -> DisplaySignature<'a> {
51 DisplaySignature(self, regs.into())
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 num_normal_params(&self) -> usize {
95 self.params
96 .iter()
97 .filter(|arg| arg.purpose == ArgumentPurpose::Normal)
98 .count()
99 }
100
101 pub fn uses_struct_return_param(&self) -> bool {
103 self.uses_special_param(ArgumentPurpose::StructReturn)
104 }
105
106 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 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 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
135pub 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#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)]
175pub struct AbiParam {
176 pub value_type: Type,
178 pub purpose: ArgumentPurpose,
180 pub extension: ArgumentExtension,
182
183 pub location: ArgumentLoc,
186}
187
188impl AbiParam {
189 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 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 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 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 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 pub fn display<'a, R: Into<Option<&'a RegInfo>>>(&'a self, regs: R) -> DisplayAbiParam<'a> {
239 DisplayAbiParam(self, regs.into())
240 }
241}
242
243pub 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#[derive(Copy, Clone, PartialEq, Eq, Debug, Hash)]
277pub enum ArgumentExtension {
278 None,
280 Uext,
282 Sext,
284}
285
286#[derive(Copy, Clone, PartialEq, Eq, Debug, Hash)]
294pub enum ArgumentPurpose {
295 Normal,
297
298 StructReturn,
307
308 Link,
316
317 FramePointer,
324
325 CalleeSaved,
330
331 VMContext,
336
337 SignatureId,
342
343 StackLimit,
348}
349
350static 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#[derive(Clone, Debug)]
389pub struct ExtFuncData {
390 pub name: ExternalName,
392 pub signature: SigRef,
394 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 sig.params[0].location = ArgumentLoc::Stack(24);
476 sig.params[1].location = ArgumentLoc::Stack(8);
477
478 assert_eq!(
480 sig.to_string(),
481 "(i32 [24], i32x4 [8]) -> f32, b8 baldrdash_system_v"
482 );
483 }
484}