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),
Special(SpecialType),
Vector(VectorType),
}
impl ValueType {
pub fn all_lane_types() -> LaneTypeIterator {
LaneTypeIterator::new()
}
pub fn all_special_types() -> SpecialTypeIterator {
SpecialTypeIterator::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::Special(s) => s.doc(),
ValueType::Vector(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::Special(s) => s.lane_bits(),
ValueType::Vector(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) -> Option<u8> {
match *self {
ValueType::Lane(l) => Some(l.number()),
ValueType::Reference(r) => Some(r.number()),
ValueType::Special(s) => Some(s.number()),
ValueType::Vector(ref v) => Some(v.number()),
}
}
pub fn rust_name(&self) -> String {
format!("{}{}", _RUST_NAME_PREFIX, self.to_string().to_uppercase())
}
pub fn _wider_or_equal(&self, rhs: &ValueType) -> bool {
(self.lane_count() == rhs.lane_count()) && (self.lane_bits() >= rhs.lane_bits())
}
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::Special(s) => s.fmt(f),
ValueType::Vector(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<SpecialType> for ValueType {
fn from(spec: SpecialType) -> Self {
ValueType::Special(spec)
}
}
impl From<VectorType> for ValueType {
fn from(vector: VectorType) -> Self {
ValueType::Vector(vector)
}
}
#[derive(Clone, Copy, PartialEq, Eq, Hash)]
pub(crate) enum LaneType {
Bool(shared_types::Bool),
Float(shared_types::Float),
Int(shared_types::Int),
}
impl LaneType {
pub fn doc(self) -> String {
match self {
LaneType::Bool(_) => format!("A boolean type with {} bits.", self.lane_bits()),
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::Bool(ref b) => *b as u64,
LaneType::Float(ref f) => *f as u64,
LaneType::Int(ref i) => *i as u64,
}
}
pub fn number(self) -> u8 {
constants::LANE_BASE
+ match self {
LaneType::Bool(shared_types::Bool::B1) => 0,
LaneType::Bool(shared_types::Bool::B8) => 1,
LaneType::Bool(shared_types::Bool::B16) => 2,
LaneType::Bool(shared_types::Bool::B32) => 3,
LaneType::Bool(shared_types::Bool::B64) => 4,
LaneType::Bool(shared_types::Bool::B128) => 5,
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 bool_from_bits(num_bits: u16) -> LaneType {
LaneType::Bool(match num_bits {
1 => shared_types::Bool::B1,
8 => shared_types::Bool::B8,
16 => shared_types::Bool::B16,
32 => shared_types::Bool::B32,
64 => shared_types::Bool::B64,
128 => shared_types::Bool::B128,
_ => unreachable!("unxpected num bits for bool"),
})
}
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 is_float(self) -> bool {
match self {
LaneType::Float(_) => true,
_ => false,
}
}
pub fn is_int(self) -> bool {
match self {
LaneType::Int(_) => true,
_ => false,
}
}
}
impl fmt::Display for LaneType {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match *self {
LaneType::Bool(_) => write!(f, "b{}", self.lane_bits()),
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::Bool(_) => format!("BoolType({})", inner_msg),
LaneType::Float(_) => format!("FloatType({})", inner_msg),
LaneType::Int(_) => format!("IntType({})", inner_msg),
}
)
}
}
impl From<shared_types::Bool> for LaneType {
fn from(b: shared_types::Bool) -> Self {
LaneType::Bool(b)
}
}
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 {
bool_iter: shared_types::BoolIterator,
int_iter: shared_types::IntIterator,
float_iter: shared_types::FloatIterator,
}
impl LaneTypeIterator {
fn new() -> Self {
Self {
bool_iter: shared_types::BoolIterator::new(),
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(b) = self.bool_iter.next() {
Some(LaneType::from(b))
} else 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) -> u8 {
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 u8
}
}
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, Copy, PartialEq, Eq, Hash)]
pub(crate) enum SpecialType {
Flag(shared_types::Flag),
}
impl SpecialType {
pub fn doc(self) -> String {
match self {
SpecialType::Flag(shared_types::Flag::IFlags) => String::from(
"CPU flags representing the result of an integer comparison. These flags
can be tested with an :type:`intcc` condition code.",
),
SpecialType::Flag(shared_types::Flag::FFlags) => String::from(
"CPU flags representing the result of a floating point comparison. These
flags can be tested with a :type:`floatcc` condition code.",
),
}
}
pub fn lane_bits(self) -> u64 {
match self {
SpecialType::Flag(_) => 0,
}
}
pub fn number(self) -> u8 {
match self {
SpecialType::Flag(shared_types::Flag::IFlags) => 1,
SpecialType::Flag(shared_types::Flag::FFlags) => 2,
}
}
}
impl fmt::Display for SpecialType {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match *self {
SpecialType::Flag(shared_types::Flag::IFlags) => write!(f, "iflags"),
SpecialType::Flag(shared_types::Flag::FFlags) => write!(f, "fflags"),
}
}
}
impl fmt::Debug for SpecialType {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(
f,
"{}",
match *self {
SpecialType::Flag(_) => format!("FlagsType({})", self),
}
)
}
}
impl From<shared_types::Flag> for SpecialType {
fn from(f: shared_types::Flag) -> Self {
SpecialType::Flag(f)
}
}
pub(crate) struct SpecialTypeIterator {
flag_iter: shared_types::FlagIterator,
}
impl SpecialTypeIterator {
fn new() -> Self {
Self {
flag_iter: shared_types::FlagIterator::new(),
}
}
}
impl Iterator for SpecialTypeIterator {
type Item = SpecialType;
fn next(&mut self) -> Option<Self::Item> {
if let Some(f) = self.flag_iter.next() {
Some(SpecialType::from(f))
} else {
None
}
}
}
#[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) -> u8 {
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> {
if let Some(r) = self.reference_iter.next() {
Some(ReferenceType::from(r))
} else {
None
}
}
}