Index: lib/CodeGen/SelectionDAG/DAGCombiner.cpp =================================================================== --- lib/CodeGen/SelectionDAG/DAGCombiner.cpp +++ lib/CodeGen/SelectionDAG/DAGCombiner.cpp @@ -82,7 +82,11 @@ MaySplitLoadIndex("combiner-split-load-index", cl::Hidden, cl::init(true), cl::desc("DAG combiner may split indexing from loads")); -//------------------------------ DAGCombiner ---------------------------------// + static cl::opt + CombinerOptBRCC("combiner-optimize-brcc", cl::Hidden, + cl::desc("Optimize removable src operand of br_cc")); + + //------------------------------ DAGCombiner--------------------------------// class DAGCombiner { SelectionDAG &DAG; @@ -9662,6 +9666,48 @@ Simp.getOperand(0), Simp.getOperand(1), N->getOperand(4)); + if (CombinerOptBRCC.getNumOccurrences() > 0) { + // %2 = add %1, #const + // br_cc cond %2, #const + // --> + // br_cc cond %1, 0 + SDNode *CondLHSNode = CondLHS.getNode(); + if (!Simp.getNode() && CondLHSNode->hasOneUse() && + CondLHSNode->getOpcode() == ISD::ADD && + (CC->get() == ISD::SETEQ || CC->get() == ISD::SETGT || + CC->get() == ISD::SETGE || CC->get() == ISD::SETLT || + CC->get() == ISD::SETLE || CC->get() == ISD::SETNE)) { + assert(N == *CondLHSNode->use_begin()); + SDValue AddLHS = CondLHSNode->getOperand(0); + SDValue AddRHS = CondLHSNode->getOperand(1); + ConstantSDNode *ConstAddRHS = dyn_cast(AddRHS); + ConstantSDNode *ConstNRHS = dyn_cast(CondRHS); + if (ConstAddRHS && ConstNRHS && + AddRHS.getValueType().getScalarType().getSizeInBits() == + CondRHS.getValueType().getScalarType().getSizeInBits() && + APInt::isSameValue(ConstAddRHS->getAPIntValue(), + ConstNRHS->getAPIntValue())) { + DEBUG(dbgs() << "ConstAddRHS and ConstNRHS are the same constants\n"); + DEBUG(dbgs() << "ConstAddRHS's value: " << ConstAddRHS->getAPIntValue() + << "\n"); + DEBUG(dbgs() << "ConstNRHS's value: " << ConstNRHS->getAPIntValue() + << "\n"); + DEBUG(dbgs() << "ConstNRHS - ConstAddRHS: " + << ConstNRHS->getAPIntValue() - + ConstAddRHS->getAPIntValue() + << "\n"); + + return DAG.getNode( + ISD::BR_CC, SDLoc(N), MVT::Other, N->getOperand(0), + N->getOperand(1), AddLHS, + DAG.getConstant( + APInt::getNullValue( + CondRHS.getValueType().getScalarType().getSizeInBits()), + SDLoc(N), CondRHS.getValueType()), + N->getOperand(4)); + } + } + } return SDValue(); } Index: test/CodeGen/AArch64/DAGCombine-optimize-brcc.ll =================================================================== --- /dev/null +++ test/CodeGen/AArch64/DAGCombine-optimize-brcc.ll @@ -0,0 +1,46 @@ +; RUN: llc -march=aarch64 -asm-verbose=false -combiner-optimize-brcc -o - %s | FileCheck %s + +; This test is for the option '-combiner-optimize-brcc' which removes an unnecessary add instruciton. +; The transformation is done as following. +; %2 = add %1, #const +; br_cc cond %2, #const +; --> +; br_cc cond %1, 0 + +; CHECK: cmp x8, #0 +; CHECK-NEXT: sub x8, x8, #1 +; CHECK-NEXT: add x0, x0, x10 +define i64 @foo(i64* %a, i64 %w) { +entry: + %cmp = icmp eq i64 %w, 0 + br i1 %cmp, label %cleanup, label %if.end + +if.end: + %0 = load i64, i64* %a, align 8 + %cmp1 = icmp sgt i64 %0, 0 + br i1 %cmp1, label %for.body.lr.ph, label %cleanup + +for.body.lr.ph: + %d1 = bitcast i64* %a to i64** + %1 = load i64*, i64** %d1, align 8 + %2 = add i64 %0, -1 + br label %for.body + +for.body: + %lsr.iv = phi i64 [ %2, %for.body.lr.ph ], [ %lsr.iv.next, %for.body ] + %ret = phi i64 [ 0, %for.body.lr.ph ], [ %ret.next, %for.body ] + %gep = getelementptr i64, i64* %1, i64 %lsr.iv + %3 = load i64, i64* %gep, align 8 + %ret.next = add i64 %ret, %3 + %lsr.iv.next = add i64 %lsr.iv, -1 + %4 = add i64 %lsr.iv.next, 2 + %cmp2 = icmp sgt i64 %4, 1 + br i1 %cmp2, label %for.body, label %for.end.loopexit + +for.end.loopexit: + br label %cleanup + +cleanup: + %conv3.sink = phi i64 [ -1, %entry ], [ 0, %if.end ], [ %ret.next, %for.end.loopexit ] + ret i64 %conv3.sink +}