diff --git a/cranelift/codegen/meta/src/cdsl/typevar.rs b/cranelift/codegen/meta/src/cdsl/typevar.rs index 0c0b2e9647..752b458b2a 100644 --- a/cranelift/codegen/meta/src/cdsl/typevar.rs +++ b/cranelift/codegen/meta/src/cdsl/typevar.rs @@ -211,6 +211,24 @@ impl TypeVar { "can't double 256 lanes" ); } + DerivedFunc::MergeLanes => { + assert!( + ts.ints.is_empty() || *ts.ints.iter().max().unwrap() < MAX_BITS, + "can't double all integer types" + ); + assert!( + ts.floats.is_empty() || *ts.floats.iter().max().unwrap() < MAX_FLOAT_BITS, + "can't double all float types" + ); + assert!( + ts.bools.is_empty() || *ts.bools.iter().max().unwrap() < MAX_BITS, + "can't double all boolean types" + ); + assert!( + *ts.lanes.iter().min().unwrap() > 1, + "can't halve a scalar type" + ); + } DerivedFunc::LaneOf | DerivedFunc::AsBool => { /* no particular assertions */ } } @@ -248,6 +266,9 @@ impl TypeVar { pub fn split_lanes(&self) -> TypeVar { self.derived(DerivedFunc::SplitLanes) } + pub fn merge_lanes(&self) -> TypeVar { + self.derived(DerivedFunc::MergeLanes) + } /// Constrain the range of types this variable can assume to a subset of those in the typeset /// ts. @@ -355,6 +376,7 @@ pub(crate) enum DerivedFunc { HalfVector, DoubleVector, SplitLanes, + MergeLanes, } impl DerivedFunc { @@ -367,6 +389,7 @@ impl DerivedFunc { DerivedFunc::HalfVector => "half_vector", DerivedFunc::DoubleVector => "double_vector", DerivedFunc::SplitLanes => "split_lanes", + DerivedFunc::MergeLanes => "merge_lanes", } } @@ -377,6 +400,8 @@ impl DerivedFunc { DerivedFunc::DoubleWidth => Some(DerivedFunc::HalfWidth), DerivedFunc::HalfVector => Some(DerivedFunc::DoubleVector), DerivedFunc::DoubleVector => Some(DerivedFunc::HalfVector), + DerivedFunc::MergeLanes => Some(DerivedFunc::SplitLanes), + DerivedFunc::SplitLanes => Some(DerivedFunc::MergeLanes), _ => None, } } @@ -462,6 +487,7 @@ impl TypeSet { DerivedFunc::HalfVector => self.half_vector(), DerivedFunc::DoubleVector => self.double_vector(), DerivedFunc::SplitLanes => self.half_width().double_vector(), + DerivedFunc::MergeLanes => self.double_width().half_vector(), } } @@ -601,7 +627,8 @@ impl TypeSet { DerivedFunc::DoubleWidth => self.half_width(), DerivedFunc::HalfVector => self.double_vector(), DerivedFunc::DoubleVector => self.half_vector(), - DerivedFunc::SplitLanes => self.half_vector().double_width(), + DerivedFunc::SplitLanes => self.double_width().half_vector(), + DerivedFunc::MergeLanes => self.half_width().double_vector(), } } diff --git a/cranelift/codegen/src/ir/instructions.rs b/cranelift/codegen/src/ir/instructions.rs index f835bd5f4a..2ba730b687 100644 --- a/cranelift/codegen/src/ir/instructions.rs +++ b/cranelift/codegen/src/ir/instructions.rs @@ -584,6 +584,9 @@ enum OperandConstraint { /// This operand is `ctrlType.split_lanes()`. SplitLanes, + + /// This operand is `ctrlType.merge_lanes()`. + MergeLanes, } impl OperandConstraint { @@ -615,6 +618,11 @@ impl OperandConstraint { .split_lanes() .expect("invalid type for split_lanes"), ), + MergeLanes => Bound( + ctrl_type + .merge_lanes() + .expect("invalid type for merge_lanes"), + ), } } } diff --git a/cranelift/codegen/src/ir/types.rs b/cranelift/codegen/src/ir/types.rs index 319f3ae66f..c669839da5 100644 --- a/cranelift/codegen/src/ir/types.rs +++ b/cranelift/codegen/src/ir/types.rs @@ -284,7 +284,7 @@ impl Type { /// Split the lane width in half and double the number of lanes to maintain the same bit-width. /// - /// If this is a scalar type of n bits, it produces a SIMD vector type of (n/2)x2. + /// If this is a scalar type of `n` bits, it produces a SIMD vector type of `(n/2)x2`. pub fn split_lanes(self) -> Option { match self.half_width() { Some(half_width) => half_width.by(2), @@ -292,6 +292,17 @@ impl Type { } } + /// Merge lanes to half the number of lanes and double the lane width to maintain the same + /// bit-width. + /// + /// If this is a scalar type, it will return `None`. + pub fn merge_lanes(self) -> Option { + match self.double_width() { + Some(double_width) => double_width.half_vector(), + None => None, + } + } + /// Index of this type, for use with hash tables etc. pub fn index(self) -> usize { usize::from(self.0)