auto *Phi0 = dyn_cast<PHINode>(BO.getOperand(0));
auto *Phi1 = dyn_cast<PHINode>(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.
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<Value *, 4> NewIncomingValues;
+ auto CanFoldIncomingValuePair = [&](std::tuple<Use &, Use &> 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;
; 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:
; 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:
; 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:
; 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:
; 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:
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
}