Add function signatures.
Describe function argument and return value types along with flags for passing values in an ABI-compliant way.
This commit is contained in:
@@ -3,6 +3,12 @@
|
||||
|
||||
use std::fmt::{self, Display, Formatter, Write};
|
||||
|
||||
// ====--------------------------------------------------------------------------------------====//
|
||||
//
|
||||
// Value types
|
||||
//
|
||||
// ====--------------------------------------------------------------------------------------====//
|
||||
|
||||
/// The type of an SSA value.
|
||||
///
|
||||
/// The `VOID` type is only used for instructions that produce no value. It can't be part of a SIMD
|
||||
@@ -177,6 +183,107 @@ impl Display for Type {
|
||||
}
|
||||
}
|
||||
|
||||
// ====--------------------------------------------------------------------------------------====//
|
||||
//
|
||||
// Function signatures
|
||||
//
|
||||
// ====--------------------------------------------------------------------------------------====//
|
||||
|
||||
/// Function argument extension options.
|
||||
///
|
||||
/// On some architectures, small integer function arguments are extended to the width of a
|
||||
/// general-purpose register.
|
||||
#[derive(Copy, Clone, PartialEq, Eq, Debug)]
|
||||
pub enum ArgumentExtension {
|
||||
/// No extension, high bits are indeterminate.
|
||||
None,
|
||||
/// Unsigned extension: high bits in register are 0.
|
||||
Uext,
|
||||
/// Signed extension: high bits in register replicate sign bit.
|
||||
Sext,
|
||||
}
|
||||
|
||||
/// Function argument or return value type.
|
||||
///
|
||||
/// This describes the value type being passed to or from a function along with flags that affect
|
||||
/// how the argument is passed.
|
||||
#[derive(Copy, Clone, PartialEq, Eq, Debug)]
|
||||
pub struct ArgumentType {
|
||||
pub value_type: Type,
|
||||
pub extension: ArgumentExtension,
|
||||
/// Place this argument in a register if possible.
|
||||
pub inreg: bool,
|
||||
}
|
||||
|
||||
/// Function signature.
|
||||
///
|
||||
/// The function signature describes the types of arguments and return values along with other
|
||||
/// details that are needed to call a function correctly.
|
||||
pub struct Signature {
|
||||
pub argument_types: Vec<ArgumentType>,
|
||||
pub return_types: Vec<ArgumentType>,
|
||||
}
|
||||
|
||||
impl ArgumentType {
|
||||
pub fn new(vt: Type) -> ArgumentType {
|
||||
ArgumentType {
|
||||
value_type: vt,
|
||||
extension: ArgumentExtension::None,
|
||||
inreg: false,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Display for ArgumentType {
|
||||
fn fmt(&self, f: &mut Formatter) -> fmt::Result {
|
||||
try!(write!(f, "{}", self.value_type));
|
||||
match self.extension {
|
||||
ArgumentExtension::None => {}
|
||||
ArgumentExtension::Uext => try!(write!(f, " uext")),
|
||||
ArgumentExtension::Sext => try!(write!(f, " sext")),
|
||||
}
|
||||
if self.inreg {
|
||||
try!(write!(f, " inreg"));
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
impl Signature {
|
||||
pub fn new() -> Signature {
|
||||
Signature {
|
||||
argument_types: Vec::new(),
|
||||
return_types: Vec::new(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn write_list(f: &mut Formatter, args: &Vec<ArgumentType>) -> fmt::Result {
|
||||
match args.split_first() {
|
||||
None => {}
|
||||
Some((first, rest)) => {
|
||||
try!(write!(f, "{}", first));
|
||||
for arg in rest {
|
||||
try!(write!(f, ", {}", arg));
|
||||
}
|
||||
}
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
impl Display for Signature {
|
||||
fn fmt(&self, f: &mut Formatter) -> fmt::Result {
|
||||
try!(write!(f, "("));
|
||||
try!(write_list(f, &self.argument_types));
|
||||
try!(write!(f, ")"));
|
||||
if !self.return_types.is_empty() {
|
||||
try!(write!(f, " -> "));
|
||||
try!(write_list(f, &self.return_types));
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
@@ -248,4 +355,28 @@ mod tests {
|
||||
assert_eq!(format!("{}", I8.by(64)), "i8x64");
|
||||
assert_eq!(format!("{}", F64.by(2)), "f64x2");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn argument_type() {
|
||||
let mut t = ArgumentType::new(I32);
|
||||
assert_eq!(format!("{}", t), "i32");
|
||||
t.extension = ArgumentExtension::Uext;
|
||||
assert_eq!(format!("{}", t), "i32 uext");
|
||||
t.inreg = true;
|
||||
assert_eq!(format!("{}", t), "i32 uext inreg");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn signatures() {
|
||||
let mut sig = Signature::new();
|
||||
assert_eq!(format!("{}", sig), "()");
|
||||
sig.argument_types.push(ArgumentType::new(I32));
|
||||
assert_eq!(format!("{}", sig), "(i32)");
|
||||
sig.return_types.push(ArgumentType::new(F32));
|
||||
assert_eq!(format!("{}", sig), "(i32) -> f32");
|
||||
sig.argument_types.push(ArgumentType::new(I32.by(4)));
|
||||
assert_eq!(format!("{}", sig), "(i32, i32x4) -> f32");
|
||||
sig.return_types.push(ArgumentType::new(B8));
|
||||
assert_eq!(format!("{}", sig), "(i32, i32x4) -> f32, b8");
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user