Skip to content

Commit

Permalink
[InstCombine] Combine binary operator of two phi node
Browse files Browse the repository at this point in the history
Combine binary operator of two phi node if there is at least one
specific constant value in phi0 and phi1's incoming values for each
same incoming 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]
```

Fixes: #61137

Differential Revision: https://reviews.llvm.org/D145223
  • Loading branch information
luxufan committed Mar 21, 2023
1 parent 9c93e72 commit 6beb371
Show file tree
Hide file tree
Showing 2 changed files with 75 additions and 15 deletions.
47 changes: 46 additions & 1 deletion llvm/lib/Transforms/InstCombine/InstructionCombining.cpp
Expand Up @@ -1294,14 +1294,59 @@ Instruction *InstCombinerImpl::foldBinopWithPhiOperands(BinaryOperator &BO) {
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.
if (BO.getParent() != Phi0->getParent() ||
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;
Expand Down
43 changes: 29 additions & 14 deletions llvm/test/Transforms/InstCombine/phi.ll
Expand Up @@ -1508,9 +1508,7 @@ define i32 @add_two_phi_node_can_fold(i1 %c, i32 %i, i32 %j) {
; 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:
Expand Down Expand Up @@ -1558,9 +1556,7 @@ define i32 @or_two_phi_node_can_fold(i1 %c, i32 %i, i32 %j) {
; 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:
Expand All @@ -1583,9 +1579,7 @@ define i32 @and_two_phi_node_can_fold(i1 %c, i32 %i, i32 %j) {
; 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:
Expand All @@ -1608,9 +1602,7 @@ define i32 @mul_two_phi_node_can_fold(i1 %c, i32 %i, i32 %j) {
; 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:
Expand All @@ -1633,9 +1625,32 @@ define i32 @xor_two_phi_node_can_fold(i1 %c, i32 %i, i32 %j) {
; 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:
Expand All @@ -1647,6 +1662,6 @@ if.then:
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
}

0 comments on commit 6beb371

Please sign in to comment.