diff --git a/llvm/lib/Transforms/InstCombine/InstructionCombining.cpp b/llvm/lib/Transforms/InstCombine/InstructionCombining.cpp --- a/llvm/lib/Transforms/InstCombine/InstructionCombining.cpp +++ b/llvm/lib/Transforms/InstCombine/InstructionCombining.cpp @@ -1294,7 +1294,7 @@ auto *Phi0 = dyn_cast(BO.getOperand(0)); auto *Phi1 = dyn_cast(BO.getOperand(1)); if (!Phi0 || !Phi1 || !Phi0->hasOneUse() || !Phi1->hasOneUse() || - Phi0->getNumOperands() != 2 || Phi1->getNumOperands() != 2) + Phi0->getNumOperands() != Phi1->getNumOperands()) return nullptr; // TODO: Remove the restriction for binop being in the same block as the phis. @@ -1302,6 +1302,51 @@ BO.getParent() != Phi1->getParent()) return nullptr; + // Fold if there is at least one specific constant value in phi0 or phi1's + // incoming values that comes from the same block and this specific constant + // value can be used to do optimization for specific binary operator. + // For example: + // %phi0 = phi i32 [0, %bb0], [%i, %bb1] + // %phi1 = phi i32 [%j, %bb0], [0, %bb1] + // %add = add i32 %phi0, %phi1 + // ==> + // %add = phi i32 [%j, %bb0], [%i, %bb1] + Constant *C = ConstantExpr::getBinOpIdentity(BO.getOpcode(), BO.getType(), + /*AllowRHSConstant*/ false); + if (C) { + SmallVector NewIncomingValues; + auto CanFoldIncomingValuePair = [&](std::tuple T) { + auto &Phi0Use = std::get<0>(T); + auto &Phi1Use = std::get<1>(T); + if (Phi0->getIncomingBlock(Phi0Use) != Phi1->getIncomingBlock(Phi1Use)) + return false; + Value *Phi0UseV = Phi0Use.get(); + Value *Phi1UseV = Phi1Use.get(); + if (Phi0UseV == C) + NewIncomingValues.push_back(Phi1UseV); + else if (Phi1UseV == C) + NewIncomingValues.push_back(Phi0UseV); + else + return false; + return true; + }; + + if (all_of(zip(Phi0->operands(), Phi1->operands()), + CanFoldIncomingValuePair)) { + PHINode *NewPhi = + PHINode::Create(Phi0->getType(), Phi0->getNumOperands()); + assert(NewIncomingValues.size() == Phi0->getNumOperands() && + "The number of collected incoming values should equal the number " + "of the original PHINode operands!"); + for (unsigned I = 0; I < Phi0->getNumOperands(); I++) + NewPhi->addIncoming(NewIncomingValues[I], Phi0->getIncomingBlock(I)); + return NewPhi; + } + } + + if (Phi0->getNumOperands() != 2 || Phi1->getNumOperands() != 2) + return nullptr; + // Match a pair of incoming constants for one of the predecessor blocks. BasicBlock *ConstBB, *OtherBB; Constant *C0, *C1; diff --git a/llvm/test/Transforms/InstCombine/phi.ll b/llvm/test/Transforms/InstCombine/phi.ll --- a/llvm/test/Transforms/InstCombine/phi.ll +++ b/llvm/test/Transforms/InstCombine/phi.ll @@ -1508,9 +1508,7 @@ ; CHECK: if.then: ; CHECK-NEXT: br label [[IF_END]] ; CHECK: if.end: -; CHECK-NEXT: [[X:%.*]] = phi i32 [ 0, [[IF_THEN]] ], [ [[J:%.*]], [[ENTRY:%.*]] ] -; CHECK-NEXT: [[Y:%.*]] = phi i32 [ [[I:%.*]], [[IF_THEN]] ], [ 0, [[ENTRY]] ] -; CHECK-NEXT: [[ADD:%.*]] = add i32 [[Y]], [[X]] +; CHECK-NEXT: [[ADD:%.*]] = phi i32 [ [[I:%.*]], [[IF_THEN]] ], [ [[J:%.*]], [[ENTRY:%.*]] ] ; CHECK-NEXT: ret i32 [[ADD]] ; entry: @@ -1558,9 +1556,7 @@ ; CHECK: if.then: ; CHECK-NEXT: br label [[IF_END]] ; CHECK: if.end: -; CHECK-NEXT: [[X:%.*]] = phi i32 [ 0, [[IF_THEN]] ], [ [[J:%.*]], [[ENTRY:%.*]] ] -; CHECK-NEXT: [[Y:%.*]] = phi i32 [ [[I:%.*]], [[IF_THEN]] ], [ 0, [[ENTRY]] ] -; CHECK-NEXT: [[ADD:%.*]] = or i32 [[Y]], [[X]] +; CHECK-NEXT: [[ADD:%.*]] = phi i32 [ [[I:%.*]], [[IF_THEN]] ], [ [[J:%.*]], [[ENTRY:%.*]] ] ; CHECK-NEXT: ret i32 [[ADD]] ; entry: @@ -1583,9 +1579,7 @@ ; CHECK: if.then: ; CHECK-NEXT: br label [[IF_END]] ; CHECK: if.end: -; CHECK-NEXT: [[X:%.*]] = phi i32 [ -1, [[IF_THEN]] ], [ [[J:%.*]], [[ENTRY:%.*]] ] -; CHECK-NEXT: [[Y:%.*]] = phi i32 [ [[I:%.*]], [[IF_THEN]] ], [ -1, [[ENTRY]] ] -; CHECK-NEXT: [[ADD:%.*]] = and i32 [[Y]], [[X]] +; CHECK-NEXT: [[ADD:%.*]] = phi i32 [ [[I:%.*]], [[IF_THEN]] ], [ [[J:%.*]], [[ENTRY:%.*]] ] ; CHECK-NEXT: ret i32 [[ADD]] ; entry: @@ -1608,9 +1602,7 @@ ; CHECK: if.then: ; CHECK-NEXT: br label [[IF_END]] ; CHECK: if.end: -; CHECK-NEXT: [[X:%.*]] = phi i32 [ 1, [[IF_THEN]] ], [ [[J:%.*]], [[ENTRY:%.*]] ] -; CHECK-NEXT: [[Y:%.*]] = phi i32 [ [[I:%.*]], [[IF_THEN]] ], [ 1, [[ENTRY]] ] -; CHECK-NEXT: [[ADD:%.*]] = mul i32 [[Y]], [[X]] +; CHECK-NEXT: [[ADD:%.*]] = phi i32 [ [[I:%.*]], [[IF_THEN]] ], [ [[J:%.*]], [[ENTRY:%.*]] ] ; CHECK-NEXT: ret i32 [[ADD]] ; entry: @@ -1633,9 +1625,32 @@ ; CHECK: if.then: ; CHECK-NEXT: br label [[IF_END]] ; CHECK: if.end: +; CHECK-NEXT: [[ADD:%.*]] = phi i32 [ [[I:%.*]], [[IF_THEN]] ], [ [[J:%.*]], [[ENTRY:%.*]] ] +; CHECK-NEXT: ret i32 [[ADD]] +; +entry: + br i1 %c, label %if.then, label %if.end + +if.then: + br label %if.end + +if.end: + %x = phi i32 [ 0, %if.then ], [ %j, %entry ] + %y = phi i32 [ %i, %if.then ], [ 0, %entry ] + %add = xor i32 %y, %x + ret i32 %add +} + +define i32 @sub_two_phi_node_cant_fold(i1 %c, i32 %i, i32 %j) { +; CHECK-LABEL: @sub_two_phi_node_cant_fold( +; CHECK-NEXT: entry: +; CHECK-NEXT: br i1 [[C:%.*]], label [[IF_THEN:%.*]], label [[IF_END:%.*]] +; CHECK: if.then: +; CHECK-NEXT: br label [[IF_END]] +; CHECK: if.end: ; CHECK-NEXT: [[X:%.*]] = phi i32 [ 0, [[IF_THEN]] ], [ [[J:%.*]], [[ENTRY:%.*]] ] ; CHECK-NEXT: [[Y:%.*]] = phi i32 [ [[I:%.*]], [[IF_THEN]] ], [ 0, [[ENTRY]] ] -; CHECK-NEXT: [[ADD:%.*]] = xor i32 [[Y]], [[X]] +; CHECK-NEXT: [[ADD:%.*]] = sub i32 [[Y]], [[X]] ; CHECK-NEXT: ret i32 [[ADD]] ; entry: @@ -1647,6 +1662,6 @@ if.end: %x = phi i32 [ 0, %if.then ], [ %j, %entry ] %y = phi i32 [ %i, %if.then ], [ 0, %entry ] - %add = xor i32 %y, %x + %add = sub i32 %y, %x ret i32 %add }