diff --git a/cranelift/.gitignore b/cranelift/.gitignore index 0d20b6487c..25eadf4e60 100644 --- a/cranelift/.gitignore +++ b/cranelift/.gitignore @@ -1 +1,3 @@ *.pyc +Cargo.lock +target diff --git a/cranelift/src/libcretonne/Cargo.toml b/cranelift/src/libcretonne/Cargo.toml new file mode 100644 index 0000000000..58a67fe569 --- /dev/null +++ b/cranelift/src/libcretonne/Cargo.toml @@ -0,0 +1,10 @@ +[package] +authors = ["The cwCretonneRust Project Developers"] +name = "cretonne" +version = "0.0.0" + +[lib] +name = "cretonne" +path = "lib.rs" + +[dependencies] diff --git a/cranelift/src/libcretonne/lib.rs b/cranelift/src/libcretonne/lib.rs new file mode 100644 index 0000000000..e2adcaec67 --- /dev/null +++ b/cranelift/src/libcretonne/lib.rs @@ -0,0 +1,8 @@ + +//====--------------------------------------------------------------------------------------====// +// +// Cretonne code generation library. +// +//====--------------------------------------------------------------------------------------====// + +mod types; diff --git a/cranelift/src/libcretonne/types.rs b/cranelift/src/libcretonne/types.rs new file mode 100644 index 0000000000..49d7cc29ce --- /dev/null +++ b/cranelift/src/libcretonne/types.rs @@ -0,0 +1,230 @@ + +//! Common types for the Cretonne code generator. + +use std::fmt::{self, Display, Formatter, Write}; + +/// 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 +/// vector. +/// +/// Basic integer types: `I8`, `I16`, `I32`, and `I64`. These types are sign-agnostic. +/// +/// Basic floating point types: `F32` and `F64`. IEEE single and double precision. +/// +/// Boolean types: `B1`, `B8`, `B16`, `B32`, and `B64`. These all encode 'true' or 'false'. The +/// larger types use redundant bits. +/// +/// SIMD vector types have power-of-two lanes, up to 256. Lanes can be any int/float/bool type. +/// +#[derive(Copy, Clone, PartialEq, Eq, Debug)] +pub struct Type(u8); + +pub const VOID: Type = Type(0); + +pub const I8: Type = Type(1); +pub const I16: Type = Type(2); +pub const I32: Type = Type(3); +pub const I64: Type = Type(4); + +pub const F32: Type = Type(5); +pub const F64: Type = Type(6); + +pub const B1: Type = Type(7); +pub const B8: Type = Type(8); +pub const B16: Type = Type(9); +pub const B32: Type = Type(10); +pub const B64: Type = Type(11); + +impl Type { + /// Get the lane type of this SIMD vector type. + /// + /// A scalar type is the same as a SIMD vector type with one lane, so it returns itself. + pub fn lane_type(self) -> Type { + Type(self.0 & 0x0f) + } + + /// Get the number of bits in a lane. + pub fn lane_bits(self) -> u8 { + match self.lane_type() { + B1 => 1, + B8 | I8 => 8, + B16 | I16 => 16, + B32 | I32 | F32 => 32, + B64 | I64 | F64 => 64, + _ => 0, + } + } + + /// Is this the VOID type? + pub fn is_void(self) -> bool { + self == VOID + } + + /// Is this a scalar boolean type? + pub fn is_bool(self) -> bool { + match self { + B1 | B8 | B16 | B32 | B64 => true, + _ => false, + } + } + + /// Is this a scalar integer type? + pub fn is_int(self) -> bool { + match self { + I8 | I16 | I32 | I64 => true, + _ => false, + } + } + + /// Is this a scalar floating point type? + pub fn is_float(self) -> bool { + match self { + F32 | F64 => true, + _ => false, + } + } + + /// Get log2 of the number of lanes in this SIMD vector type. + /// + /// All SIMD types have a lane count that is a power of two and no larger than 256, so this + /// will be a number in the range 0-8. + /// + /// A scalar type is the same as a SIMD vector type with one lane, so it return 0. + pub fn log2_lane_count(self) -> u8 { + self.0 >> 4 + } + + /// Is this a scalar type? (That is, not a SIMD vector type). + /// + /// A scalar type is the same as a SIMD vector type with one lane. + pub fn is_scalar(self) -> bool { + self.log2_lane_count() == 0 + } + + /// Get the number of lanes in this SIMD vector type. + /// + /// A scalar type is the same as a SIMD vector type with one lane, so it returns 1. + pub fn lane_count(self) -> u16 { + 1 << self.log2_lane_count() + } + + /// Get the total number of bits used to represent this type. + pub fn bits(self) -> u16 { + self.lane_bits() as u16 * self.lane_count() + } + + /// Get a SIMD vector type with `n` times more lanes than this one. + /// + /// If this is a scalar type, this produces a SIMD type with this as a lane type and `n` lanes. + /// + /// If this is already a SIMD vector type, this produces a SIMD vector type with `n * + /// self.lane_count()` lanes. + pub fn by(self, n: u16) -> Type { + debug_assert!(self.lane_bits() > 0, + "Can't make SIMD vectors with void lanes."); + debug_assert!(n.is_power_of_two(), + "Number of SIMD lanes must be a power of two"); + let log2_lanes: u32 = n.trailing_zeros(); + let new_type = self.0 as u32 + (log2_lanes << 4); + assert!(new_type < 0x90, "No more than 256 SIMD lanes supported"); + Type(new_type as u8) + } + + /// Get a SIMD vector with half the number of lanes. + pub fn half_vector(self) -> Type { + assert!(!self.is_scalar(), "Expecting a proper SIMD vector type."); + Type(self.0 - 0x10) + } +} + +impl Display for Type { + fn fmt(&self, f: &mut Formatter) -> fmt::Result { + if self.is_void() { + write!(f, "void") + } else if self.is_bool() { + write!(f, "b{}", self.lane_bits()) + } else if self.is_int() { + write!(f, "i{}", self.lane_bits()) + } else if self.is_float() { + write!(f, "f{}", self.lane_bits()) + } else if !self.is_scalar() { + write!(f, "{}x{}", self.lane_type(), self.lane_count()) + } else { + panic!("Invalid Type(0x{:x})", self.0) + } + } +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn basic_scalars() { + assert_eq!(VOID, VOID.lane_type()); + assert_eq!(0, VOID.bits()); + assert_eq!(B1, B1.lane_type()); + assert_eq!(B8, B8.lane_type()); + assert_eq!(B16, B16.lane_type()); + assert_eq!(B32, B32.lane_type()); + assert_eq!(B64, B64.lane_type()); + assert_eq!(I8, I8.lane_type()); + assert_eq!(I16, I16.lane_type()); + assert_eq!(I32, I32.lane_type()); + assert_eq!(I64, I64.lane_type()); + assert_eq!(F32, F32.lane_type()); + assert_eq!(F64, F64.lane_type()); + + assert_eq!(VOID.lane_bits(), 0); + assert_eq!(B1.lane_bits(), 1); + assert_eq!(B8.lane_bits(), 8); + assert_eq!(B16.lane_bits(), 16); + assert_eq!(B32.lane_bits(), 32); + assert_eq!(B64.lane_bits(), 64); + assert_eq!(I8.lane_bits(), 8); + assert_eq!(I16.lane_bits(), 16); + assert_eq!(I32.lane_bits(), 32); + assert_eq!(I64.lane_bits(), 64); + assert_eq!(F32.lane_bits(), 32); + assert_eq!(F64.lane_bits(), 64); + } + + #[test] + fn vectors() { + let big = F64.by(256); + assert_eq!(big.lane_bits(), 64); + assert_eq!(big.lane_count(), 256); + assert_eq!(big.bits(), 64 * 256); + + assert_eq!(format!("{}", big.half_vector()), "f64x128"); + assert_eq!(format!("{}", B1.by(2).half_vector()), "b1"); + } + + #[test] + fn format_scalars() { + assert_eq!(format!("{}", VOID), "void"); + assert_eq!(format!("{}", B1), "b1"); + assert_eq!(format!("{}", B8), "b8"); + assert_eq!(format!("{}", B16), "b16"); + assert_eq!(format!("{}", B32), "b32"); + assert_eq!(format!("{}", B64), "b64"); + assert_eq!(format!("{}", I8), "i8"); + assert_eq!(format!("{}", I16), "i16"); + assert_eq!(format!("{}", I32), "i32"); + assert_eq!(format!("{}", I64), "i64"); + assert_eq!(format!("{}", F32), "f32"); + assert_eq!(format!("{}", F64), "f64"); + } + + #[test] + fn format_vectors() { + assert_eq!(format!("{}", B1.by(8)), "b1x8"); + assert_eq!(format!("{}", B8.by(1)), "b8"); + assert_eq!(format!("{}", B16.by(256)), "b16x256"); + assert_eq!(format!("{}", B32.by(4).by(2)), "b32x8"); + assert_eq!(format!("{}", B64.by(8)), "b64x8"); + assert_eq!(format!("{}", I8.by(64)), "i8x64"); + assert_eq!(format!("{}", F64.by(2)), "f64x2"); + } +}