Remove vconcat and vsplit clif instructions (#5465)
Fixes #5463. * remove vsplit instruction * remove vconcat instruction * remove unsused half/double vector helper functions * remove unused operand constraints * delete + inline Type::half_vector method
This commit is contained in:
@@ -174,18 +174,6 @@ impl TypeVar {
|
|||||||
"can't double all float types"
|
"can't double all float types"
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
DerivedFunc::HalfVector => {
|
|
||||||
assert!(
|
|
||||||
*ts.lanes.iter().min().unwrap() > 1,
|
|
||||||
"can't halve a scalar type"
|
|
||||||
);
|
|
||||||
}
|
|
||||||
DerivedFunc::DoubleVector => {
|
|
||||||
assert!(
|
|
||||||
*ts.lanes.iter().max().unwrap() < MAX_LANES,
|
|
||||||
"can't double 256 lanes"
|
|
||||||
);
|
|
||||||
}
|
|
||||||
DerivedFunc::SplitLanes => {
|
DerivedFunc::SplitLanes => {
|
||||||
assert!(
|
assert!(
|
||||||
ts.ints.is_empty() || *ts.ints.iter().min().unwrap() > 8,
|
ts.ints.is_empty() || *ts.ints.iter().min().unwrap() > 8,
|
||||||
@@ -244,12 +232,6 @@ impl TypeVar {
|
|||||||
pub fn double_width(&self) -> TypeVar {
|
pub fn double_width(&self) -> TypeVar {
|
||||||
self.derived(DerivedFunc::DoubleWidth)
|
self.derived(DerivedFunc::DoubleWidth)
|
||||||
}
|
}
|
||||||
pub fn half_vector(&self) -> TypeVar {
|
|
||||||
self.derived(DerivedFunc::HalfVector)
|
|
||||||
}
|
|
||||||
pub fn double_vector(&self) -> TypeVar {
|
|
||||||
self.derived(DerivedFunc::DoubleVector)
|
|
||||||
}
|
|
||||||
pub fn split_lanes(&self) -> TypeVar {
|
pub fn split_lanes(&self) -> TypeVar {
|
||||||
self.derived(DerivedFunc::SplitLanes)
|
self.derived(DerivedFunc::SplitLanes)
|
||||||
}
|
}
|
||||||
@@ -317,8 +299,6 @@ pub(crate) enum DerivedFunc {
|
|||||||
AsBool,
|
AsBool,
|
||||||
HalfWidth,
|
HalfWidth,
|
||||||
DoubleWidth,
|
DoubleWidth,
|
||||||
HalfVector,
|
|
||||||
DoubleVector,
|
|
||||||
SplitLanes,
|
SplitLanes,
|
||||||
MergeLanes,
|
MergeLanes,
|
||||||
DynamicToVector,
|
DynamicToVector,
|
||||||
@@ -331,8 +311,6 @@ impl DerivedFunc {
|
|||||||
DerivedFunc::AsBool => "as_bool",
|
DerivedFunc::AsBool => "as_bool",
|
||||||
DerivedFunc::HalfWidth => "half_width",
|
DerivedFunc::HalfWidth => "half_width",
|
||||||
DerivedFunc::DoubleWidth => "double_width",
|
DerivedFunc::DoubleWidth => "double_width",
|
||||||
DerivedFunc::HalfVector => "half_vector",
|
|
||||||
DerivedFunc::DoubleVector => "double_vector",
|
|
||||||
DerivedFunc::SplitLanes => "split_lanes",
|
DerivedFunc::SplitLanes => "split_lanes",
|
||||||
DerivedFunc::MergeLanes => "merge_lanes",
|
DerivedFunc::MergeLanes => "merge_lanes",
|
||||||
DerivedFunc::DynamicToVector => "dynamic_to_vector",
|
DerivedFunc::DynamicToVector => "dynamic_to_vector",
|
||||||
@@ -410,8 +388,6 @@ impl TypeSet {
|
|||||||
DerivedFunc::AsBool => self.as_bool(),
|
DerivedFunc::AsBool => self.as_bool(),
|
||||||
DerivedFunc::HalfWidth => self.half_width(),
|
DerivedFunc::HalfWidth => self.half_width(),
|
||||||
DerivedFunc::DoubleWidth => self.double_width(),
|
DerivedFunc::DoubleWidth => self.double_width(),
|
||||||
DerivedFunc::HalfVector => self.half_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(),
|
DerivedFunc::MergeLanes => self.double_width().half_vector(),
|
||||||
DerivedFunc::DynamicToVector => self.dynamic_to_vector(),
|
DerivedFunc::DynamicToVector => self.dynamic_to_vector(),
|
||||||
|
|||||||
@@ -1409,60 +1409,6 @@ pub(crate) fn define(
|
|||||||
.operands_out(vec![a]),
|
.operands_out(vec![a]),
|
||||||
);
|
);
|
||||||
|
|
||||||
let x = &Operand::new("x", TxN).with_doc("Vector to split");
|
|
||||||
let lo = &Operand::new("lo", &TxN.half_vector()).with_doc("Low-numbered lanes of `x`");
|
|
||||||
let hi = &Operand::new("hi", &TxN.half_vector()).with_doc("High-numbered lanes of `x`");
|
|
||||||
|
|
||||||
ig.push(
|
|
||||||
Inst::new(
|
|
||||||
"vsplit",
|
|
||||||
r#"
|
|
||||||
Split a vector into two halves.
|
|
||||||
|
|
||||||
Split the vector `x` into two separate values, each containing half of
|
|
||||||
the lanes from ``x``. The result may be two scalars if ``x`` only had
|
|
||||||
two lanes.
|
|
||||||
"#,
|
|
||||||
&formats.unary,
|
|
||||||
)
|
|
||||||
.operands_in(vec![x])
|
|
||||||
.operands_out(vec![lo, hi]),
|
|
||||||
);
|
|
||||||
|
|
||||||
let Any128 = &TypeVar::new(
|
|
||||||
"Any128",
|
|
||||||
"Any scalar or vector type with as most 128 lanes",
|
|
||||||
TypeSetBuilder::new()
|
|
||||||
.ints(Interval::All)
|
|
||||||
.floats(Interval::All)
|
|
||||||
.simd_lanes(1..128)
|
|
||||||
.includes_scalars(true)
|
|
||||||
.build(),
|
|
||||||
);
|
|
||||||
|
|
||||||
let x = &Operand::new("x", Any128).with_doc("Low-numbered lanes");
|
|
||||||
let y = &Operand::new("y", Any128).with_doc("High-numbered lanes");
|
|
||||||
let a = &Operand::new("a", &Any128.double_vector()).with_doc("Concatenation of `x` and `y`");
|
|
||||||
|
|
||||||
ig.push(
|
|
||||||
Inst::new(
|
|
||||||
"vconcat",
|
|
||||||
r#"
|
|
||||||
Vector concatenation.
|
|
||||||
|
|
||||||
Return a vector formed by concatenating ``x`` and ``y``. The resulting
|
|
||||||
vector type has twice as many lanes as each of the inputs. The lanes of
|
|
||||||
``x`` appear as the low-numbered lanes, and the lanes of ``y`` become
|
|
||||||
the high-numbered lanes of ``a``.
|
|
||||||
|
|
||||||
It is possible to form a vector by concatenating two scalars.
|
|
||||||
"#,
|
|
||||||
&formats.binary,
|
|
||||||
)
|
|
||||||
.operands_in(vec![x, y])
|
|
||||||
.operands_out(vec![a]),
|
|
||||||
);
|
|
||||||
|
|
||||||
let c = &Operand::new("c", &TxN.as_bool()).with_doc("Controlling vector");
|
let c = &Operand::new("c", &TxN.as_bool()).with_doc("Controlling vector");
|
||||||
let x = &Operand::new("x", TxN).with_doc("Value to use where `c` is true");
|
let x = &Operand::new("x", TxN).with_doc("Value to use where `c` is true");
|
||||||
let y = &Operand::new("y", TxN).with_doc("Value to use where `c` is false");
|
let y = &Operand::new("y", TxN).with_doc("Value to use where `c` is false");
|
||||||
|
|||||||
@@ -603,12 +603,6 @@ enum OperandConstraint {
|
|||||||
/// This operand is `ctrlType.double_width()`.
|
/// This operand is `ctrlType.double_width()`.
|
||||||
DoubleWidth,
|
DoubleWidth,
|
||||||
|
|
||||||
/// This operand is `ctrlType.half_vector()`.
|
|
||||||
HalfVector,
|
|
||||||
|
|
||||||
/// This operand is `ctrlType.double_vector()`.
|
|
||||||
DoubleVector,
|
|
||||||
|
|
||||||
/// This operand is `ctrlType.split_lanes()`.
|
/// This operand is `ctrlType.split_lanes()`.
|
||||||
SplitLanes,
|
SplitLanes,
|
||||||
|
|
||||||
@@ -637,12 +631,6 @@ impl OperandConstraint {
|
|||||||
.double_width()
|
.double_width()
|
||||||
.expect("invalid type for double_width"),
|
.expect("invalid type for double_width"),
|
||||||
),
|
),
|
||||||
HalfVector => Bound(
|
|
||||||
ctrl_type
|
|
||||||
.half_vector()
|
|
||||||
.expect("invalid type for half_vector"),
|
|
||||||
),
|
|
||||||
DoubleVector => Bound(ctrl_type.by(2).expect("invalid type for double_vector")),
|
|
||||||
SplitLanes => {
|
SplitLanes => {
|
||||||
if ctrl_type.is_dynamic_vector() {
|
if ctrl_type.is_dynamic_vector() {
|
||||||
Bound(
|
Bound(
|
||||||
|
|||||||
@@ -364,17 +364,6 @@ impl Type {
|
|||||||
Some(Self(self.0 - constants::VECTOR_BASE))
|
Some(Self(self.0 - constants::VECTOR_BASE))
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Get a SIMD vector with half the number of lanes.
|
|
||||||
///
|
|
||||||
/// There is no `double_vector()` method. Use `t.by(2)` instead.
|
|
||||||
pub fn half_vector(self) -> Option<Self> {
|
|
||||||
if self.is_vector() && !self.is_dynamic_vector() {
|
|
||||||
Some(Self(self.0 - 0x10))
|
|
||||||
} else {
|
|
||||||
None
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// 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`.
|
||||||
@@ -391,7 +380,13 @@ impl Type {
|
|||||||
/// If this is a scalar type, it will return `None`.
|
/// If this is a scalar type, it will return `None`.
|
||||||
pub fn merge_lanes(self) -> Option<Self> {
|
pub fn merge_lanes(self) -> Option<Self> {
|
||||||
match self.double_width() {
|
match self.double_width() {
|
||||||
Some(double_width) => double_width.half_vector(),
|
Some(double_width) => {
|
||||||
|
if double_width.is_vector() && !double_width.is_dynamic_vector() {
|
||||||
|
Some(Self(double_width.0 - 0x10))
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
}
|
||||||
|
}
|
||||||
None => None,
|
None => None,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -544,10 +539,6 @@ mod tests {
|
|||||||
assert_eq!(big.lane_count(), 256);
|
assert_eq!(big.lane_count(), 256);
|
||||||
assert_eq!(big.bits(), 64 * 256);
|
assert_eq!(big.bits(), 64 * 256);
|
||||||
|
|
||||||
assert_eq!(big.half_vector().unwrap().to_string(), "f64x128");
|
|
||||||
assert_eq!(I32.half_vector(), None);
|
|
||||||
assert_eq!(INVALID.half_vector(), None);
|
|
||||||
|
|
||||||
// Check that the generated constants match the computed vector types.
|
// Check that the generated constants match the computed vector types.
|
||||||
assert_eq!(I32.by(4), Some(I32X4));
|
assert_eq!(I32.by(4), Some(I32X4));
|
||||||
assert_eq!(F64.by(8), Some(F64X8));
|
assert_eq!(F64.by(8), Some(F64X8));
|
||||||
@@ -566,7 +557,6 @@ mod tests {
|
|||||||
assert_eq!(I16X8XN.min_lane_count(), 8);
|
assert_eq!(I16X8XN.min_lane_count(), 8);
|
||||||
|
|
||||||
// Change lane counts
|
// Change lane counts
|
||||||
assert_eq!(F64X4XN.half_vector(), None);
|
|
||||||
assert_eq!(I8X8XN.by(2), None);
|
assert_eq!(I8X8XN.by(2), None);
|
||||||
|
|
||||||
// Conversions to and from vectors.
|
// Conversions to and from vectors.
|
||||||
|
|||||||
@@ -1,31 +0,0 @@
|
|||||||
test interpret
|
|
||||||
|
|
||||||
function %vsplit_i32x4_hi(i32x4) -> i32x2 {
|
|
||||||
block0(v0: i32x4):
|
|
||||||
v1, v2 = vsplit.i32x4 v0
|
|
||||||
return v1
|
|
||||||
}
|
|
||||||
; run: %vsplit_i32x4_hi([1 2 3 4]) == [1 2]
|
|
||||||
|
|
||||||
function %vsplit_i32x4_lo(i32x4) -> i32x2 {
|
|
||||||
block0(v0: i32x4):
|
|
||||||
v1, v2 = vsplit.i32x4 v0
|
|
||||||
return v2
|
|
||||||
}
|
|
||||||
; run: %vsplit_i32x4_lo([1 2 3 4]) == [3 4]
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
function %vsplit_scalar_i64x2_hi(i64x2) -> i64 {
|
|
||||||
block0(v0: i64x2):
|
|
||||||
v1, v2 = vsplit.i64x2 v0
|
|
||||||
return v1
|
|
||||||
}
|
|
||||||
; run: %vsplit_scalar_i64x2_hi([1 2]) == 1
|
|
||||||
|
|
||||||
function %vsplit_scalar_i64x2_lo(i64x2) -> i64 {
|
|
||||||
block0(v0: i64x2):
|
|
||||||
v1, v2 = vsplit.i64x2 v0
|
|
||||||
return v2
|
|
||||||
}
|
|
||||||
; run: %vsplit_scalar_i64x2_lo([3 4]) == 4
|
|
||||||
@@ -985,16 +985,6 @@ where
|
|||||||
}
|
}
|
||||||
assign(Value::int(result, ctrl_ty)?)
|
assign(Value::int(result, ctrl_ty)?)
|
||||||
}
|
}
|
||||||
Opcode::Vsplit => {
|
|
||||||
let new_type = ctrl_ty.half_vector().unwrap();
|
|
||||||
let vector = extractlanes(&arg(0)?, ctrl_ty)?;
|
|
||||||
let (high, low) = vector.split_at((ctrl_ty.lane_count() / 2) as usize);
|
|
||||||
assign_multiple(&[
|
|
||||||
vectorizelanes(high, new_type)?,
|
|
||||||
vectorizelanes(low, new_type)?,
|
|
||||||
])
|
|
||||||
}
|
|
||||||
Opcode::Vconcat => unimplemented!("Vconcat"),
|
|
||||||
Opcode::Vselect => assign(vselect(&arg(0)?, &arg(1)?, &arg(2)?, ctrl_ty)?),
|
Opcode::Vselect => assign(vselect(&arg(0)?, &arg(1)?, &arg(2)?, ctrl_ty)?),
|
||||||
Opcode::VanyTrue => {
|
Opcode::VanyTrue => {
|
||||||
let lane_ty = ctrl_ty.lane_type();
|
let lane_ty = ctrl_ty.lane_type();
|
||||||
|
|||||||
Reference in New Issue
Block a user