diff --git a/llvm/lib/Target/AArch64/AArch64ISelLowering.cpp b/llvm/lib/Target/AArch64/AArch64ISelLowering.cpp --- a/llvm/lib/Target/AArch64/AArch64ISelLowering.cpp +++ b/llvm/lib/Target/AArch64/AArch64ISelLowering.cpp @@ -14540,24 +14540,34 @@ TargetLowering::DAGCombinerInfo &DCI) { SelectionDAG &DAG = DCI.DAG; SDValue LHS = N->getOperand(0); + SDValue RHS = N->getOperand(1); EVT VT = N->getValueType(0); if (SDValue R = performANDORCSELCombine(N, DAG)) return R; - if (!VT.isVector() || !DAG.getTargetLoweringInfo().isTypeLegal(VT)) + if (!DAG.getTargetLoweringInfo().isTypeLegal(VT)) return SDValue(); + // Although NEON has no EORV instruction, when only the least significant bit + // is required the operation is synonymous with ADDV. + if (LHS.getOpcode() == ISD::VECREDUCE_XOR && isOneConstant(RHS) && + LHS.getOperand(0).getValueType().isFixedLengthVector() && + LHS.hasOneUse()) { + SDLoc DL(N); + SDValue ADDV = DAG.getNode(ISD::VECREDUCE_ADD, DL, VT, LHS.getOperand(0)); + return DAG.getNode(ISD::AND, DL, VT, ADDV, RHS); + } + if (VT.isScalableVector()) return performSVEAndCombine(N, DCI); // The combining code below works only for NEON vectors. In particular, it // does not work for SVE when dealing with vectors wider than 128 bits. - if (!(VT.is64BitVector() || VT.is128BitVector())) + if (!VT.is64BitVector() && !VT.is128BitVector()) return SDValue(); - BuildVectorSDNode *BVN = - dyn_cast(N->getOperand(1).getNode()); + BuildVectorSDNode *BVN = dyn_cast(RHS.getNode()); if (!BVN) return SDValue(); diff --git a/llvm/test/CodeGen/AArch64/reduce-xor.ll b/llvm/test/CodeGen/AArch64/reduce-xor.ll --- a/llvm/test/CodeGen/AArch64/reduce-xor.ll +++ b/llvm/test/CodeGen/AArch64/reduce-xor.ll @@ -19,10 +19,8 @@ define i1 @test_redxor_v2i1(<2 x i1> %a) { ; CHECK-LABEL: test_redxor_v2i1: ; CHECK: // %bb.0: -; CHECK-NEXT: // kill: def $d0 killed $d0 def $q0 -; CHECK-NEXT: mov w8, v0.s[1] -; CHECK-NEXT: fmov w9, s0 -; CHECK-NEXT: eor w8, w9, w8 +; CHECK-NEXT: addp v0.2s, v0.2s, v0.2s +; CHECK-NEXT: fmov w8, s0 ; CHECK-NEXT: and w0, w8, #0x1 ; CHECK-NEXT: ret ; @@ -42,14 +40,8 @@ define i1 @test_redxor_v4i1(<4 x i1> %a) { ; CHECK-LABEL: test_redxor_v4i1: ; CHECK: // %bb.0: -; CHECK-NEXT: // kill: def $d0 killed $d0 def $q0 -; CHECK-NEXT: umov w8, v0.h[1] -; CHECK-NEXT: umov w9, v0.h[0] -; CHECK-NEXT: umov w10, v0.h[2] -; CHECK-NEXT: umov w11, v0.h[3] -; CHECK-NEXT: eor w8, w9, w8 -; CHECK-NEXT: eor w8, w8, w10 -; CHECK-NEXT: eor w8, w8, w11 +; CHECK-NEXT: addv h0, v0.4h +; CHECK-NEXT: fmov w8, s0 ; CHECK-NEXT: and w0, w8, #0x1 ; CHECK-NEXT: ret ; @@ -75,22 +67,8 @@ define i1 @test_redxor_v8i1(<8 x i1> %a) { ; CHECK-LABEL: test_redxor_v8i1: ; CHECK: // %bb.0: -; CHECK-NEXT: // kill: def $d0 killed $d0 def $q0 -; CHECK-NEXT: umov w8, v0.b[1] -; CHECK-NEXT: umov w9, v0.b[0] -; CHECK-NEXT: umov w10, v0.b[2] -; CHECK-NEXT: umov w11, v0.b[3] -; CHECK-NEXT: umov w12, v0.b[4] -; CHECK-NEXT: umov w13, v0.b[5] -; CHECK-NEXT: eor w8, w9, w8 -; CHECK-NEXT: umov w9, v0.b[6] -; CHECK-NEXT: eor w8, w8, w10 -; CHECK-NEXT: umov w10, v0.b[7] -; CHECK-NEXT: eor w8, w8, w11 -; CHECK-NEXT: eor w8, w8, w12 -; CHECK-NEXT: eor w8, w8, w13 -; CHECK-NEXT: eor w8, w8, w9 -; CHECK-NEXT: eor w8, w8, w10 +; CHECK-NEXT: addv b0, v0.8b +; CHECK-NEXT: fmov w8, s0 ; CHECK-NEXT: and w0, w8, #0x1 ; CHECK-NEXT: ret ; @@ -128,23 +106,8 @@ define i1 @test_redxor_v16i1(<16 x i1> %a) { ; CHECK-LABEL: test_redxor_v16i1: ; CHECK: // %bb.0: -; CHECK-NEXT: ext v1.16b, v0.16b, v0.16b, #8 -; CHECK-NEXT: eor v0.8b, v0.8b, v1.8b -; CHECK-NEXT: umov w8, v0.b[1] -; CHECK-NEXT: umov w9, v0.b[0] -; CHECK-NEXT: umov w10, v0.b[2] -; CHECK-NEXT: umov w11, v0.b[3] -; CHECK-NEXT: umov w12, v0.b[4] -; CHECK-NEXT: eor w8, w9, w8 -; CHECK-NEXT: umov w9, v0.b[5] -; CHECK-NEXT: eor w8, w8, w10 -; CHECK-NEXT: umov w10, v0.b[6] -; CHECK-NEXT: eor w8, w8, w11 -; CHECK-NEXT: umov w11, v0.b[7] -; CHECK-NEXT: eor w8, w8, w12 -; CHECK-NEXT: eor w8, w8, w9 -; CHECK-NEXT: eor w8, w8, w10 -; CHECK-NEXT: eor w8, w8, w11 +; CHECK-NEXT: addv b0, v0.16b +; CHECK-NEXT: fmov w8, s0 ; CHECK-NEXT: and w0, w8, #0x1 ; CHECK-NEXT: ret ;