diff --git a/llvm/lib/CodeGen/SelectionDAG/LegalizeIntegerTypes.cpp b/llvm/lib/CodeGen/SelectionDAG/LegalizeIntegerTypes.cpp --- a/llvm/lib/CodeGen/SelectionDAG/LegalizeIntegerTypes.cpp +++ b/llvm/lib/CodeGen/SelectionDAG/LegalizeIntegerTypes.cpp @@ -4786,6 +4786,23 @@ SDValue InOp0 = N->getOperand(0); EVT InVT = InOp0.getValueType(); + // Try and extract from a smaller type so that it eventually falls + // into the promotion code below. + if (getTypeAction(InVT) == TargetLowering::TypeSplitVector || + getTypeAction(InVT) == TargetLowering::TypeLegal) { + EVT NInVT = InVT.getHalfNumVectorElementsVT(*DAG.getContext()); + unsigned NElts = NInVT.getVectorMinNumElements(); + uint64_t IdxVal = cast(BaseIdx)->getZExtValue(); + + SDValue Step1 = DAG.getNode(ISD::EXTRACT_SUBVECTOR, dl, NInVT, InOp0, + DAG.getConstant(alignDown(IdxVal, NElts), dl, + BaseIdx.getValueType())); + SDValue Step2 = DAG.getNode( + ISD::EXTRACT_SUBVECTOR, dl, OutVT, Step1, + DAG.getConstant(IdxVal % NElts, dl, BaseIdx.getValueType())); + return DAG.getNode(ISD::ANY_EXTEND, dl, NOutVT, Step2); + } + // Promote operands and see if this is handled by target lowering, // Otherwise, use the BUILD_VECTOR approach below if (getTypeAction(InVT) == TargetLowering::TypePromoteInteger) { diff --git a/llvm/test/CodeGen/AArch64/sve-extract-vector.ll b/llvm/test/CodeGen/AArch64/sve-extract-vector.ll --- a/llvm/test/CodeGen/AArch64/sve-extract-vector.ll +++ b/llvm/test/CodeGen/AArch64/sve-extract-vector.ll @@ -370,6 +370,185 @@ ret %res } +; +; Extracting illegal vector that needs promotion from a vector that needs splitting. +; + +define @extract_nxv2i8_nxv32i8_0( %vec) { +; CHECK-LABEL: extract_nxv2i8_nxv32i8_0: +; CHECK: // %bb.0: +; CHECK-NEXT: uunpklo z0.h, z0.b +; CHECK-NEXT: uunpklo z0.s, z0.h +; CHECK-NEXT: uunpklo z0.d, z0.s +; CHECK-NEXT: ret + %res = call @llvm.experimental.vector.extract.nxv2i8.nxv32i8( %vec, i64 0) + ret %res +} + +define @extract_nxv2i8_nxv32i8_2( %vec) { +; CHECK-LABEL: extract_nxv2i8_nxv32i8_2: +; CHECK: // %bb.0: +; CHECK-NEXT: uunpklo z0.h, z0.b +; CHECK-NEXT: uunpklo z0.s, z0.h +; CHECK-NEXT: uunpkhi z0.d, z0.s +; CHECK-NEXT: ret + %res = call @llvm.experimental.vector.extract.nxv2i8.nxv32i8( %vec, i64 2) + ret %res +} + +define @extract_nxv2i8_nxv32i8_4( %vec) { +; CHECK-LABEL: extract_nxv2i8_nxv32i8_4: +; CHECK: // %bb.0: +; CHECK-NEXT: uunpklo z0.h, z0.b +; CHECK-NEXT: uunpkhi z0.s, z0.h +; CHECK-NEXT: uunpklo z0.d, z0.s +; CHECK-NEXT: ret + %res = call @llvm.experimental.vector.extract.nxv2i8.nxv32i8( %vec, i64 4) + ret %res +} + +define @extract_nxv2i8_nxv32i8_6( %vec) { +; CHECK-LABEL: extract_nxv2i8_nxv32i8_6: +; CHECK: // %bb.0: +; CHECK-NEXT: uunpklo z0.h, z0.b +; CHECK-NEXT: uunpkhi z0.s, z0.h +; CHECK-NEXT: uunpkhi z0.d, z0.s +; CHECK-NEXT: ret + %res = call @llvm.experimental.vector.extract.nxv2i8.nxv32i8( %vec, i64 6) + ret %res +} + +define @extract_nxv2i8_nxv32i8_8( %vec) { +; CHECK-LABEL: extract_nxv2i8_nxv32i8_8: +; CHECK: // %bb.0: +; CHECK-NEXT: uunpkhi z0.h, z0.b +; CHECK-NEXT: uunpklo z0.s, z0.h +; CHECK-NEXT: uunpklo z0.d, z0.s +; CHECK-NEXT: ret + %res = call @llvm.experimental.vector.extract.nxv2i8.nxv32i8( %vec, i64 8) + ret %res +} + +define @extract_nxv2i8_nxv32i8_10( %vec) { +; CHECK-LABEL: extract_nxv2i8_nxv32i8_10: +; CHECK: // %bb.0: +; CHECK-NEXT: uunpkhi z0.h, z0.b +; CHECK-NEXT: uunpklo z0.s, z0.h +; CHECK-NEXT: uunpkhi z0.d, z0.s +; CHECK-NEXT: ret + %res = call @llvm.experimental.vector.extract.nxv2i8.nxv32i8( %vec, i64 10) + ret %res +} + +define @extract_nxv2i8_nxv32i8_12( %vec) { +; CHECK-LABEL: extract_nxv2i8_nxv32i8_12: +; CHECK: // %bb.0: +; CHECK-NEXT: uunpkhi z0.h, z0.b +; CHECK-NEXT: uunpkhi z0.s, z0.h +; CHECK-NEXT: uunpklo z0.d, z0.s +; CHECK-NEXT: ret + %res = call @llvm.experimental.vector.extract.nxv2i8.nxv32i8( %vec, i64 12) + ret %res +} + +define @extract_nxv2i8_nxv32i8_14( %vec) { +; CHECK-LABEL: extract_nxv2i8_nxv32i8_14: +; CHECK: // %bb.0: +; CHECK-NEXT: uunpkhi z0.h, z0.b +; CHECK-NEXT: uunpkhi z0.s, z0.h +; CHECK-NEXT: uunpkhi z0.d, z0.s +; CHECK-NEXT: ret + %res = call @llvm.experimental.vector.extract.nxv2i8.nxv32i8( %vec, i64 14) + ret %res +} + +define @extract_nxv2i8_nxv32i8_16( %vec) { +; CHECK-LABEL: extract_nxv2i8_nxv32i8_16: +; CHECK: // %bb.0: +; CHECK-NEXT: uunpklo z0.h, z1.b +; CHECK-NEXT: uunpklo z0.s, z0.h +; CHECK-NEXT: uunpklo z0.d, z0.s +; CHECK-NEXT: ret + %res = call @llvm.experimental.vector.extract.nxv2i8.nxv32i8( %vec, i64 16) + ret %res +} + +define @extract_nxv2i8_nxv32i8_18( %vec) { +; CHECK-LABEL: extract_nxv2i8_nxv32i8_18: +; CHECK: // %bb.0: +; CHECK-NEXT: uunpklo z0.h, z1.b +; CHECK-NEXT: uunpklo z0.s, z0.h +; CHECK-NEXT: uunpkhi z0.d, z0.s +; CHECK-NEXT: ret + %res = call @llvm.experimental.vector.extract.nxv2i8.nxv32i8( %vec, i64 18) + ret %res +} + +define @extract_nxv2i8_nxv32i8_20( %vec) { +; CHECK-LABEL: extract_nxv2i8_nxv32i8_20: +; CHECK: // %bb.0: +; CHECK-NEXT: uunpklo z0.h, z1.b +; CHECK-NEXT: uunpkhi z0.s, z0.h +; CHECK-NEXT: uunpklo z0.d, z0.s +; CHECK-NEXT: ret + %res = call @llvm.experimental.vector.extract.nxv2i8.nxv32i8( %vec, i64 20) + ret %res +} + +define @extract_nxv2i8_nxv32i8_22( %vec) { +; CHECK-LABEL: extract_nxv2i8_nxv32i8_22: +; CHECK: // %bb.0: +; CHECK-NEXT: uunpklo z0.h, z1.b +; CHECK-NEXT: uunpkhi z0.s, z0.h +; CHECK-NEXT: uunpkhi z0.d, z0.s +; CHECK-NEXT: ret + %res = call @llvm.experimental.vector.extract.nxv2i8.nxv32i8( %vec, i64 22) + ret %res +} + +define @extract_nxv2i8_nxv32i8_24( %vec) { +; CHECK-LABEL: extract_nxv2i8_nxv32i8_24: +; CHECK: // %bb.0: +; CHECK-NEXT: uunpkhi z0.h, z1.b +; CHECK-NEXT: uunpklo z0.s, z0.h +; CHECK-NEXT: uunpklo z0.d, z0.s +; CHECK-NEXT: ret + %res = call @llvm.experimental.vector.extract.nxv2i8.nxv32i8( %vec, i64 24) + ret %res +} + +define @extract_nxv2i8_nxv32i8_26( %vec) { +; CHECK-LABEL: extract_nxv2i8_nxv32i8_26: +; CHECK: // %bb.0: +; CHECK-NEXT: uunpkhi z0.h, z1.b +; CHECK-NEXT: uunpklo z0.s, z0.h +; CHECK-NEXT: uunpkhi z0.d, z0.s +; CHECK-NEXT: ret + %res = call @llvm.experimental.vector.extract.nxv2i8.nxv32i8( %vec, i64 26) + ret %res +} + +define @extract_nxv2i8_nxv32i8_28( %vec) { +; CHECK-LABEL: extract_nxv2i8_nxv32i8_28: +; CHECK: // %bb.0: +; CHECK-NEXT: uunpkhi z0.h, z1.b +; CHECK-NEXT: uunpkhi z0.s, z0.h +; CHECK-NEXT: uunpklo z0.d, z0.s +; CHECK-NEXT: ret + %res = call @llvm.experimental.vector.extract.nxv2i8.nxv32i8( %vec, i64 28) + ret %res +} + +define @extract_nxv2i8_nxv32i8_30( %vec) { +; CHECK-LABEL: extract_nxv2i8_nxv32i8_30: +; CHECK: // %bb.0: +; CHECK-NEXT: uunpkhi z0.h, z1.b +; CHECK-NEXT: uunpkhi z0.s, z0.h +; CHECK-NEXT: uunpkhi z0.d, z0.s +; CHECK-NEXT: ret + %res = call @llvm.experimental.vector.extract.nxv2i8.nxv32i8( %vec, i64 30) + ret %res +} attributes #0 = { vscale_range(2,2) } @@ -386,3 +565,5 @@ declare @llvm.experimental.vector.extract.nxv2i1.nxv16i1(, i64) declare @llvm.experimental.vector.extract.nxv2i1.nxv8i1(, i64) declare @llvm.experimental.vector.extract.nxv4i1.nxv16i1(, i64) + +declare @llvm.experimental.vector.extract.nxv2i8.nxv32i8( , i64)