Add DerivedFunction for doubling lane widths and halving the number of lanes (i.e. merging)

Certain operations (e.g. widening) will have operands with types like `NxM` but will return results with types like `(N*2)x(M/2)` (double the lane width, halve the number of lanes; maintain the same number of vector bits). This is equivalent to applying two `DerivedFunction`s to the type: `DerivedFunction::DoubleWidth` then `DerivedFunction::HalfVector`. Since there is no easy way to apply multiple `DerivedFunction`s (e.g. most of the logic is one-level deep, 1d5a678124/cranelift/codegen/meta/src/gen_inst.rs (L618-L621)), I added `DerivedFunction::MergeLanes` to do the necessary type conversion.
This commit is contained in:
Andrew Brown
2020-07-07 13:37:37 -07:00
parent 12a31c88d7
commit 0e5e8a62c8
3 changed files with 48 additions and 2 deletions

View File

@@ -211,6 +211,24 @@ impl TypeVar {
"can't double 256 lanes" "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 */ } DerivedFunc::LaneOf | DerivedFunc::AsBool => { /* no particular assertions */ }
} }
@@ -248,6 +266,9 @@ impl TypeVar {
pub fn split_lanes(&self) -> TypeVar { pub fn split_lanes(&self) -> TypeVar {
self.derived(DerivedFunc::SplitLanes) 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 /// Constrain the range of types this variable can assume to a subset of those in the typeset
/// ts. /// ts.
@@ -355,6 +376,7 @@ pub(crate) enum DerivedFunc {
HalfVector, HalfVector,
DoubleVector, DoubleVector,
SplitLanes, SplitLanes,
MergeLanes,
} }
impl DerivedFunc { impl DerivedFunc {
@@ -367,6 +389,7 @@ impl DerivedFunc {
DerivedFunc::HalfVector => "half_vector", DerivedFunc::HalfVector => "half_vector",
DerivedFunc::DoubleVector => "double_vector", DerivedFunc::DoubleVector => "double_vector",
DerivedFunc::SplitLanes => "split_lanes", DerivedFunc::SplitLanes => "split_lanes",
DerivedFunc::MergeLanes => "merge_lanes",
} }
} }
@@ -377,6 +400,8 @@ impl DerivedFunc {
DerivedFunc::DoubleWidth => Some(DerivedFunc::HalfWidth), DerivedFunc::DoubleWidth => Some(DerivedFunc::HalfWidth),
DerivedFunc::HalfVector => Some(DerivedFunc::DoubleVector), DerivedFunc::HalfVector => Some(DerivedFunc::DoubleVector),
DerivedFunc::DoubleVector => Some(DerivedFunc::HalfVector), DerivedFunc::DoubleVector => Some(DerivedFunc::HalfVector),
DerivedFunc::MergeLanes => Some(DerivedFunc::SplitLanes),
DerivedFunc::SplitLanes => Some(DerivedFunc::MergeLanes),
_ => None, _ => None,
} }
} }
@@ -462,6 +487,7 @@ impl TypeSet {
DerivedFunc::HalfVector => self.half_vector(), DerivedFunc::HalfVector => self.half_vector(),
DerivedFunc::DoubleVector => self.double_vector(), DerivedFunc::DoubleVector => self.double_vector(),
DerivedFunc::SplitLanes => self.half_width().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::DoubleWidth => self.half_width(),
DerivedFunc::HalfVector => self.double_vector(), DerivedFunc::HalfVector => self.double_vector(),
DerivedFunc::DoubleVector => self.half_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(),
} }
} }

View File

@@ -584,6 +584,9 @@ enum OperandConstraint {
/// This operand is `ctrlType.split_lanes()`. /// This operand is `ctrlType.split_lanes()`.
SplitLanes, SplitLanes,
/// This operand is `ctrlType.merge_lanes()`.
MergeLanes,
} }
impl OperandConstraint { impl OperandConstraint {
@@ -615,6 +618,11 @@ impl OperandConstraint {
.split_lanes() .split_lanes()
.expect("invalid type for split_lanes"), .expect("invalid type for split_lanes"),
), ),
MergeLanes => Bound(
ctrl_type
.merge_lanes()
.expect("invalid type for merge_lanes"),
),
} }
} }
} }

View File

@@ -284,7 +284,7 @@ impl Type {
/// Split the lane width in half and double the number of lanes to maintain the same bit-width. /// 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<Self> { pub fn split_lanes(self) -> Option<Self> {
match self.half_width() { match self.half_width() {
Some(half_width) => half_width.by(2), 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<Self> {
match self.double_width() {
Some(double_width) => double_width.half_vector(),
None => None,
}
}
/// Index of this type, for use with hash tables etc. /// Index of this type, for use with hash tables etc.
pub fn index(self) -> usize { pub fn index(self) -> usize {
usize::from(self.0) usize::from(self.0)