diff --git a/cranelift/docs/langref.rst b/cranelift/docs/langref.rst index 23cc225d7f..5fb42c44a2 100644 --- a/cranelift/docs/langref.rst +++ b/cranelift/docs/langref.rst @@ -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 diff --git a/cranelift/filetests/isa/riscv/abi.cton b/cranelift/filetests/isa/riscv/abi.cton index e3bafb83e1..bb27ac20ae 100644 --- a/cranelift/filetests/isa/riscv/abi.cton +++ b/cranelift/filetests/isa/riscv/abi.cton @@ -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 +} diff --git a/lib/cretonne/meta/base/instructions.py b/lib/cretonne/meta/base/instructions.py index 9cec7d9d58..09cd2c75c7 100644 --- a/lib/cretonne/meta/base/instructions.py +++ b/lib/cretonne/meta/base/instructions.py @@ -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') diff --git a/lib/cretonne/meta/cdsl/typevar.py b/lib/cretonne/meta/cdsl/typevar.py index 580d367f51..908ebbd8cd 100644 --- a/lib/cretonne/meta/cdsl/typevar.py +++ b/lib/cretonne/meta/cdsl/typevar.py @@ -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 """ diff --git a/lib/cretonne/src/ir/instructions.rs b/lib/cretonne/src/ir/instructions.rs index c4ac3b0c20..2a956ffc86 100644 --- a/lib/cretonne/src/ir/instructions.rs +++ b/lib/cretonne/src/ir/instructions.rs @@ -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")), } } } diff --git a/lib/cretonne/src/ir/types.rs b/lib/cretonne/src/ir/types.rs index 2391ca6072..550f25804b 100644 --- a/lib/cretonne/src/ir/types.rs +++ b/lib/cretonne/src/ir/types.rs @@ -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 { if self.is_scalar() { None diff --git a/lib/cretonne/src/legalizer.rs b/lib/cretonne/src/legalizer.rs index 885a034084..9223a174b0 100644 --- a/lib/cretonne/src/legalizer.rs +++ b/lib/cretonne/src/legalizer.rs @@ -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 => {