From d256c46f6005cf35dda545a16a9b972755cafbf6 Mon Sep 17 00:00:00 2001 From: Jakob Stoklund Olesen Date: Tue, 27 Sep 2016 15:39:54 -0700 Subject: [PATCH] Add HalfWidth and DoubleWidth type variable functions. These functions compute types with half or double the number of bits in each lane. --- cranelift/src/libcretonne/ir/instructions.rs | 8 +++ cranelift/src/libcretonne/ir/types.rs | 65 +++++++++++++++++++- meta/cretonne/test_typevar.py | 21 ++++++- meta/cretonne/typevar.py | 30 +++++++++ 4 files changed, 122 insertions(+), 2 deletions(-) diff --git a/cranelift/src/libcretonne/ir/instructions.rs b/cranelift/src/libcretonne/ir/instructions.rs index afd6ba319f..f60d23c60c 100644 --- a/cranelift/src/libcretonne/ir/instructions.rs +++ b/cranelift/src/libcretonne/ir/instructions.rs @@ -547,6 +547,12 @@ enum OperandConstraint { /// This operand is `ctrlType.as_bool()`. AsBool, + + /// This operand is `ctrlType.half_width()`. + HalfWidth, + + /// This operand is `ctrlType.double_width()`. + DoubleWidth, } impl OperandConstraint { @@ -562,6 +568,8 @@ impl OperandConstraint { Same => Some(ctrl_type), LaneOf => Some(ctrl_type.lane_type()), 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")), } } } diff --git a/cranelift/src/libcretonne/ir/types.rs b/cranelift/src/libcretonne/ir/types.rs index 1eb546bde6..7c9175f460 100644 --- a/cranelift/src/libcretonne/ir/types.rs +++ b/cranelift/src/libcretonne/ir/types.rs @@ -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. pub fn as_bool(self) -> Type { // 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)) } + /// 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 { + 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 { + 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? pub fn is_void(self) -> bool { self == VOID @@ -333,6 +365,37 @@ mod tests { 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] fn vectors() { let big = F64.by(256).unwrap(); diff --git a/meta/cretonne/test_typevar.py b/meta/cretonne/test_typevar.py index 128b32b71f..a841acfdb9 100644 --- a/meta/cretonne/test_typevar.py +++ b/meta/cretonne/test_typevar.py @@ -2,7 +2,7 @@ from __future__ import absolute_import from unittest import TestCase from doctest import DocTestSuite from . import typevar -from .typevar import TypeSet +from .typevar import TypeSet, TypeVar def load_tests(loader, tests, ignore): @@ -43,3 +43,22 @@ class TestTypeSet(TestCase): # Can't rehash after modification. with self.assertRaises(AssertionError): 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() diff --git a/meta/cretonne/typevar.py b/meta/cretonne/typevar.py index 918933b7c6..a29548af38 100644 --- a/meta/cretonne/typevar.py +++ b/meta/cretonne/typevar.py @@ -274,6 +274,36 @@ class TypeVar(object): """ 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): # 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