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:
@@ -193,6 +193,24 @@ impl TypeVar {
|
|||||||
"can't double 256 lanes"
|
"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 */ }
|
DerivedFunc::LaneOf | DerivedFunc::AsBool => { /* no particular assertions */ }
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -227,6 +245,9 @@ impl TypeVar {
|
|||||||
pub fn double_vector(&self) -> TypeVar {
|
pub fn double_vector(&self) -> TypeVar {
|
||||||
self.derived(DerivedFunc::DoubleVector)
|
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
|
/// Constrain the range of types this variable can assume to a subset of those in the typeset
|
||||||
/// ts.
|
/// ts.
|
||||||
@@ -333,6 +354,7 @@ pub(crate) enum DerivedFunc {
|
|||||||
DoubleWidth,
|
DoubleWidth,
|
||||||
HalfVector,
|
HalfVector,
|
||||||
DoubleVector,
|
DoubleVector,
|
||||||
|
SplitLanes,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl DerivedFunc {
|
impl DerivedFunc {
|
||||||
@@ -344,6 +366,7 @@ impl DerivedFunc {
|
|||||||
DerivedFunc::DoubleWidth => "double_width",
|
DerivedFunc::DoubleWidth => "double_width",
|
||||||
DerivedFunc::HalfVector => "half_vector",
|
DerivedFunc::HalfVector => "half_vector",
|
||||||
DerivedFunc::DoubleVector => "double_vector",
|
DerivedFunc::DoubleVector => "double_vector",
|
||||||
|
DerivedFunc::SplitLanes => "split_lanes",
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -438,6 +461,7 @@ impl TypeSet {
|
|||||||
DerivedFunc::DoubleWidth => self.double_width(),
|
DerivedFunc::DoubleWidth => self.double_width(),
|
||||||
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(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -577,6 +601,7 @@ 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(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -518,6 +518,9 @@ enum OperandConstraint {
|
|||||||
|
|
||||||
/// This operand is `ctrlType.double_vector()`.
|
/// This operand is `ctrlType.double_vector()`.
|
||||||
DoubleVector,
|
DoubleVector,
|
||||||
|
|
||||||
|
/// This operand is `ctrlType.split_lanes()`.
|
||||||
|
SplitLanes,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl OperandConstraint {
|
impl OperandConstraint {
|
||||||
@@ -544,6 +547,11 @@ impl OperandConstraint {
|
|||||||
.expect("invalid type for half_vector"),
|
.expect("invalid type for half_vector"),
|
||||||
),
|
),
|
||||||
DoubleVector => Bound(ctrl_type.by(2).expect("invalid type for double_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"),
|
||||||
|
),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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.
|
/// 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)
|
||||||
|
|||||||
Reference in New Issue
Block a user