forked from bytecodealliance/wasmtime
-
Notifications
You must be signed in to change notification settings - Fork 1
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Implement type representation in Rust.
Start the Cretonne library as a Rust crate.
- Loading branch information
Jakob Stoklund Olesen
committed
Mar 11, 2016
1 parent
29cc36c
commit 82e05bc
Showing
4 changed files
with
250 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1 +1,3 @@ | ||
*.pyc | ||
Cargo.lock | ||
target |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,10 @@ | ||
[package] | ||
authors = ["The cwCretonneRust Project Developers"] | ||
name = "cretonne" | ||
version = "0.0.0" | ||
|
||
[lib] | ||
name = "cretonne" | ||
path = "lib.rs" | ||
|
||
[dependencies] |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,8 @@ | ||
|
||
//====--------------------------------------------------------------------------------------====// | ||
// | ||
// Cretonne code generation library. | ||
// | ||
//====--------------------------------------------------------------------------------------====// | ||
|
||
mod types; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -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"); | ||
} | ||
} |