Add DerivedFunction for splitting lane widths and doubling the number of lanes

Certain operations (e.g. x86_packss) will have operands with types like `NxM` but will return results with types like `(N/2)x(M*2)` (halve the lane width, double the number of lanes; maintain the same number of vector bits). This is equivalent to applying two `DerivedFunction`s to the type: `DerivedFunction::HalfWidth` then `DerivedFunction::DoubleVector`. 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::SplitLanes` to do the necessary type conversion.
This commit is contained in:
Andrew Brown
2020-03-25 10:15:06 -07:00
parent f5fc09f64a
commit 341dc45cea
3 changed files with 43 additions and 0 deletions

View File

@@ -193,6 +193,24 @@ impl TypeVar {
"can't double 256 lanes"
);
}
DerivedFunc::SplitLanes => {
assert!(
ts.ints.is_empty() || *ts.ints.iter().min().unwrap() > 8,
"can't halve all integer types"
);
assert!(
ts.floats.is_empty() || *ts.floats.iter().min().unwrap() > 32,
"can't halve all float types"
);
assert!(
ts.bools.is_empty() || *ts.bools.iter().min().unwrap() > 8,
"can't halve all boolean types"
);
assert!(
*ts.lanes.iter().max().unwrap() < MAX_LANES,
"can't double 256 lanes"
);
}
DerivedFunc::LaneOf | DerivedFunc::AsBool => { /* no particular assertions */ }
}
@@ -227,6 +245,9 @@ impl TypeVar {
pub fn double_vector(&self) -> TypeVar {
self.derived(DerivedFunc::DoubleVector)
}
pub fn split_lanes(&self) -> TypeVar {
self.derived(DerivedFunc::SplitLanes)
}
/// Constrain the range of types this variable can assume to a subset of those in the typeset
/// ts.
@@ -333,6 +354,7 @@ pub(crate) enum DerivedFunc {
DoubleWidth,
HalfVector,
DoubleVector,
SplitLanes,
}
impl DerivedFunc {
@@ -344,6 +366,7 @@ impl DerivedFunc {
DerivedFunc::DoubleWidth => "double_width",
DerivedFunc::HalfVector => "half_vector",
DerivedFunc::DoubleVector => "double_vector",
DerivedFunc::SplitLanes => "split_lanes",
}
}
@@ -438,6 +461,7 @@ impl TypeSet {
DerivedFunc::DoubleWidth => self.double_width(),
DerivedFunc::HalfVector => self.half_vector(),
DerivedFunc::DoubleVector => self.double_vector(),
DerivedFunc::SplitLanes => self.half_width().double_vector(),
}
}
@@ -577,6 +601,7 @@ impl TypeSet {
DerivedFunc::DoubleWidth => self.half_width(),
DerivedFunc::HalfVector => self.double_vector(),
DerivedFunc::DoubleVector => self.half_vector(),
DerivedFunc::SplitLanes => self.half_vector().double_width(),
}
}

View File

@@ -518,6 +518,9 @@ enum OperandConstraint {
/// This operand is `ctrlType.double_vector()`.
DoubleVector,
/// This operand is `ctrlType.split_lanes()`.
SplitLanes,
}
impl OperandConstraint {
@@ -544,6 +547,11 @@ impl OperandConstraint {
.expect("invalid type for half_vector"),
),
DoubleVector => Bound(ctrl_type.by(2).expect("invalid type for double_vector")),
SplitLanes => Bound(
ctrl_type
.split_lanes()
.expect("invalid type for split_lanes"),
),
}
}
}

View File

@@ -279,6 +279,16 @@ 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.
pub fn split_lanes(self) -> Option<Self> {
match self.half_width() {
Some(half_width) => half_width.by(2),
None => None,
}
}
/// Index of this type, for use with hash tables etc.
pub fn index(self) -> usize {
usize::from(self.0)