Index: llvm/lib/Target/AArch64/AArch64ISelLowering.cpp =================================================================== --- llvm/lib/Target/AArch64/AArch64ISelLowering.cpp +++ llvm/lib/Target/AArch64/AArch64ISelLowering.cpp @@ -14364,6 +14364,29 @@ return DAG.getNode(N->getOpcode(), SDLoc(N), VT, LHS, RHS); } +static SDValue performNegCSelCombine(SDNode *N, SelectionDAG &DAG) { + if (N->getOpcode() != ISD::SUB || !isNullConstant(N->getOperand(0))) + return SDValue(); + + SDValue CSel = N->getOperand(1); + if (CSel.getOpcode() != AArch64ISD::CSEL || !CSel->hasOneUse()) + return SDValue(); + + SDValue N0 = CSel->getOperand(0); + SDValue N1 = CSel->getOperand(1); + + if ((N0.getOpcode() != ISD::SUB || !isNullConstant(N0.getOperand(0))) && + (N1.getOpcode() != ISD::SUB || !isNullConstant(N1.getOperand(0)))) + return SDValue(); + + EVT VT = CSel.getValueType(); + SDLoc DL(CSel); + SDValue N0N = DAG.getNode(N->getOpcode(), DL, VT, N->getOperand(0), N0); + SDValue N1N = DAG.getNode(N->getOpcode(), DL, VT, N->getOperand(0), N1); + return DAG.getNode(AArch64ISD::CSEL, DL, VT, N0N, N1N, CSel->getOperand(2), + CSel->getOperand(3)); +} + static SDValue performAddSubCombine(SDNode *N, TargetLowering::DAGCombinerInfo &DCI, SelectionDAG &DAG) { @@ -14372,6 +14395,8 @@ return Val; if (SDValue Val = performAddDotCombine(N, DAG)) return Val; + if (SDValue Val = performNegCSelCombine(N, DAG)) + return Val; return performAddSubLongCombine(N, DCI, DAG); } Index: llvm/test/CodeGen/AArch64/csel-addsubconst.ll =================================================================== --- llvm/test/CodeGen/AArch64/csel-addsubconst.ll +++ llvm/test/CodeGen/AArch64/csel-addsubconst.ll @@ -204,8 +204,7 @@ ; CHECK-LABEL: negneg: ; CHECK: // %bb.0: ; CHECK-NEXT: cmp w2, #0 -; CHECK-NEXT: csneg w8, w1, w0, gt -; CHECK-NEXT: neg w0, w8 +; CHECK-NEXT: csneg w0, w0, w1, le ; CHECK-NEXT: ret %s = sub i32 0, %x %c = icmp sgt i32 %z, 0 @@ -218,8 +217,7 @@ ; CHECK-LABEL: negnegr: ; CHECK: // %bb.0: ; CHECK-NEXT: cmp w2, #0 -; CHECK-NEXT: csneg w8, w1, w0, le -; CHECK-NEXT: neg w0, w8 +; CHECK-NEXT: csneg w0, w0, w1, gt ; CHECK-NEXT: ret %s = sub i32 0, %x %c = icmp sgt i32 %z, 0 @@ -231,10 +229,8 @@ define i32 @negdoubleneg(i32 %x, i32 %y, i32 %z) { ; CHECK-LABEL: negdoubleneg: ; CHECK: // %bb.0: -; CHECK-NEXT: neg w8, w1 ; CHECK-NEXT: cmp w2, #0 -; CHECK-NEXT: csneg w8, w8, w0, le -; CHECK-NEXT: neg w0, w8 +; CHECK-NEXT: csel w0, w1, w0, le ; CHECK-NEXT: ret %s1 = sub i32 0, %x %s2 = sub i32 0, %y Index: llvm/test/CodeGen/AArch64/neg-abs.ll =================================================================== --- llvm/test/CodeGen/AArch64/neg-abs.ll +++ llvm/test/CodeGen/AArch64/neg-abs.ll @@ -8,8 +8,7 @@ ; CHECK-LABEL: neg_abs64: ; CHECK: // %bb.0: ; CHECK-NEXT: cmp x0, #0 -; CHECK-NEXT: cneg x8, x0, mi -; CHECK-NEXT: neg x0, x8 +; CHECK-NEXT: cneg x0, x0, pl ; CHECK-NEXT: ret %abs = tail call i64 @llvm.abs.i64(i64 %x, i1 true) %neg = sub nsw i64 0, %abs @@ -22,8 +21,7 @@ ; CHECK-LABEL: neg_abs32: ; CHECK: // %bb.0: ; CHECK-NEXT: cmp w0, #0 -; CHECK-NEXT: cneg w8, w0, mi -; CHECK-NEXT: neg w0, w8 +; CHECK-NEXT: cneg w0, w0, pl ; CHECK-NEXT: ret %abs = tail call i32 @llvm.abs.i32(i32 %x, i1 true) %neg = sub nsw i32 0, %abs