diff --git a/lib/CodeGen/SelectionDAG/LegalizeVectorTypes.cpp b/lib/CodeGen/SelectionDAG/LegalizeVectorTypes.cpp index 68187dd0b8c..27f63d27823 100644 --- a/lib/CodeGen/SelectionDAG/LegalizeVectorTypes.cpp +++ b/lib/CodeGen/SelectionDAG/LegalizeVectorTypes.cpp @@ -237,7 +237,23 @@ SDValue DAGTypeLegalizer::ScalarizeVecRes_LOAD(LoadSDNode *N) { SDValue DAGTypeLegalizer::ScalarizeVecRes_UnaryOp(SDNode *N) { // Get the dest type - it doesn't always match the input type, e.g. int_to_fp. EVT DestVT = N->getValueType(0).getVectorElementType(); - SDValue Op = GetScalarizedVector(N->getOperand(0)); + SDValue Op = N->getOperand(0); + EVT OpVT = Op.getValueType(); + SDLoc DL(N); + // The result needs scalarizing, but it's not a given that the source does. + // This is a workaround for targets where it's impossible to scalarize the + // result of a conversion, because the source type is legal. + // For instance, this happens on AArch64: v1i1 is illegal but v1i{8,16,32} + // are widened to v8i8, v4i16, and v2i32, which is legal, because v1i64 is + // legal and was not scalarized. + // See the similar logic in ScalarizeVecRes_VSETCC + if (getTypeAction(OpVT) == TargetLowering::TypeScalarizeVector) { + Op = GetScalarizedVector(Op); + } else { + EVT VT = OpVT.getVectorElementType(); + Op = DAG.getNode(ISD::EXTRACT_VECTOR_ELT, DL, VT, Op, + DAG.getConstant(0, TLI.getVectorIdxTy())); + } return DAG.getNode(N->getOpcode(), SDLoc(N), DestVT, Op); } diff --git a/test/CodeGen/AArch64/trunc-v1i64.ll b/test/CodeGen/AArch64/trunc-v1i64.ll index 159b8e0cff3..19efd2fafd5 100644 --- a/test/CodeGen/AArch64/trunc-v1i64.ll +++ b/test/CodeGen/AArch64/trunc-v1i64.ll @@ -60,4 +60,23 @@ define <8 x i8> @test_v1i8_1(<1 x i64> %in0) { %1 = shufflevector <1 x i64> %in0, <1 x i64> undef, <8 x i32> %2 = trunc <8 x i64> %1 to <8 x i8> ret <8 x i8> %2 -} \ No newline at end of file +} + +; PR20777: v1i1 is also problematic, but we can't widen it, so we extract_elt +; the i64 out of the v1i64 operand, and truncate that scalar instead. + +define <1 x i1> @test_v1i1_0(<1 x i64> %in0) { +; CHECK-LABEL: test_v1i1_0: +; CHECK: fmov w0, s0 + %1 = trunc <1 x i64> %in0 to <1 x i1> + ret <1 x i1> %1 +} + +define i1 @test_v1i1_1(<1 x i64> %in0) { +; CHECK-LABEL: test_v1i1_1: +; CHECK: fmov [[REG:w[0-9]+]], s0 + %1 = trunc <1 x i64> %in0 to <1 x i1> +; CHECK: and w0, [[REG]], #0x1 + %2 = extractelement <1 x i1> %1, i32 0 + ret i1 %2 +}