Add HalfWidth and DoubleWidth type variable functions.
These functions compute types with half or double the number of bits in each lane.
This commit is contained in:
@@ -547,6 +547,12 @@ enum OperandConstraint {
|
|||||||
|
|
||||||
/// This operand is `ctrlType.as_bool()`.
|
/// This operand is `ctrlType.as_bool()`.
|
||||||
AsBool,
|
AsBool,
|
||||||
|
|
||||||
|
/// This operand is `ctrlType.half_width()`.
|
||||||
|
HalfWidth,
|
||||||
|
|
||||||
|
/// This operand is `ctrlType.double_width()`.
|
||||||
|
DoubleWidth,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl OperandConstraint {
|
impl OperandConstraint {
|
||||||
@@ -562,6 +568,8 @@ impl OperandConstraint {
|
|||||||
Same => Some(ctrl_type),
|
Same => Some(ctrl_type),
|
||||||
LaneOf => Some(ctrl_type.lane_type()),
|
LaneOf => Some(ctrl_type.lane_type()),
|
||||||
AsBool => Some(ctrl_type.as_bool()),
|
AsBool => Some(ctrl_type.as_bool()),
|
||||||
|
HalfWidth => Some(ctrl_type.half_width().expect("invalid type for half_width")),
|
||||||
|
DoubleWidth => Some(ctrl_type.double_width().expect("invalid type for double_width")),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -67,7 +67,7 @@ impl Type {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Get a type with the same number of lanes as this type, but with the lanes replaces by
|
/// Get a type with the same number of lanes as this type, but with the lanes replaced by
|
||||||
/// booleans of the same size.
|
/// booleans of the same size.
|
||||||
pub fn as_bool(self) -> Type {
|
pub fn as_bool(self) -> Type {
|
||||||
// Replace the low 4 bits with the boolean version, preserve the high 4 bits.
|
// Replace the low 4 bits with the boolean version, preserve the high 4 bits.
|
||||||
@@ -81,6 +81,38 @@ impl Type {
|
|||||||
Type(lane.0 | (self.0 & 0xf0))
|
Type(lane.0 | (self.0 & 0xf0))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Get a type with the same number of lanes as this type, but with lanes that are half the
|
||||||
|
/// number of bits.
|
||||||
|
pub fn half_width(self) -> Option<Type> {
|
||||||
|
let lane = match self.lane_type() {
|
||||||
|
I16 => I8,
|
||||||
|
I32 => I16,
|
||||||
|
I64 => I32,
|
||||||
|
F64 => F32,
|
||||||
|
B16 => B8,
|
||||||
|
B32 => B16,
|
||||||
|
B64 => B32,
|
||||||
|
_ => return None,
|
||||||
|
};
|
||||||
|
Some(Type(lane.0 | (self.0 & 0xf0)))
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Get a type with the same number of lanes as this type, but with lanes that are twice the
|
||||||
|
/// number of bits.
|
||||||
|
pub fn double_width(self) -> Option<Type> {
|
||||||
|
let lane = match self.lane_type() {
|
||||||
|
I8 => I16,
|
||||||
|
I16 => I32,
|
||||||
|
I32 => I64,
|
||||||
|
F32 => F64,
|
||||||
|
B8 => B16,
|
||||||
|
B16 => B32,
|
||||||
|
B32 => B64,
|
||||||
|
_ => return None,
|
||||||
|
};
|
||||||
|
Some(Type(lane.0 | (self.0 & 0xf0)))
|
||||||
|
}
|
||||||
|
|
||||||
/// Is this the VOID type?
|
/// Is this the VOID type?
|
||||||
pub fn is_void(self) -> bool {
|
pub fn is_void(self) -> bool {
|
||||||
self == VOID
|
self == VOID
|
||||||
@@ -333,6 +365,37 @@ mod tests {
|
|||||||
assert_eq!(F64.lane_bits(), 64);
|
assert_eq!(F64.lane_bits(), 64);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn typevar_functions() {
|
||||||
|
assert_eq!(VOID.half_width(), None);
|
||||||
|
assert_eq!(B1.half_width(), None);
|
||||||
|
assert_eq!(B8.half_width(), None);
|
||||||
|
assert_eq!(B16.half_width(), Some(B8));
|
||||||
|
assert_eq!(B32.half_width(), Some(B16));
|
||||||
|
assert_eq!(B64.half_width(), Some(B32));
|
||||||
|
assert_eq!(I8.half_width(), None);
|
||||||
|
assert_eq!(I16.half_width(), Some(I8));
|
||||||
|
assert_eq!(I32.half_width(), Some(I16));
|
||||||
|
assert_eq!(I32X4.half_width(), Some(I16X4));
|
||||||
|
assert_eq!(I64.half_width(), Some(I32));
|
||||||
|
assert_eq!(F32.half_width(), None);
|
||||||
|
assert_eq!(F64.half_width(), Some(F32));
|
||||||
|
|
||||||
|
assert_eq!(VOID.double_width(), None);
|
||||||
|
assert_eq!(B1.double_width(), None);
|
||||||
|
assert_eq!(B8.double_width(), Some(B16));
|
||||||
|
assert_eq!(B16.double_width(), Some(B32));
|
||||||
|
assert_eq!(B32.double_width(), Some(B64));
|
||||||
|
assert_eq!(B64.double_width(), None);
|
||||||
|
assert_eq!(I8.double_width(), Some(I16));
|
||||||
|
assert_eq!(I16.double_width(), Some(I32));
|
||||||
|
assert_eq!(I32.double_width(), Some(I64));
|
||||||
|
assert_eq!(I32X4.double_width(), Some(I64X4));
|
||||||
|
assert_eq!(I64.double_width(), None);
|
||||||
|
assert_eq!(F32.double_width(), Some(F64));
|
||||||
|
assert_eq!(F64.double_width(), None);
|
||||||
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn vectors() {
|
fn vectors() {
|
||||||
let big = F64.by(256).unwrap();
|
let big = F64.by(256).unwrap();
|
||||||
|
|||||||
@@ -2,7 +2,7 @@ from __future__ import absolute_import
|
|||||||
from unittest import TestCase
|
from unittest import TestCase
|
||||||
from doctest import DocTestSuite
|
from doctest import DocTestSuite
|
||||||
from . import typevar
|
from . import typevar
|
||||||
from .typevar import TypeSet
|
from .typevar import TypeSet, TypeVar
|
||||||
|
|
||||||
|
|
||||||
def load_tests(loader, tests, ignore):
|
def load_tests(loader, tests, ignore):
|
||||||
@@ -43,3 +43,22 @@ class TestTypeSet(TestCase):
|
|||||||
# Can't rehash after modification.
|
# Can't rehash after modification.
|
||||||
with self.assertRaises(AssertionError):
|
with self.assertRaises(AssertionError):
|
||||||
a in s
|
a in s
|
||||||
|
|
||||||
|
|
||||||
|
class TestTypeVar(TestCase):
|
||||||
|
def test_functions(self):
|
||||||
|
x = TypeVar('x', 'all ints', ints=True)
|
||||||
|
with self.assertRaises(AssertionError):
|
||||||
|
x.double_width()
|
||||||
|
with self.assertRaises(AssertionError):
|
||||||
|
x.half_width()
|
||||||
|
|
||||||
|
x2 = TypeVar('x2', 'i16 and up', ints=(16, 64))
|
||||||
|
with self.assertRaises(AssertionError):
|
||||||
|
x2.double_width()
|
||||||
|
self.assertEqual(str(x2.half_width()), '`HalfWidth(x2)`')
|
||||||
|
|
||||||
|
x3 = TypeVar('x3', 'up to i32', ints=(8, 32))
|
||||||
|
self.assertEqual(str(x3.double_width()), '`DoubleWidth(x3)`')
|
||||||
|
with self.assertRaises(AssertionError):
|
||||||
|
x3.half_width()
|
||||||
|
|||||||
@@ -274,6 +274,36 @@ class TypeVar(object):
|
|||||||
"""
|
"""
|
||||||
return TypeVar(None, None, base=self, derived_func='AsBool')
|
return TypeVar(None, None, base=self, derived_func='AsBool')
|
||||||
|
|
||||||
|
def half_width(self):
|
||||||
|
"""
|
||||||
|
Return a derived type variable that has the same number of vector lanes
|
||||||
|
as this one, but the lanes are half the width.
|
||||||
|
"""
|
||||||
|
ts = self.type_set
|
||||||
|
if ts.min_int:
|
||||||
|
assert ts.min_int > 8, "Can't halve all integer types"
|
||||||
|
if ts.min_float:
|
||||||
|
assert ts.min_float > 32, "Can't halve all float types"
|
||||||
|
if ts.min_bool:
|
||||||
|
assert ts.min_bool > 8, "Can't halve all boolean types"
|
||||||
|
|
||||||
|
return TypeVar(None, None, base=self, derived_func='HalfWidth')
|
||||||
|
|
||||||
|
def double_width(self):
|
||||||
|
"""
|
||||||
|
Return a derived type variable that has the same number of vector lanes
|
||||||
|
as this one, but the lanes are double the width.
|
||||||
|
"""
|
||||||
|
ts = self.type_set
|
||||||
|
if ts.max_int:
|
||||||
|
assert ts.max_int < MAX_BITS, "Can't double all integer types."
|
||||||
|
if ts.max_float:
|
||||||
|
assert ts.max_float < MAX_BITS, "Can't double all float types."
|
||||||
|
if ts.max_bool:
|
||||||
|
assert ts.max_bool < MAX_BITS, "Can't double all boolean types."
|
||||||
|
|
||||||
|
return TypeVar(None, None, base=self, derived_func='DoubleWidth')
|
||||||
|
|
||||||
def operand_kind(self):
|
def operand_kind(self):
|
||||||
# When a `TypeVar` object is used to describe the type of an `Operand`
|
# When a `TypeVar` object is used to describe the type of an `Operand`
|
||||||
# in an instruction definition, the kind of that operand is an SSA
|
# in an instruction definition, the kind of that operand is an SSA
|
||||||
|
|||||||
Reference in New Issue
Block a user