Add vsplit and vconcat instructions.
Add support for two new type variable functions: half_vector() and double_vector(). Use these two instructions to break down unsupported SIMD types and build them up again.
This commit is contained in:
@@ -668,14 +668,9 @@ allocation pass and beyond.
|
|||||||
Vector operations
|
Vector operations
|
||||||
-----------------
|
-----------------
|
||||||
|
|
||||||
|
.. autoinst:: vsplit
|
||||||
|
.. autoinst:: vconcat
|
||||||
.. autoinst:: vselect
|
.. autoinst:: vselect
|
||||||
|
|
||||||
.. inst:: a = vbuild x, y, z, ...
|
|
||||||
|
|
||||||
Vector build.
|
|
||||||
|
|
||||||
Build a vector value from the provided lanes.
|
|
||||||
|
|
||||||
.. autoinst:: splat
|
.. autoinst:: splat
|
||||||
.. autoinst:: insertlane
|
.. autoinst:: insertlane
|
||||||
.. autoinst:: extractlane
|
.. autoinst:: extractlane
|
||||||
|
|||||||
@@ -21,6 +21,14 @@ function f(i32) {
|
|||||||
sig3 = signature(f64, f64, f64, f64, f64, f64, f64, i64) -> f64
|
sig3 = signature(f64, f64, f64, f64, f64, f64, f64, i64) -> f64
|
||||||
; check: sig3 = signature(f64 [%f10], f64 [%f11], f64 [%f12], f64 [%f13], f64 [%f14], f64 [%f15], f64 [%f16], i32 [0], i32 [4]) -> f64 [%f10]
|
; check: sig3 = signature(f64 [%f10], f64 [%f11], f64 [%f12], f64 [%f13], f64 [%f14], f64 [%f15], f64 [%f16], i32 [0], i32 [4]) -> f64 [%f10]
|
||||||
|
|
||||||
|
; Splitting vectors.
|
||||||
|
sig4 = signature(i32x4)
|
||||||
|
; check: sig4 = signature(i32 [%x10], i32 [%x11], i32 [%x12], i32 [%x13])
|
||||||
|
|
||||||
|
; Splitting vectors, then splitting ints.
|
||||||
|
sig5 = signature(i64x4)
|
||||||
|
; check: sig5 = signature(i32 [%x10], i32 [%x11], i32 [%x12], i32 [%x13], i32 [%x14], i32 [%x15], i32 [%x16], i32 [%x17])
|
||||||
|
|
||||||
ebb0(v0: i32):
|
ebb0(v0: i32):
|
||||||
return_reg v0
|
return_reg v0
|
||||||
}
|
}
|
||||||
@@ -32,3 +40,17 @@ ebb0(v0: i64):
|
|||||||
v1 = iadd_imm v0, 1
|
v1 = iadd_imm v0, 1
|
||||||
return v0
|
return v0
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function vector_split_args(i64x4) -> i64 {
|
||||||
|
ebb0(v0: i64x4):
|
||||||
|
; check: $ebb0($(v0al=$VX): i32, $(v0ah=$VX): i32, $(v0bl=$VX): i32, $(v0bh=$VX): i32, $(v0cl=$VX): i32, $(v0ch=$VX): i32, $(v0dl=$VX): i32, $(v0dh=$VX): i32):
|
||||||
|
; check: $(v0a=$V) = iconcat_lohi $v0al, $v0ah
|
||||||
|
; check: $(v0b=$V) = iconcat_lohi $v0bl, $v0bh
|
||||||
|
; check: $(v0ab=$V) = vconcat $v0a, $v0b
|
||||||
|
; check: $(v0c=$V) = iconcat_lohi $v0cl, $v0ch
|
||||||
|
; check: $(v0d=$V) = iconcat_lohi $v0dl, $v0dh
|
||||||
|
; check: $(v0cd=$V) = vconcat $v0c, $v0d
|
||||||
|
; check: $(v0abcd=$V) = vconcat $v0ab, $v0cd
|
||||||
|
v1 = iadd v0, v0
|
||||||
|
return v0
|
||||||
|
}
|
||||||
|
|||||||
@@ -264,6 +264,40 @@ fill = Instruction(
|
|||||||
# Vector operations
|
# Vector operations
|
||||||
#
|
#
|
||||||
|
|
||||||
|
x = Operand('x', TxN, doc='Vector to split')
|
||||||
|
lo = Operand('lo', TxN.half_vector(), doc='Low-numbered lanes of `x`')
|
||||||
|
hi = Operand('hi', TxN.half_vector(), doc='High-numbered lanes of `x`')
|
||||||
|
|
||||||
|
vsplit = Instruction(
|
||||||
|
'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.
|
||||||
|
""",
|
||||||
|
ins=x, outs=(lo, hi))
|
||||||
|
|
||||||
|
Any128 = TypeVar(
|
||||||
|
'Any128', 'Any scalar or vector type with as most 128 lanes',
|
||||||
|
ints=True, floats=True, bools=True, scalars=True, simd=(1, 128))
|
||||||
|
x = Operand('x', Any128, doc='Low-numbered lanes')
|
||||||
|
y = Operand('y', Any128, doc='High-numbered lanes')
|
||||||
|
a = Operand('a', Any128.double_vector(), doc='Concatenation of `x` and `y`')
|
||||||
|
|
||||||
|
vconcat = Instruction(
|
||||||
|
'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.
|
||||||
|
""",
|
||||||
|
ins=(x, y), outs=a)
|
||||||
|
|
||||||
c = Operand('c', TxN.as_bool(), doc='Controlling vector')
|
c = Operand('c', TxN.as_bool(), doc='Controlling vector')
|
||||||
x = Operand('x', TxN, doc='Value to use where `c` is true')
|
x = Operand('x', TxN, doc='Value to use where `c` is true')
|
||||||
y = Operand('y', TxN, doc='Value to use where `c` is false')
|
y = Operand('y', TxN, doc='Value to use where `c` is false')
|
||||||
|
|||||||
@@ -315,6 +315,8 @@ class TypeVar(object):
|
|||||||
ASBOOL = 'as_bool'
|
ASBOOL = 'as_bool'
|
||||||
HALFWIDTH = 'half_width'
|
HALFWIDTH = 'half_width'
|
||||||
DOUBLEWIDTH = 'double_width'
|
DOUBLEWIDTH = 'double_width'
|
||||||
|
HALFVECTOR = 'half_vector'
|
||||||
|
DOUBLEVECTOR = 'double_vector'
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def derived(base, derived_func):
|
def derived(base, derived_func):
|
||||||
@@ -396,6 +398,30 @@ class TypeVar(object):
|
|||||||
|
|
||||||
return TypeVar.derived(self, self.DOUBLEWIDTH)
|
return TypeVar.derived(self, self.DOUBLEWIDTH)
|
||||||
|
|
||||||
|
def half_vector(self):
|
||||||
|
# type: () -> TypeVar
|
||||||
|
"""
|
||||||
|
Return a derived type variable that has half the number of vector lanes
|
||||||
|
as this one, with the same lane type.
|
||||||
|
"""
|
||||||
|
if not self.is_derived:
|
||||||
|
ts = self.type_set
|
||||||
|
assert ts.min_lanes > 1, "Can't halve a scalar type"
|
||||||
|
|
||||||
|
return TypeVar.derived(self, self.HALFVECTOR)
|
||||||
|
|
||||||
|
def double_vector(self):
|
||||||
|
# type: () -> TypeVar
|
||||||
|
"""
|
||||||
|
Return a derived type variable that has twice the number of vector
|
||||||
|
lanes as this one, with the same lane type.
|
||||||
|
"""
|
||||||
|
if not self.is_derived:
|
||||||
|
ts = self.type_set
|
||||||
|
assert ts.max_lanes < 256, "Can't double 256 lanes."
|
||||||
|
|
||||||
|
return TypeVar.derived(self, self.DOUBLEVECTOR)
|
||||||
|
|
||||||
def free_typevar(self):
|
def free_typevar(self):
|
||||||
# type: () -> TypeVar
|
# type: () -> TypeVar
|
||||||
"""
|
"""
|
||||||
|
|||||||
@@ -708,6 +708,12 @@ 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,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl OperandConstraint {
|
impl OperandConstraint {
|
||||||
@@ -725,6 +731,8 @@ impl OperandConstraint {
|
|||||||
AsBool => Some(ctrl_type.as_bool()),
|
AsBool => Some(ctrl_type.as_bool()),
|
||||||
HalfWidth => Some(ctrl_type.half_width().expect("invalid type for half_width")),
|
HalfWidth => Some(ctrl_type.half_width().expect("invalid type for half_width")),
|
||||||
DoubleWidth => Some(ctrl_type.double_width().expect("invalid type for double_width")),
|
DoubleWidth => Some(ctrl_type.double_width().expect("invalid type for double_width")),
|
||||||
|
HalfVector => Some(ctrl_type.half_vector().expect("invalid type for half_vector")),
|
||||||
|
DoubleVector => Some(ctrl_type.by(2).expect("invalid type for double_vector")),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -217,6 +217,8 @@ impl Type {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Get a SIMD vector with half the number of lanes.
|
/// 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<Type> {
|
pub fn half_vector(self) -> Option<Type> {
|
||||||
if self.is_scalar() {
|
if self.is_scalar() {
|
||||||
None
|
None
|
||||||
|
|||||||
@@ -173,9 +173,9 @@ fn convert_from_abi(dfg: &mut DataFlowGraph,
|
|||||||
// Construct a `ty` by concatenating two halves of a vector.
|
// Construct a `ty` by concatenating two halves of a vector.
|
||||||
ValueConversion::VectorSplit => {
|
ValueConversion::VectorSplit => {
|
||||||
let abi_ty = ty.half_vector().expect("Invalid type for conversion");
|
let abi_ty = ty.half_vector().expect("Invalid type for conversion");
|
||||||
let _lo = convert_from_abi(dfg, pos, entry, abi_arg, abi_types, abi_ty);
|
let lo = convert_from_abi(dfg, pos, entry, abi_arg, abi_types, abi_ty);
|
||||||
let _hi = convert_from_abi(dfg, pos, entry, abi_arg, abi_types, abi_ty);
|
let hi = convert_from_abi(dfg, pos, entry, abi_arg, abi_types, abi_ty);
|
||||||
unimplemented!()
|
dfg.ins(pos).vconcat(lo, hi)
|
||||||
}
|
}
|
||||||
// Construct a `ty` by bit-casting from an integer type.
|
// Construct a `ty` by bit-casting from an integer type.
|
||||||
ValueConversion::IntBits => {
|
ValueConversion::IntBits => {
|
||||||
|
|||||||
Reference in New Issue
Block a user