diff --git a/llvm/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp b/llvm/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp --- a/llvm/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp +++ b/llvm/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp @@ -607,30 +607,39 @@ 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 Ops; - DAG.ExtractVectorElements(Val, Ops); - SDValue EltUndef = DAG.getUNDEF(ElementVT); - for (unsigned i = ValueNumElts, e = PartNumElts; i != e; ++i) - Ops.push_back(EltUndef); - - // FIXME: Use CONCAT for 2x -> 4x. - return DAG.getBuildVector(PartVT, DL, Ops); - } + ElementCount PartNumElts = PartVT.getVectorElementCount(); + ElementCount ValueNumElts = ValueVT.getVectorElementCount(); + + // 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 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 diff --git a/llvm/lib/CodeGen/TargetLoweringBase.cpp b/llvm/lib/CodeGen/TargetLoweringBase.cpp --- a/llvm/lib/CodeGen/TargetLoweringBase.cpp +++ b/llvm/lib/CodeGen/TargetLoweringBase.cpp @@ -976,9 +976,6 @@ 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 @@ // 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 @@ 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 @@ /// 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 @@ // 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)) { diff --git a/llvm/test/CodeGen/AArch64/sve-widen-scalable-vectortype.ll b/llvm/test/CodeGen/AArch64/sve-widen-scalable-vectortype.ll new file mode 100644 --- /dev/null +++ b/llvm/test/CodeGen/AArch64/sve-widen-scalable-vectortype.ll @@ -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 @widen_1i32( %illegal) nounwind { + ret %illegal +} + +define @widen_1f64( %illegal) nounwind { + ret %illegal +} diff --git a/llvm/test/CodeGen/RISCV/rvv/legalize-scalable-vectortype.ll b/llvm/test/CodeGen/RISCV/rvv/legalize-scalable-vectortype.ll new file mode 100644 --- /dev/null +++ b/llvm/test/CodeGen/RISCV/rvv/legalize-scalable-vectortype.ll @@ -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 @trunc_nxv4i32_to_nxv4i5( %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 %a to + ret %v +} + +define @trunc_nxv1i32_to_nxv1i5( %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 %a to + ret %v +}