[TargetLowering] Improve legalization of scalable vector types
This patch extends the vector type-conversion and legalization capabilities of scalable vector types. Firstly, `vscale x 1` types now behave more like the corresponding `vscale x 2+` types. This enables the integer promotion legalization of extended scalable types, such as the promotion of `<vscale x 1 x i5>` to `<vscale x 1 x i8>`. These `vscale x 1` types are also now better handled by `getVectorTypeBreakdown`, where what looks like older handling for 1-element fixed-length vector types was spuriously updated to include scalable types. Widening of scalable types is now better supported, by using `INSERT_SUBVECTOR` to insert the smaller scalable vector "value" type into the wider scalable vector "part" type. This allows AArch64 to pass and return `vscale x 1` types by value by widening. There are still cases where we are unable to legalize `vscale x 1` types, such as where expansion would require splitting the vector in two. Reviewed By: sdesmalen Differential Revision: https://reviews.llvm.org/D102073
This commit is contained in:
parent
6110b667b0
commit
c5ec00e62b
@ -607,30 +607,39 @@ static void getCopyToParts(SelectionDAG &DAG, const SDLoc &DL, SDValue Val,
|
||||
std::reverse(Parts, Parts + OrigNumParts);
|
||||
}
|
||||
|
||||
static SDValue widenVectorToPartType(SelectionDAG &DAG,
|
||||
SDValue Val, const SDLoc &DL, EVT PartVT) {
|
||||
if (!PartVT.isFixedLengthVector())
|
||||
static SDValue widenVectorToPartType(SelectionDAG &DAG, SDValue Val,
|
||||
const SDLoc &DL, EVT PartVT) {
|
||||
if (!PartVT.isVector())
|
||||
return SDValue();
|
||||
|
||||
EVT ValueVT = Val.getValueType();
|
||||
unsigned PartNumElts = PartVT.getVectorNumElements();
|
||||
unsigned ValueNumElts = ValueVT.getVectorNumElements();
|
||||
if (PartNumElts > ValueNumElts &&
|
||||
PartVT.getVectorElementType() == ValueVT.getVectorElementType()) {
|
||||
EVT ElementVT = PartVT.getVectorElementType();
|
||||
// Vector widening case, e.g. <2 x float> -> <4 x float>. Shuffle in
|
||||
// undef elements.
|
||||
SmallVector<SDValue, 16> Ops;
|
||||
DAG.ExtractVectorElements(Val, Ops);
|
||||
SDValue EltUndef = DAG.getUNDEF(ElementVT);
|
||||
for (unsigned i = ValueNumElts, e = PartNumElts; i != e; ++i)
|
||||
Ops.push_back(EltUndef);
|
||||
ElementCount PartNumElts = PartVT.getVectorElementCount();
|
||||
ElementCount ValueNumElts = ValueVT.getVectorElementCount();
|
||||
|
||||
// FIXME: Use CONCAT for 2x -> 4x.
|
||||
return DAG.getBuildVector(PartVT, DL, Ops);
|
||||
}
|
||||
// We only support widening vectors with equivalent element types and
|
||||
// fixed/scalable properties. If a target needs to widen a fixed-length type
|
||||
// to a scalable one, it should be possible to use INSERT_SUBVECTOR below.
|
||||
if (ElementCount::isKnownLE(PartNumElts, ValueNumElts) ||
|
||||
PartNumElts.isScalable() != ValueNumElts.isScalable() ||
|
||||
PartVT.getVectorElementType() != ValueVT.getVectorElementType())
|
||||
return SDValue();
|
||||
|
||||
return SDValue();
|
||||
// Widening a scalable vector to another scalable vector is done by inserting
|
||||
// the vector into a larger undef one.
|
||||
if (PartNumElts.isScalable())
|
||||
return DAG.getNode(ISD::INSERT_SUBVECTOR, DL, PartVT, DAG.getUNDEF(PartVT),
|
||||
Val, DAG.getVectorIdxConstant(0, DL));
|
||||
|
||||
EVT ElementVT = PartVT.getVectorElementType();
|
||||
// Vector widening case, e.g. <2 x float> -> <4 x float>. Shuffle in
|
||||
// undef elements.
|
||||
SmallVector<SDValue, 16> Ops;
|
||||
DAG.ExtractVectorElements(Val, Ops);
|
||||
SDValue EltUndef = DAG.getUNDEF(ElementVT);
|
||||
Ops.append((PartNumElts - ValueNumElts).getFixedValue(), EltUndef);
|
||||
|
||||
// FIXME: Use CONCAT for 2x -> 4x.
|
||||
return DAG.getBuildVector(PartVT, DL, Ops);
|
||||
}
|
||||
|
||||
/// getCopyToPartsVector - Create a series of nodes that contain the specified
|
||||
|
||||
@ -976,9 +976,6 @@ TargetLoweringBase::getTypeConversion(LLVMContext &Context, EVT VT) const {
|
||||
if (NumElts.isScalar())
|
||||
return LegalizeKind(TypeScalarizeVector, EltVT);
|
||||
|
||||
if (VT.getVectorElementCount() == ElementCount::getScalable(1))
|
||||
report_fatal_error("Cannot legalize this vector");
|
||||
|
||||
// Try to widen vector elements until the element type is a power of two and
|
||||
// promote it to a legal type later on, for example:
|
||||
// <3 x i8> -> <4 x i8> -> <4 x i32>
|
||||
@ -996,9 +993,12 @@ TargetLoweringBase::getTypeConversion(LLVMContext &Context, EVT VT) const {
|
||||
|
||||
// If type is to be expanded, split the vector.
|
||||
// <4 x i140> -> <2 x i140>
|
||||
if (LK.first == TypeExpandInteger)
|
||||
if (LK.first == TypeExpandInteger) {
|
||||
if (VT.getVectorElementCount() == ElementCount::getScalable(1))
|
||||
report_fatal_error("Cannot legalize this scalable vector");
|
||||
return LegalizeKind(TypeSplitVector,
|
||||
VT.getHalfNumVectorElementsVT(Context));
|
||||
}
|
||||
|
||||
// Promote the integer element types until a legal vector type is found
|
||||
// or until the element integer type is too big. If a legal type was not
|
||||
@ -1057,6 +1057,9 @@ TargetLoweringBase::getTypeConversion(LLVMContext &Context, EVT VT) const {
|
||||
return LegalizeKind(TypeWidenVector, NVT);
|
||||
}
|
||||
|
||||
if (VT.getVectorElementCount() == ElementCount::getScalable(1))
|
||||
report_fatal_error("Cannot legalize this vector");
|
||||
|
||||
// Vectors with illegal element types are expanded.
|
||||
EVT NVT = EVT::getVectorVT(Context, EltVT,
|
||||
VT.getVectorElementCount().divideCoefficientBy(2));
|
||||
@ -1497,10 +1500,10 @@ MVT::SimpleValueType TargetLoweringBase::getCmpLibcallReturnType() const {
|
||||
/// This method returns the number of registers needed, and the VT for each
|
||||
/// register. It also returns the VT and quantity of the intermediate values
|
||||
/// before they are promoted/expanded.
|
||||
unsigned TargetLoweringBase::getVectorTypeBreakdown(LLVMContext &Context, EVT VT,
|
||||
EVT &IntermediateVT,
|
||||
unsigned &NumIntermediates,
|
||||
MVT &RegisterVT) const {
|
||||
unsigned TargetLoweringBase::getVectorTypeBreakdown(LLVMContext &Context,
|
||||
EVT VT, EVT &IntermediateVT,
|
||||
unsigned &NumIntermediates,
|
||||
MVT &RegisterVT) const {
|
||||
ElementCount EltCnt = VT.getVectorElementCount();
|
||||
|
||||
// If there is a wider vector type with the same element type as this one,
|
||||
@ -1509,7 +1512,7 @@ unsigned TargetLoweringBase::getVectorTypeBreakdown(LLVMContext &Context, EVT VT
|
||||
// This handles things like <2 x float> -> <4 x float> and
|
||||
// <4 x i1> -> <4 x i32>.
|
||||
LegalizeTypeAction TA = getTypeAction(Context, VT);
|
||||
if (EltCnt.getKnownMinValue() != 1 &&
|
||||
if (!EltCnt.isScalar() &&
|
||||
(TA == TypeWidenVector || TA == TypePromoteInteger)) {
|
||||
EVT RegisterEVT = getTypeToTransformTo(Context, VT);
|
||||
if (isTypeLegal(RegisterEVT)) {
|
||||
|
||||
18
llvm/test/CodeGen/AArch64/sve-widen-scalable-vectortype.ll
Normal file
18
llvm/test/CodeGen/AArch64/sve-widen-scalable-vectortype.ll
Normal file
@ -0,0 +1,18 @@
|
||||
; RUN: llc -mtriple=aarch64--linux-gnu -mattr=+sve -asm-verbose=0 < %s
|
||||
|
||||
; Test that scalable vectors that are smaller than the legal vector size can be
|
||||
; properly widened to part vectors.
|
||||
|
||||
;
|
||||
; Vectors that need widening
|
||||
;
|
||||
|
||||
; For now, just check that these don't crash during legalization. Widening of
|
||||
; scalable-vector INSERT_SUBVECTOR and EXTRACT_SUBVECTOR is not yet available.
|
||||
define <vscale x 1 x i32> @widen_1i32(<vscale x 1 x i32> %illegal) nounwind {
|
||||
ret <vscale x 1 x i32> %illegal
|
||||
}
|
||||
|
||||
define <vscale x 1 x double> @widen_1f64(<vscale x 1 x double> %illegal) nounwind {
|
||||
ret <vscale x 1 x double> %illegal
|
||||
}
|
||||
27
llvm/test/CodeGen/RISCV/rvv/legalize-scalable-vectortype.ll
Normal file
27
llvm/test/CodeGen/RISCV/rvv/legalize-scalable-vectortype.ll
Normal file
@ -0,0 +1,27 @@
|
||||
; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py
|
||||
; RUN: llc -mtriple=riscv32 -mattr=+experimental-v -verify-machineinstrs < %s | FileCheck %s
|
||||
; RUN: llc -mtriple=riscv64 -mattr=+experimental-v -verify-machineinstrs < %s | FileCheck %s
|
||||
|
||||
define <vscale x 4 x i5> @trunc_nxv4i32_to_nxv4i5(<vscale x 4 x i32> %a) {
|
||||
; CHECK-LABEL: trunc_nxv4i32_to_nxv4i5:
|
||||
; CHECK: # %bb.0:
|
||||
; CHECK-NEXT: vsetvli a0, zero, e16,m1,ta,mu
|
||||
; CHECK-NEXT: vnsrl.wi v25, v8, 0
|
||||
; CHECK-NEXT: vsetvli a0, zero, e8,mf2,ta,mu
|
||||
; CHECK-NEXT: vnsrl.wi v8, v25, 0
|
||||
; CHECK-NEXT: ret
|
||||
%v = trunc <vscale x 4 x i32> %a to <vscale x 4 x i5>
|
||||
ret <vscale x 4 x i5> %v
|
||||
}
|
||||
|
||||
define <vscale x 1 x i5> @trunc_nxv1i32_to_nxv1i5(<vscale x 1 x i32> %a) {
|
||||
; CHECK-LABEL: trunc_nxv1i32_to_nxv1i5:
|
||||
; CHECK: # %bb.0:
|
||||
; CHECK-NEXT: vsetvli a0, zero, e16,mf4,ta,mu
|
||||
; CHECK-NEXT: vnsrl.wi v25, v8, 0
|
||||
; CHECK-NEXT: vsetvli a0, zero, e8,mf8,ta,mu
|
||||
; CHECK-NEXT: vnsrl.wi v8, v25, 0
|
||||
; CHECK-NEXT: ret
|
||||
%v = trunc <vscale x 1 x i32> %a to <vscale x 1 x i5>
|
||||
ret <vscale x 1 x i5> %v
|
||||
}
|
||||
Loading…
x
Reference in New Issue
Block a user