use std::fmt;
use crate::shared::types as shared_types;
use cranelift_codegen_shared::constants;
static RUST_NAME_PREFIX: &str = "ir::types::";
#[derive(Clone, Debug, PartialEq, Eq, Hash)]
pub(crate) enum ValueType {
Lane(LaneType),
Reference(ReferenceType),
Vector(VectorType),
DynamicVector(DynamicVectorType),
}
impl ValueType {
pub fn all_lane_types() -> LaneTypeIterator {
LaneTypeIterator::new()
}
pub fn all_reference_types() -> ReferenceTypeIterator {
ReferenceTypeIterator::new()
}
pub fn doc(&self) -> String {
match *self {
ValueType::Lane(l) => l.doc(),
ValueType::Reference(r) => r.doc(),
ValueType::Vector(ref v) => v.doc(),
ValueType::DynamicVector(ref v) => v.doc(),
}
}
pub fn lane_bits(&self) -> u64 {
match *self {
ValueType::Lane(l) => l.lane_bits(),
ValueType::Reference(r) => r.lane_bits(),
ValueType::Vector(ref v) => v.lane_bits(),
ValueType::DynamicVector(ref v) => v.lane_bits(),
}
}
pub fn lane_count(&self) -> u64 {
match *self {
ValueType::Vector(ref v) => v.lane_count(),
_ => 1,
}
}
pub fn membytes(&self) -> u64 {
self.width() / 8
}
pub fn number(&self) -> u16 {
match *self {
ValueType::Lane(l) => l.number(),
ValueType::Reference(r) => r.number(),
ValueType::Vector(ref v) => v.number(),
ValueType::DynamicVector(ref v) => v.number(),
}
}
pub fn rust_name(&self) -> String {
format!("{}{}", RUST_NAME_PREFIX, self.to_string().to_uppercase())
}
pub fn width(&self) -> u64 {
self.lane_count() * self.lane_bits()
}
}
impl fmt::Display for ValueType {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match *self {
ValueType::Lane(l) => l.fmt(f),
ValueType::Reference(r) => r.fmt(f),
ValueType::Vector(ref v) => v.fmt(f),
ValueType::DynamicVector(ref v) => v.fmt(f),
}
}
}
impl From<LaneType> for ValueType {
fn from(lane: LaneType) -> Self {
ValueType::Lane(lane)
}
}
impl From<ReferenceType> for ValueType {
fn from(reference: ReferenceType) -> Self {
ValueType::Reference(reference)
}
}
impl From<VectorType> for ValueType {
fn from(vector: VectorType) -> Self {
ValueType::Vector(vector)
}
}
impl From<DynamicVectorType> for ValueType {
fn from(vector: DynamicVectorType) -> Self {
ValueType::DynamicVector(vector)
}
}
#[derive(Clone, Copy, PartialEq, Eq, Hash)]
pub(crate) enum LaneType {
Float(shared_types::Float),
Int(shared_types::Int),
}
impl LaneType {
pub fn doc(self) -> String {
match self {
LaneType::Float(shared_types::Float::F32) => String::from(
"A 32-bit floating point type represented in the IEEE 754-2008
*binary32* interchange format. This corresponds to the :c:type:`float`
type in most C implementations.",
),
LaneType::Float(shared_types::Float::F64) => String::from(
"A 64-bit floating point type represented in the IEEE 754-2008
*binary64* interchange format. This corresponds to the :c:type:`double`
type in most C implementations.",
),
LaneType::Int(_) if self.lane_bits() < 32 => format!(
"An integer type with {} bits.
WARNING: arithmetic on {}bit integers is incomplete",
self.lane_bits(),
self.lane_bits()
),
LaneType::Int(_) => format!("An integer type with {} bits.", self.lane_bits()),
}
}
pub fn lane_bits(self) -> u64 {
match self {
LaneType::Float(ref f) => *f as u64,
LaneType::Int(ref i) => *i as u64,
}
}
pub fn number(self) -> u16 {
constants::LANE_BASE
+ match self {
LaneType::Int(shared_types::Int::I8) => 6,
LaneType::Int(shared_types::Int::I16) => 7,
LaneType::Int(shared_types::Int::I32) => 8,
LaneType::Int(shared_types::Int::I64) => 9,
LaneType::Int(shared_types::Int::I128) => 10,
LaneType::Float(shared_types::Float::F32) => 11,
LaneType::Float(shared_types::Float::F64) => 12,
}
}
pub fn int_from_bits(num_bits: u16) -> LaneType {
LaneType::Int(match num_bits {
8 => shared_types::Int::I8,
16 => shared_types::Int::I16,
32 => shared_types::Int::I32,
64 => shared_types::Int::I64,
128 => shared_types::Int::I128,
_ => unreachable!("unxpected num bits for int"),
})
}
pub fn float_from_bits(num_bits: u16) -> LaneType {
LaneType::Float(match num_bits {
32 => shared_types::Float::F32,
64 => shared_types::Float::F64,
_ => unreachable!("unxpected num bits for float"),
})
}
pub fn by(self, lanes: u16) -> ValueType {
if lanes == 1 {
self.into()
} else {
ValueType::Vector(VectorType::new(self, lanes.into()))
}
}
pub fn to_dynamic(self, lanes: u16) -> ValueType {
ValueType::DynamicVector(DynamicVectorType::new(self, lanes.into()))
}
}
impl fmt::Display for LaneType {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match *self {
LaneType::Float(_) => write!(f, "f{}", self.lane_bits()),
LaneType::Int(_) => write!(f, "i{}", self.lane_bits()),
}
}
}
impl fmt::Debug for LaneType {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
let inner_msg = format!("bits={}", self.lane_bits());
write!(
f,
"{}",
match *self {
LaneType::Float(_) => format!("FloatType({})", inner_msg),
LaneType::Int(_) => format!("IntType({})", inner_msg),
}
)
}
}
impl From<shared_types::Float> for LaneType {
fn from(f: shared_types::Float) -> Self {
LaneType::Float(f)
}
}
impl From<shared_types::Int> for LaneType {
fn from(i: shared_types::Int) -> Self {
LaneType::Int(i)
}
}
pub(crate) struct LaneTypeIterator {
int_iter: shared_types::IntIterator,
float_iter: shared_types::FloatIterator,
}
impl LaneTypeIterator {
fn new() -> Self {
Self {
int_iter: shared_types::IntIterator::new(),
float_iter: shared_types::FloatIterator::new(),
}
}
}
impl Iterator for LaneTypeIterator {
type Item = LaneType;
fn next(&mut self) -> Option<Self::Item> {
if let Some(i) = self.int_iter.next() {
Some(LaneType::from(i))
} else if let Some(f) = self.float_iter.next() {
Some(LaneType::from(f))
} else {
None
}
}
}
#[derive(Clone, PartialEq, Eq, Hash)]
pub(crate) struct VectorType {
base: LaneType,
lanes: u64,
}
impl VectorType {
pub fn new(base: LaneType, lanes: u64) -> Self {
Self { base, lanes }
}
pub fn doc(&self) -> String {
format!(
"A SIMD vector with {} lanes containing a `{}` each.",
self.lane_count(),
self.base
)
}
pub fn lane_bits(&self) -> u64 {
self.base.lane_bits()
}
pub fn lane_count(&self) -> u64 {
self.lanes
}
pub fn lane_type(&self) -> LaneType {
self.base
}
pub fn number(&self) -> u16 {
let lanes_log_2: u32 = 63 - self.lane_count().leading_zeros();
let base_num = u32::from(self.base.number());
let num = (lanes_log_2 << 4) + base_num;
num as u16
}
}
impl fmt::Display for VectorType {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "{}x{}", self.base, self.lane_count())
}
}
impl fmt::Debug for VectorType {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(
f,
"VectorType(base={}, lanes={})",
self.base,
self.lane_count()
)
}
}
#[derive(Clone, PartialEq, Eq, Hash)]
pub(crate) struct DynamicVectorType {
base: LaneType,
unscaled_lanes: u64,
}
impl DynamicVectorType {
pub fn new(base: LaneType, unscaled_lanes: u64) -> Self {
Self {
base,
unscaled_lanes,
}
}
pub fn doc(&self) -> String {
format!(
"A dynamically-scaled SIMD vector with a minimum of {} lanes containing `{}` bits each.",
self.unscaled_lanes,
self.base
)
}
pub fn lane_bits(&self) -> u64 {
self.base.lane_bits()
}
pub fn minimum_lane_count(&self) -> u64 {
self.unscaled_lanes
}
pub fn lane_type(&self) -> LaneType {
self.base
}
pub fn number(&self) -> u16 {
let base_num = u32::from(self.base.number());
let lanes_log_2: u32 = 63 - self.minimum_lane_count().leading_zeros();
let num = 0x80 + (lanes_log_2 << 4) + base_num;
num as u16
}
}
impl fmt::Display for DynamicVectorType {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "{}x{}xN", self.base, self.minimum_lane_count())
}
}
impl fmt::Debug for DynamicVectorType {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(
f,
"DynamicVectorType(base={}, lanes={})",
self.base,
self.minimum_lane_count(),
)
}
}
#[derive(Clone, Copy, PartialEq, Eq, Hash)]
pub(crate) struct ReferenceType(pub shared_types::Reference);
impl ReferenceType {
pub fn doc(self) -> String {
format!("An opaque reference type with {} bits.", self.lane_bits())
}
pub fn lane_bits(self) -> u64 {
match self.0 {
shared_types::Reference::R32 => 32,
shared_types::Reference::R64 => 64,
}
}
pub fn number(self) -> u16 {
constants::REFERENCE_BASE
+ match self {
ReferenceType(shared_types::Reference::R32) => 0,
ReferenceType(shared_types::Reference::R64) => 1,
}
}
pub fn ref_from_bits(num_bits: u16) -> ReferenceType {
ReferenceType(match num_bits {
32 => shared_types::Reference::R32,
64 => shared_types::Reference::R64,
_ => unreachable!("unexpected number of bits for a reference type"),
})
}
}
impl fmt::Display for ReferenceType {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "r{}", self.lane_bits())
}
}
impl fmt::Debug for ReferenceType {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "ReferenceType(bits={})", self.lane_bits())
}
}
impl From<shared_types::Reference> for ReferenceType {
fn from(r: shared_types::Reference) -> Self {
ReferenceType(r)
}
}
pub(crate) struct ReferenceTypeIterator {
reference_iter: shared_types::ReferenceIterator,
}
impl ReferenceTypeIterator {
fn new() -> Self {
Self {
reference_iter: shared_types::ReferenceIterator::new(),
}
}
}
impl Iterator for ReferenceTypeIterator {
type Item = ReferenceType;
fn next(&mut self) -> Option<Self::Item> {
self.reference_iter.next().map(ReferenceType::from)
}
}