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:
Jakob Stoklund Olesen
2017-03-07 14:15:55 -08:00
parent 37b2e94c72
commit fd58b7cc29
7 changed files with 97 additions and 10 deletions

View File

@@ -668,14 +668,9 @@ allocation pass and beyond.
Vector operations
-----------------
.. autoinst:: vsplit
.. autoinst:: vconcat
.. autoinst:: vselect
.. inst:: a = vbuild x, y, z, ...
Vector build.
Build a vector value from the provided lanes.
.. autoinst:: splat
.. autoinst:: insertlane
.. autoinst:: extractlane

View File

@@ -21,6 +21,14 @@ function f(i32) {
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]
; 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):
return_reg v0
}
@@ -32,3 +40,17 @@ ebb0(v0: i64):
v1 = iadd_imm v0, 1
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
}

View File

@@ -264,6 +264,40 @@ fill = Instruction(
# 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')
x = Operand('x', TxN, doc='Value to use where `c` is true')
y = Operand('y', TxN, doc='Value to use where `c` is false')

View File

@@ -315,6 +315,8 @@ class TypeVar(object):
ASBOOL = 'as_bool'
HALFWIDTH = 'half_width'
DOUBLEWIDTH = 'double_width'
HALFVECTOR = 'half_vector'
DOUBLEVECTOR = 'double_vector'
@staticmethod
def derived(base, derived_func):
@@ -396,6 +398,30 @@ class TypeVar(object):
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):
# type: () -> TypeVar
"""

View File

@@ -708,6 +708,12 @@ enum OperandConstraint {
/// This operand is `ctrlType.double_width()`.
DoubleWidth,
/// This operand is `ctrlType.half_vector()`.
HalfVector,
/// This operand is `ctrlType.double_vector()`.
DoubleVector,
}
impl OperandConstraint {
@@ -725,6 +731,8 @@ impl OperandConstraint {
AsBool => Some(ctrl_type.as_bool()),
HalfWidth => Some(ctrl_type.half_width().expect("invalid type for half_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")),
}
}
}

View File

@@ -217,6 +217,8 @@ impl Type {
}
/// 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> {
if self.is_scalar() {
None

View File

@@ -173,9 +173,9 @@ fn convert_from_abi(dfg: &mut DataFlowGraph,
// Construct a `ty` by concatenating two halves of a vector.
ValueConversion::VectorSplit => {
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 _hi = convert_from_abi(dfg, pos, entry, abi_arg, abi_types, abi_ty);
unimplemented!()
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);
dfg.ins(pos).vconcat(lo, hi)
}
// Construct a `ty` by bit-casting from an integer type.
ValueConversion::IntBits => {