Index: lib/Target/ARM64/ARM64ISelLowering.cpp =================================================================== --- lib/Target/ARM64/ARM64ISelLowering.cpp +++ lib/Target/ARM64/ARM64ISelLowering.cpp @@ -3985,38 +3985,50 @@ static bool isEXTMask(ArrayRef M, EVT VT, bool &ReverseEXT, unsigned &Imm) { unsigned NumElts = VT.getVectorNumElements(); - ReverseEXT = false; - // Look for the first non-undef choice and count backwards from - // that. E.g. <-1, -1, 3, ...> means that an EXT must start at 3 - 2 = 1. This - // guarantees that at least one index is correct. + // Look for the first non-undef mask. const int *FirstRealElt = std::find_if(M.begin(), M.end(), [](int Elt) { return Elt >= 0; }); assert(FirstRealElt != M.end() && "Completely UNDEF shuffle? Why bother?"); - Imm = *FirstRealElt - (FirstRealElt - M.begin()); - // If this is a VEXT shuffle, the immediate value is the index of the first - // element. The other shuffle indices must be the successive elements after - // the first one. - unsigned ExpectedElt = Imm; - for (unsigned i = 1; i < NumElts; ++i) { - // Increment the expected index. If it wraps around, it may still be - // a VEXT but the source vectors must be swapped. + unsigned FirstRealMask = static_cast(*FirstRealElt); + unsigned ExpectedElt = FirstRealMask; + // Check whether the following masks are satisfied. + for (unsigned i = FirstRealElt - M.begin() + 1; i < NumElts; ++i) { ExpectedElt += 1; - if (ExpectedElt == NumElts * 2) { + if (ExpectedElt == NumElts * 2) ExpectedElt = 0; - ReverseEXT = true; - } - if (M[i] < 0) continue; // ignore UNDEF indices if (ExpectedElt != static_cast(M[i])) return false; } - // Adjust the index value if the source operands will be swapped. - if (ReverseEXT) - Imm -= NumElts; + ReverseEXT = false; + // If the result elements start from the second operand, we need to traverse + // two operands and adjust the start index.E.g. For two v8i8 type V0 and V1, + // "shuffle V0, V1, <9, 10, 0, 1, 2, 3, 4, 5>" is translated into + // "EXT V1, V0, #1" (mask 9 is the element 1 of V1). + // Also watch out 2 situations if there are some beginning UNDEFs: + // (1) is treated as <1, 2, 3, ...>. + // (2) is treated as + // <(2*NumElts -2), (2*NumElts -1), 0, 1, ...>. + if (FirstRealElt == M.begin()) { // No UNDEFs before the first real mask. + Imm = FirstRealMask; + if (Imm > NumElts) { // Traverse operands and adjust the start index. + ReverseEXT = true; + Imm -= NumElts; + } + } else { + unsigned HeadUNDEFs = FirstRealElt - M.begin(); + if (FirstRealMask >= HeadUNDEFs) { + Imm = FirstRealMask - HeadUNDEFs; + } else { + // Traverse operands and adjust the start index. + ReverseEXT = true; + Imm = NumElts - (HeadUNDEFs - FirstRealMask); + } + } return true; } Index: test/CodeGen/ARM64/ext.ll =================================================================== --- test/CodeGen/ARM64/ext.ll +++ test/CodeGen/ARM64/ext.ll @@ -65,6 +65,15 @@ ret <8 x i8> %tmp3 } +define <8 x i8> @test_vextd_undef2(<8 x i8>* %A, <8 x i8>* %B) nounwind { +;CHECK-LABEL: test_vextd_undef2: +;CHECK: {{ext.8b.*#6}} + %tmp1 = load <8 x i8>* %A + %tmp2 = load <8 x i8>* %B + %tmp3 = shufflevector <8 x i8> %tmp1, <8 x i8> %tmp2, <8 x i32> + ret <8 x i8> %tmp3 +} + define <16 x i8> @test_vextRq_undef(<16 x i8>* %A, <16 x i8>* %B) nounwind { ;CHECK-LABEL: test_vextRq_undef: ;CHECK: {{ext.16b.*#7}} @@ -74,6 +83,14 @@ ret <16 x i8> %tmp3 } +define <8 x i16> @test_vextRq_undef2(<8 x i16>* %A) nounwind { +;CHECK-LABEL: test_vextRq_undef2: +;CHECK: {{ext.16b.*#10}} + %tmp1 = load <8 x i16>* %A + %vext = shufflevector <8 x i16> %tmp1, <8 x i16> undef, <8 x i32> + ret <8 x i16> %vext; +} + ; Tests for ReconstructShuffle function. Indices have to be carefully ; chosen to reach lowering phase as a BUILD_VECTOR.