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 @@ -955,6 +955,12 @@ unsigned NumVectorRegs = 1; + // Scalable vectors cannot be scalarized, so splitting or widening is + // required. + if (VT.isScalableVector() && !isPowerOf2_32(EC.Min)) + llvm_unreachable( + "Splitting or widening of non-power-of-2 MVTs is not implemented."); + // FIXME: We don't support non-power-of-2-sized vectors for now. // Ideally we could break down into LHS/RHS like LegalizeDAG does. if (!isPowerOf2_32(EC.Min)) { @@ -1418,8 +1424,34 @@ unsigned NumVectorRegs = 1; - // FIXME: We don't support non-power-of-2-sized vectors for now. Ideally we - // could break down into LHS/RHS like LegalizeDAG does. + // Scalable vectors cannot be scalarized, so handle the legalisation of the + // types like done elsewhere in SelectionDAG. + if (VT.isScalableVector() && !isPowerOf2_32(EltCnt.Min)) { + LegalizeKind LK; + EVT PartVT = VT; + do { + // Iterate until we've found a legal (part) type to hold VT. + LK = getTypeConversion(Context, PartVT); + PartVT = LK.second; + } while (LK.first != TypeLegal); + + NumIntermediates = + VT.getVectorElementCount().Min / PartVT.getVectorElementCount().Min; + + // FIXME: This code needs to be extended to handle more complex vector + // breakdowns, like nxv7i64 -> nxv8i64 -> 4 x nxv2i64. Currently the only + // supported cases are vectors that are broken down into equal parts + // such as nxv6i64 -> 3 x nxv2i64. + assert(NumIntermediates * PartVT.getVectorElementCount().Min == + VT.getVectorElementCount().Min && + "Expected an integer multiple of PartVT"); + IntermediateVT = PartVT; + RegisterVT = getRegisterType(Context, IntermediateVT); + return NumIntermediates; + } + + // FIXME: We don't support non-power-of-2-sized vectors for now. Ideally + // we could break down into LHS/RHS like LegalizeDAG does. if (!isPowerOf2_32(EltCnt.Min)) { NumVectorRegs = EltCnt.Min; EltCnt.Min = 1; diff --git a/llvm/test/CodeGen/AArch64/sve-breakdown-scalable-vectortype.ll b/llvm/test/CodeGen/AArch64/sve-breakdown-scalable-vectortype.ll new file mode 100644 --- /dev/null +++ b/llvm/test/CodeGen/AArch64/sve-breakdown-scalable-vectortype.ll @@ -0,0 +1,312 @@ +; RUN: llc -mtriple=aarch64--linux-gnu -mattr=+sve -asm-verbose=0 < %s | FileCheck %s + +; Test that scalable vectors that are a multiple of the legal vector size +; can be properly broken down into part vectors. + +declare void @bar() + +; +; Vectors twice the size +; + +define @wide_32i8(i1 %b, %legal, %illegal) nounwind { +; CHECK-LABEL: wide_32i8 +; CHECK: mov z0.d, z1.d +; CHECK-NEXT: mov z1.d, z2.d +; CHECK-NEXT: ret + br i1 %b, label %L1, label %L2 +L1: + call void @bar() + ret undef +L2: + ret %illegal +} + +define @wide_16i16(i1 %b, %legal, %illegal) nounwind { +; CHECK-LABEL: wide_16i16 +; CHECK: mov z0.d, z1.d +; CHECK-NEXT: mov z1.d, z2.d +; CHECK-NEXT: ret + br i1 %b, label %L1, label %L2 +L1: + call void @bar() + ret undef +L2: + ret %illegal +} + +define @wide_8i32(i1 %b, %legal, %illegal) nounwind { +; CHECK-LABEL: wide_8i32 +; CHECK: mov z0.d, z1.d +; CHECK-NEXT: mov z1.d, z2.d +; CHECK-NEXT: ret + br i1 %b, label %L1, label %L2 +L1: + call void @bar() + ret undef +L2: + ret %illegal +} + +define @wide_4i64(i1 %b, %legal, %illegal) nounwind { +; CHECK-LABEL: wide_4i64 +; CHECK: mov z0.d, z1.d +; CHECK-NEXT: mov z1.d, z2.d +; CHECK-NEXT: ret + br i1 %b, label %L1, label %L2 +L1: + call void @bar() + ret undef +L2: + ret %illegal +} + +define @wide_16f16(i1 %b, %legal, %illegal) nounwind { +; CHECK-LABEL: wide_16f16 +; CHECK: mov z0.d, z1.d +; CHECK-NEXT: mov z1.d, z2.d +; CHECK-NEXT: ret + br i1 %b, label %L1, label %L2 +L1: + call void @bar() + ret undef +L2: + ret %illegal +} + +define @wide_8f32(i1 %b, %legal, %illegal) nounwind { +; CHECK-LABEL: wide_8f32 +; CHECK: mov z0.d, z1.d +; CHECK-NEXT: mov z1.d, z2.d +; CHECK-NEXT: ret + br i1 %b, label %L1, label %L2 +L1: + call void @bar() + ret undef +L2: + ret %illegal +} + +define @wide_4f64(i1 %b, %legal, %illegal) nounwind { +; CHECK-LABEL: wide_4f64 +; CHECK: mov z0.d, z1.d +; CHECK-NEXT: mov z1.d, z2.d +; CHECK-NEXT: ret + br i1 %b, label %L1, label %L2 +L1: + call void @bar() + ret undef +L2: + ret %illegal +} + +; +; Vectors three times the size +; + +define @wide_48i8(i1 %b, %legal, %illegal) nounwind { +; CHECK-LABEL: wide_48i8 +; CHECK: mov z0.d, z1.d +; CHECK-NEXT: mov z1.d, z2.d +; CHECK-NEXT: mov z2.d, z3.d +; CHECK-NEXT: ret + br i1 %b, label %L1, label %L2 +L1: + call void @bar() + ret undef +L2: + ret %illegal +} + +define @wide_24i16(i1 %b, %legal, %illegal) nounwind { +; CHECK-LABEL: wide_24i16 +; CHECK: mov z0.d, z1.d +; CHECK-NEXT: mov z1.d, z2.d +; CHECK-NEXT: mov z2.d, z3.d +; CHECK-NEXT: ret + br i1 %b, label %L1, label %L2 +L1: + call void @bar() + ret undef +L2: + ret %illegal +} + +define @wide_12i32(i1 %b, %legal, %illegal) nounwind { +; CHECK-LABEL: wide_12i32 +; CHECK: mov z0.d, z1.d +; CHECK-NEXT: mov z1.d, z2.d +; CHECK-NEXT: mov z2.d, z3.d +; CHECK-NEXT: ret + br i1 %b, label %L1, label %L2 +L1: + call void @bar() + ret undef +L2: + ret %illegal +} + +define @wide_6i64(i1 %b, %legal, %illegal) nounwind { +; CHECK-LABEL: wide_6i64 +; CHECK: mov z0.d, z1.d +; CHECK-NEXT: mov z1.d, z2.d +; CHECK-NEXT: mov z2.d, z3.d +; CHECK-NEXT: ret + br i1 %b, label %L1, label %L2 +L1: + call void @bar() + ret undef +L2: + ret %illegal +} + +define @wide_24f16(i1 %b, %legal, %illegal) nounwind { +; CHECK-LABEL: wide_24f16 +; CHECK: mov z0.d, z1.d +; CHECK-NEXT: mov z1.d, z2.d +; CHECK-NEXT: mov z2.d, z3.d +; CHECK-NEXT: ret + br i1 %b, label %L1, label %L2 +L1: + call void @bar() + ret undef +L2: + ret %illegal +} + +define @wide_12f32(i1 %b, %legal, %illegal) nounwind { +; CHECK-LABEL: wide_12f32 +; CHECK: mov z0.d, z1.d +; CHECK-NEXT: mov z1.d, z2.d +; CHECK-NEXT: mov z2.d, z3.d +; CHECK-NEXT: ret + br i1 %b, label %L1, label %L2 +L1: + call void @bar() + ret undef +L2: + ret %illegal +} + +define @wide_6f64(i1 %b, %legal, %illegal) nounwind { +; CHECK-LABEL: wide_6f64 +; CHECK: mov z0.d, z1.d +; CHECK-NEXT: mov z1.d, z2.d +; CHECK-NEXT: mov z2.d, z3.d +; CHECK-NEXT: ret + br i1 %b, label %L1, label %L2 +L1: + call void @bar() + ret undef +L2: + ret %illegal +} + +; +; Vectors four times the size +; + +define @wide_64i8(i1 %b, %legal, %illegal) nounwind { +; CHECK-LABEL: wide_64i8 +; CHECK: mov z0.d, z1.d +; CHECK-NEXT: mov z1.d, z2.d +; CHECK-NEXT: mov z2.d, z3.d +; CHECK-NEXT: mov z3.d, z4.d +; CHECK-NEXT: ret + br i1 %b, label %L1, label %L2 +L1: + call void @bar() + ret undef +L2: + ret %illegal +} + +define @wide_32i16(i1 %b, %legal, %illegal) nounwind { +; CHECK-LABEL: wide_32i16 +; CHECK: mov z0.d, z1.d +; CHECK-NEXT: mov z1.d, z2.d +; CHECK-NEXT: mov z2.d, z3.d +; CHECK-NEXT: mov z3.d, z4.d +; CHECK-NEXT: ret + br i1 %b, label %L1, label %L2 +L1: + call void @bar() + ret undef +L2: + ret %illegal +} + +define @wide_16i32(i1 %b, %legal, %illegal) nounwind { +; CHECK-LABEL: wide_16i32 +; CHECK: mov z0.d, z1.d +; CHECK-NEXT: mov z1.d, z2.d +; CHECK-NEXT: mov z2.d, z3.d +; CHECK-NEXT: mov z3.d, z4.d +; CHECK-NEXT: ret + br i1 %b, label %L1, label %L2 +L1: + call void @bar() + ret undef +L2: + ret %illegal +} + +define @wide_8i64(i1 %b, %legal, %illegal) nounwind { +; CHECK-LABEL: wide_8i64 +; CHECK: mov z0.d, z1.d +; CHECK-NEXT: mov z1.d, z2.d +; CHECK-NEXT: mov z2.d, z3.d +; CHECK-NEXT: mov z3.d, z4.d +; CHECK-NEXT: ret + br i1 %b, label %L1, label %L2 +L1: + call void @bar() + ret undef +L2: + ret %illegal +} + +define @wide_32f16(i1 %b, %legal, %illegal) nounwind { +; CHECK-LABEL: wide_32f16 +; CHECK: mov z0.d, z1.d +; CHECK-NEXT: mov z1.d, z2.d +; CHECK-NEXT: mov z2.d, z3.d +; CHECK-NEXT: mov z3.d, z4.d +; CHECK-NEXT: ret + br i1 %b, label %L1, label %L2 +L1: + call void @bar() + ret undef +L2: + ret %illegal +} + +define @wide_16f32(i1 %b, %legal, %illegal) nounwind { +; CHECK-LABEL: wide_16f32 +; CHECK: mov z0.d, z1.d +; CHECK-NEXT: mov z1.d, z2.d +; CHECK-NEXT: mov z2.d, z3.d +; CHECK-NEXT: mov z3.d, z4.d +; CHECK-NEXT: ret + br i1 %b, label %L1, label %L2 +L1: + call void @bar() + ret undef +L2: + ret %illegal +} + +define @wide_8f64(i1 %b, %legal, %illegal) nounwind { +; CHECK-LABEL: wide_8f64 +; CHECK: mov z0.d, z1.d +; CHECK-NEXT: mov z1.d, z2.d +; CHECK-NEXT: mov z2.d, z3.d +; CHECK-NEXT: mov z3.d, z4.d +; CHECK-NEXT: ret + br i1 %b, label %L1, label %L2 +L1: + call void @bar() + ret undef +L2: + ret %illegal +}