diff --git a/src/libcretonne/ir/extfunc.rs b/src/libcretonne/ir/extfunc.rs new file mode 100644 index 0000000000..78b723398e --- /dev/null +++ b/src/libcretonne/ir/extfunc.rs @@ -0,0 +1,135 @@ +//! External function calls. +//! +//! To a Cretonne function, all functions are "external". Directly called functions must be +//! declared in the preamble, and all function calls must have a signature. +//! +//! This module declares the data types used to represent external functions and call signatures. + +use std::fmt::{self, Display, Formatter}; +use ir::Type; + +/// 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. +#[derive(Clone, PartialEq, Eq, Debug)] +pub struct Signature { + pub argument_types: Vec, + pub return_types: Vec, +} + +impl Signature { + pub fn new() -> Signature { + Signature { + argument_types: Vec::new(), + return_types: Vec::new(), + } + } +} + +fn write_list(f: &mut Formatter, args: &Vec) -> 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(()) + } +} + +/// 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, +} + +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(()) + } +} + +/// 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, +} + +#[cfg(test)] +mod tests { + use super::*; + use ir::types::{I32, F32, B8}; + + #[test] + fn argument_type() { + let mut t = ArgumentType::new(I32); + assert_eq!(t.to_string(), "i32"); + t.extension = ArgumentExtension::Uext; + assert_eq!(t.to_string(), "i32 uext"); + t.inreg = true; + assert_eq!(t.to_string(), "i32 uext inreg"); + } + + #[test] + fn signatures() { + let mut sig = Signature::new(); + assert_eq!(sig.to_string(), "()"); + sig.argument_types.push(ArgumentType::new(I32)); + assert_eq!(sig.to_string(), "(i32)"); + sig.return_types.push(ArgumentType::new(F32)); + assert_eq!(sig.to_string(), "(i32) -> f32"); + sig.argument_types.push(ArgumentType::new(I32.by(4).unwrap())); + assert_eq!(sig.to_string(), "(i32, i32x4) -> f32"); + sig.return_types.push(ArgumentType::new(B8)); + assert_eq!(sig.to_string(), "(i32, i32x4) -> f32, b8"); + } +} diff --git a/src/libcretonne/ir/mod.rs b/src/libcretonne/ir/mod.rs index ae16eae735..285fab96e5 100644 --- a/src/libcretonne/ir/mod.rs +++ b/src/libcretonne/ir/mod.rs @@ -11,9 +11,11 @@ pub mod dfg; pub mod layout; pub mod function; mod funcname; +mod extfunc; pub use ir::funcname::FunctionName; -pub use ir::types::{Type, Signature}; +pub use ir::extfunc::{Signature, ArgumentType, ArgumentExtension}; +pub use ir::types::Type; pub use ir::entities::{Ebb, Inst, Value, StackSlot, JumpTable}; pub use ir::instructions::{Opcode, InstructionData}; pub use ir::stackslot::StackSlotData; diff --git a/src/libcretonne/ir/types.rs b/src/libcretonne/ir/types.rs index 7c9175f460..99390ee22a 100644 --- a/src/libcretonne/ir/types.rs +++ b/src/libcretonne/ir/types.rs @@ -1,4 +1,3 @@ - //! Common types for the Cretonne code generator. use std::default::Default; @@ -229,108 +228,6 @@ impl Default 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. -#[derive(Clone, PartialEq, Eq, Debug)] -pub struct Signature { - pub argument_types: Vec, - pub return_types: Vec, -} - -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) -> 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::*; @@ -442,28 +339,4 @@ mod tests { assert_eq!(I8.by(512), None); assert_eq!(VOID.by(4), None); } - - #[test] - fn argument_type() { - let mut t = ArgumentType::new(I32); - assert_eq!(t.to_string(), "i32"); - t.extension = ArgumentExtension::Uext; - assert_eq!(t.to_string(), "i32 uext"); - t.inreg = true; - assert_eq!(t.to_string(), "i32 uext inreg"); - } - - #[test] - fn signatures() { - let mut sig = Signature::new(); - assert_eq!(sig.to_string(), "()"); - sig.argument_types.push(ArgumentType::new(I32)); - assert_eq!(sig.to_string(), "(i32)"); - sig.return_types.push(ArgumentType::new(F32)); - assert_eq!(sig.to_string(), "(i32) -> f32"); - sig.argument_types.push(ArgumentType::new(I32.by(4).unwrap())); - assert_eq!(sig.to_string(), "(i32, i32x4) -> f32"); - sig.return_types.push(ArgumentType::new(B8)); - assert_eq!(sig.to_string(), "(i32, i32x4) -> f32, b8"); - } } diff --git a/src/libreader/parser.rs b/src/libreader/parser.rs index eb8c78de38..5023195e11 100644 --- a/src/libreader/parser.rs +++ b/src/libreader/parser.rs @@ -9,8 +9,8 @@ use std::str::FromStr; use std::u32; use std::mem; use cretonne::ir::{Function, Ebb, Opcode, Value, Type, FunctionName, StackSlotData, JumpTable, - JumpTableData}; -use cretonne::ir::types::{VOID, Signature, ArgumentType, ArgumentExtension}; + JumpTableData, Signature, ArgumentType, ArgumentExtension}; +use cretonne::ir::types::VOID; use cretonne::ir::immediates::{Imm64, Ieee32, Ieee64}; use cretonne::ir::entities::{AnyEntity, NO_EBB, NO_INST, NO_VALUE}; use cretonne::ir::instructions::{InstructionFormat, InstructionData, VariableArgs, @@ -1202,7 +1202,8 @@ impl<'a> Parser<'a> { #[cfg(test)] mod tests { use super::*; - use cretonne::ir::types::{self, ArgumentType, ArgumentExtension}; + use cretonne::ir::{ArgumentType, ArgumentExtension}; + use cretonne::ir::types; use cretonne::ir::entities::AnyEntity; use testfile::{Details, Comment}; use isaspec::IsaSpec;