diff --git a/llvm/lib/Target/WebAssembly/WebAssemblyISelLowering.cpp b/llvm/lib/Target/WebAssembly/WebAssemblyISelLowering.cpp --- a/llvm/lib/Target/WebAssembly/WebAssemblyISelLowering.cpp +++ b/llvm/lib/Target/WebAssembly/WebAssemblyISelLowering.cpp @@ -1736,6 +1736,48 @@ return DAG.getBitcast(DstType, NewShuffle); } +static SDValue combineSwizzleSplat(BuildVectorSDNode *N, SelectionDAG &DAG, + const BitVector &UndefElts) { + // This splat can only be lowered to a swizzle if all lanes but one are undef. + // + // We are looking for the following pattern: + // (insert undef, + // (extract Vec1, + // (sext (extract Vec2, Index)) + // ), + // Index + // ) + // + // To combine to: (swizzle vec1, vec2) + if (N->getValueType(0) != MVT::v16i8) + return SDValue(); + if (UndefElts.count() != 15) + return SDValue(); + unsigned Index1 = UndefElts.find_first_unset(); + auto Extract1 = N->getOperand(Index1); + if (Extract1.getOpcode() != ISD::EXTRACT_VECTOR_ELT) + return SDValue(); + auto Vec1 = Extract1.getOperand(0); + if (Vec1.getValueType() != MVT::v16i8) + return SDValue(); + auto SExt = Extract1.getOperand(1); + if (SExt.getOpcode() != ISD::SIGN_EXTEND) + return SDValue(); + auto Extract2 = SExt.getOperand(0); + if (Extract2.getOpcode() != ISD::EXTRACT_VECTOR_ELT) + return SDValue(); + auto Vec2 = Extract2.getOperand(0); + if (Vec2.getValueType() != MVT::v16i8) + return SDValue(); + if (Extract2.getOperand(1).getOpcode() != ISD::Constant) + return SDValue(); + unsigned Index2 = Extract2.getConstantOperandVal(1); + if (Index1 != Index2) + return SDValue(); + + return DAG.getNode(WebAssemblyISD::SWIZZLE, SDLoc(N), MVT::v16i8, Vec1, Vec2); +} + static SDValue performBUILD_VECTORCombine(SDNode *N, TargetLowering::DAGCombinerInfo &DCI) { auto &DAG = DCI.DAG; @@ -1744,9 +1786,16 @@ // Remove undef lanes from splats. They don't allow us to make any extra // optimizations and they can inhibit splat scalarization combines. BitVector UndefElts; - if (SDValue SplatVal = Build->getSplatValue(&UndefElts)) - if (UndefElts.any()) + if (SDValue SplatVal = Build->getSplatValue(&UndefElts)) { + if (UndefElts.any()) { + // If this BUILD_VECTOR can be implemented as a swizzle, perform that + // transformation now because once we remove the undef lanes we will not + // be able to recover the swizzle. + if (auto Swizzle = combineSwizzleSplat(Build, DAG, UndefElts)) + return Swizzle; return DAG.getSplatBuildVector(N->getValueType(0), SDLoc(N), SplatVal); + } + } return SDValue(); } diff --git a/llvm/test/CodeGen/WebAssembly/simd-build-vector.ll b/llvm/test/CodeGen/WebAssembly/simd-build-vector.ll --- a/llvm/test/CodeGen/WebAssembly/simd-build-vector.ll +++ b/llvm/test/CodeGen/WebAssembly/simd-build-vector.ll @@ -93,14 +93,10 @@ ret <8 x i16> %v7 } -;; TODO: This should be a swizzle, but will need a custom combine to -;; preempt the combine that removes undef lanes from splat -;; build_vectors, since swizzle lowering depends on those lanes being -;; undef. - ; CHECK-LABEL: swizzle_one_i8x16: ; CHECK-NEXT: .functype swizzle_one_i8x16 (v128, v128) -> (v128) -; CHECK-NOT: v8x16.swizzle +; CHECK-NEXT: v8x16.swizzle $push[[L0:[0-9]+]]=, $0, $1 +; CHECK-NEXT: return $pop[[L0]] define <16 x i8> @swizzle_one_i8x16(<16 x i8> %src, <16 x i8> %mask) { %m0 = extractelement <16 x i8> %mask, i32 0 %s0 = extractelement <16 x i8> %src, i8 %m0