From 341dc45cea5dd1c891483ea543ac58dd99173557 Mon Sep 17 00:00:00 2001 From: Andrew Brown Date: Wed, 25 Mar 2020 10:15:06 -0700 Subject: [PATCH] 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, https://github.com/bytecodealliance/wasmtime/blob/1d5a678124e0f035f7614cafe43066c834a5113b/cranelift/codegen/meta/src/gen_inst.rs#L618-L621), I added `DerivedFunction::SplitLanes` to do the necessary type conversion. --- cranelift/codegen/meta/src/cdsl/typevar.rs | 25 ++++++++++++++++++++++ cranelift/codegen/src/ir/instructions.rs | 8 +++++++ cranelift/codegen/src/ir/types.rs | 10 +++++++++ 3 files changed, 43 insertions(+) diff --git a/cranelift/codegen/meta/src/cdsl/typevar.rs b/cranelift/codegen/meta/src/cdsl/typevar.rs index 302da4561f..0c0b2e9647 100644 --- a/cranelift/codegen/meta/src/cdsl/typevar.rs +++ b/cranelift/codegen/meta/src/cdsl/typevar.rs @@ -193,6 +193,24 @@ impl TypeVar { "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 */ } } @@ -227,6 +245,9 @@ impl TypeVar { pub fn double_vector(&self) -> TypeVar { 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 /// ts. @@ -333,6 +354,7 @@ pub(crate) enum DerivedFunc { DoubleWidth, HalfVector, DoubleVector, + SplitLanes, } impl DerivedFunc { @@ -344,6 +366,7 @@ impl DerivedFunc { DerivedFunc::DoubleWidth => "double_width", DerivedFunc::HalfVector => "half_vector", DerivedFunc::DoubleVector => "double_vector", + DerivedFunc::SplitLanes => "split_lanes", } } @@ -438,6 +461,7 @@ impl TypeSet { DerivedFunc::DoubleWidth => self.double_width(), DerivedFunc::HalfVector => self.half_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::HalfVector => self.double_vector(), DerivedFunc::DoubleVector => self.half_vector(), + DerivedFunc::SplitLanes => self.half_vector().double_width(), } } diff --git a/cranelift/codegen/src/ir/instructions.rs b/cranelift/codegen/src/ir/instructions.rs index afe0266fe4..deb79130d4 100644 --- a/cranelift/codegen/src/ir/instructions.rs +++ b/cranelift/codegen/src/ir/instructions.rs @@ -518,6 +518,9 @@ enum OperandConstraint { /// This operand is `ctrlType.double_vector()`. DoubleVector, + + /// This operand is `ctrlType.split_lanes()`. + SplitLanes, } impl OperandConstraint { @@ -544,6 +547,11 @@ impl OperandConstraint { .expect("invalid type for half_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"), + ), } } } diff --git a/cranelift/codegen/src/ir/types.rs b/cranelift/codegen/src/ir/types.rs index 1baca567e1..060c087747 100644 --- a/cranelift/codegen/src/ir/types.rs +++ b/cranelift/codegen/src/ir/types.rs @@ -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 { + match self.half_width() { + Some(half_width) => half_width.by(2), + None => None, + } + } + /// Index of this type, for use with hash tables etc. pub fn index(self) -> usize { usize::from(self.0)