Skip to content

Commit 6beb371

Browse files
author
luxufan
committed
[InstCombine] Combine binary operator of two phi node
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
1 parent 9c93e72 commit 6beb371

File tree

2 files changed

+75
-15
lines changed

2 files changed

+75
-15
lines changed

llvm/lib/Transforms/InstCombine/InstructionCombining.cpp

Lines changed: 46 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1294,14 +1294,59 @@ Instruction *InstCombinerImpl::foldBinopWithPhiOperands(BinaryOperator &BO) {
12941294
auto *Phi0 = dyn_cast<PHINode>(BO.getOperand(0));
12951295
auto *Phi1 = dyn_cast<PHINode>(BO.getOperand(1));
12961296
if (!Phi0 || !Phi1 || !Phi0->hasOneUse() || !Phi1->hasOneUse() ||
1297-
Phi0->getNumOperands() != 2 || Phi1->getNumOperands() != 2)
1297+
Phi0->getNumOperands() != Phi1->getNumOperands())
12981298
return nullptr;
12991299

13001300
// TODO: Remove the restriction for binop being in the same block as the phis.
13011301
if (BO.getParent() != Phi0->getParent() ||
13021302
BO.getParent() != Phi1->getParent())
13031303
return nullptr;
13041304

1305+
// Fold if there is at least one specific constant value in phi0 or phi1's
1306+
// incoming values that comes from the same block and this specific constant
1307+
// value can be used to do optimization for specific binary operator.
1308+
// For example:
1309+
// %phi0 = phi i32 [0, %bb0], [%i, %bb1]
1310+
// %phi1 = phi i32 [%j, %bb0], [0, %bb1]
1311+
// %add = add i32 %phi0, %phi1
1312+
// ==>
1313+
// %add = phi i32 [%j, %bb0], [%i, %bb1]
1314+
Constant *C = ConstantExpr::getBinOpIdentity(BO.getOpcode(), BO.getType(),
1315+
/*AllowRHSConstant*/ false);
1316+
if (C) {
1317+
SmallVector<Value *, 4> NewIncomingValues;
1318+
auto CanFoldIncomingValuePair = [&](std::tuple<Use &, Use &> T) {
1319+
auto &Phi0Use = std::get<0>(T);
1320+
auto &Phi1Use = std::get<1>(T);
1321+
if (Phi0->getIncomingBlock(Phi0Use) != Phi1->getIncomingBlock(Phi1Use))
1322+
return false;
1323+
Value *Phi0UseV = Phi0Use.get();
1324+
Value *Phi1UseV = Phi1Use.get();
1325+
if (Phi0UseV == C)
1326+
NewIncomingValues.push_back(Phi1UseV);
1327+
else if (Phi1UseV == C)
1328+
NewIncomingValues.push_back(Phi0UseV);
1329+
else
1330+
return false;
1331+
return true;
1332+
};
1333+
1334+
if (all_of(zip(Phi0->operands(), Phi1->operands()),
1335+
CanFoldIncomingValuePair)) {
1336+
PHINode *NewPhi =
1337+
PHINode::Create(Phi0->getType(), Phi0->getNumOperands());
1338+
assert(NewIncomingValues.size() == Phi0->getNumOperands() &&
1339+
"The number of collected incoming values should equal the number "
1340+
"of the original PHINode operands!");
1341+
for (unsigned I = 0; I < Phi0->getNumOperands(); I++)
1342+
NewPhi->addIncoming(NewIncomingValues[I], Phi0->getIncomingBlock(I));
1343+
return NewPhi;
1344+
}
1345+
}
1346+
1347+
if (Phi0->getNumOperands() != 2 || Phi1->getNumOperands() != 2)
1348+
return nullptr;
1349+
13051350
// Match a pair of incoming constants for one of the predecessor blocks.
13061351
BasicBlock *ConstBB, *OtherBB;
13071352
Constant *C0, *C1;

llvm/test/Transforms/InstCombine/phi.ll

Lines changed: 29 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1508,9 +1508,7 @@ define i32 @add_two_phi_node_can_fold(i1 %c, i32 %i, i32 %j) {
15081508
; CHECK: if.then:
15091509
; CHECK-NEXT: br label [[IF_END]]
15101510
; CHECK: if.end:
1511-
; CHECK-NEXT: [[X:%.*]] = phi i32 [ 0, [[IF_THEN]] ], [ [[J:%.*]], [[ENTRY:%.*]] ]
1512-
; CHECK-NEXT: [[Y:%.*]] = phi i32 [ [[I:%.*]], [[IF_THEN]] ], [ 0, [[ENTRY]] ]
1513-
; CHECK-NEXT: [[ADD:%.*]] = add i32 [[Y]], [[X]]
1511+
; CHECK-NEXT: [[ADD:%.*]] = phi i32 [ [[I:%.*]], [[IF_THEN]] ], [ [[J:%.*]], [[ENTRY:%.*]] ]
15141512
; CHECK-NEXT: ret i32 [[ADD]]
15151513
;
15161514
entry:
@@ -1558,9 +1556,7 @@ define i32 @or_two_phi_node_can_fold(i1 %c, i32 %i, i32 %j) {
15581556
; CHECK: if.then:
15591557
; CHECK-NEXT: br label [[IF_END]]
15601558
; CHECK: if.end:
1561-
; CHECK-NEXT: [[X:%.*]] = phi i32 [ 0, [[IF_THEN]] ], [ [[J:%.*]], [[ENTRY:%.*]] ]
1562-
; CHECK-NEXT: [[Y:%.*]] = phi i32 [ [[I:%.*]], [[IF_THEN]] ], [ 0, [[ENTRY]] ]
1563-
; CHECK-NEXT: [[ADD:%.*]] = or i32 [[Y]], [[X]]
1559+
; CHECK-NEXT: [[ADD:%.*]] = phi i32 [ [[I:%.*]], [[IF_THEN]] ], [ [[J:%.*]], [[ENTRY:%.*]] ]
15641560
; CHECK-NEXT: ret i32 [[ADD]]
15651561
;
15661562
entry:
@@ -1583,9 +1579,7 @@ define i32 @and_two_phi_node_can_fold(i1 %c, i32 %i, i32 %j) {
15831579
; CHECK: if.then:
15841580
; CHECK-NEXT: br label [[IF_END]]
15851581
; CHECK: if.end:
1586-
; CHECK-NEXT: [[X:%.*]] = phi i32 [ -1, [[IF_THEN]] ], [ [[J:%.*]], [[ENTRY:%.*]] ]
1587-
; CHECK-NEXT: [[Y:%.*]] = phi i32 [ [[I:%.*]], [[IF_THEN]] ], [ -1, [[ENTRY]] ]
1588-
; CHECK-NEXT: [[ADD:%.*]] = and i32 [[Y]], [[X]]
1582+
; CHECK-NEXT: [[ADD:%.*]] = phi i32 [ [[I:%.*]], [[IF_THEN]] ], [ [[J:%.*]], [[ENTRY:%.*]] ]
15891583
; CHECK-NEXT: ret i32 [[ADD]]
15901584
;
15911585
entry:
@@ -1608,9 +1602,7 @@ define i32 @mul_two_phi_node_can_fold(i1 %c, i32 %i, i32 %j) {
16081602
; CHECK: if.then:
16091603
; CHECK-NEXT: br label [[IF_END]]
16101604
; CHECK: if.end:
1611-
; CHECK-NEXT: [[X:%.*]] = phi i32 [ 1, [[IF_THEN]] ], [ [[J:%.*]], [[ENTRY:%.*]] ]
1612-
; CHECK-NEXT: [[Y:%.*]] = phi i32 [ [[I:%.*]], [[IF_THEN]] ], [ 1, [[ENTRY]] ]
1613-
; CHECK-NEXT: [[ADD:%.*]] = mul i32 [[Y]], [[X]]
1605+
; CHECK-NEXT: [[ADD:%.*]] = phi i32 [ [[I:%.*]], [[IF_THEN]] ], [ [[J:%.*]], [[ENTRY:%.*]] ]
16141606
; CHECK-NEXT: ret i32 [[ADD]]
16151607
;
16161608
entry:
@@ -1633,9 +1625,32 @@ define i32 @xor_two_phi_node_can_fold(i1 %c, i32 %i, i32 %j) {
16331625
; CHECK: if.then:
16341626
; CHECK-NEXT: br label [[IF_END]]
16351627
; CHECK: if.end:
1628+
; CHECK-NEXT: [[ADD:%.*]] = phi i32 [ [[I:%.*]], [[IF_THEN]] ], [ [[J:%.*]], [[ENTRY:%.*]] ]
1629+
; CHECK-NEXT: ret i32 [[ADD]]
1630+
;
1631+
entry:
1632+
br i1 %c, label %if.then, label %if.end
1633+
1634+
if.then:
1635+
br label %if.end
1636+
1637+
if.end:
1638+
%x = phi i32 [ 0, %if.then ], [ %j, %entry ]
1639+
%y = phi i32 [ %i, %if.then ], [ 0, %entry ]
1640+
%add = xor i32 %y, %x
1641+
ret i32 %add
1642+
}
1643+
1644+
define i32 @sub_two_phi_node_cant_fold(i1 %c, i32 %i, i32 %j) {
1645+
; CHECK-LABEL: @sub_two_phi_node_cant_fold(
1646+
; CHECK-NEXT: entry:
1647+
; CHECK-NEXT: br i1 [[C:%.*]], label [[IF_THEN:%.*]], label [[IF_END:%.*]]
1648+
; CHECK: if.then:
1649+
; CHECK-NEXT: br label [[IF_END]]
1650+
; CHECK: if.end:
16361651
; CHECK-NEXT: [[X:%.*]] = phi i32 [ 0, [[IF_THEN]] ], [ [[J:%.*]], [[ENTRY:%.*]] ]
16371652
; CHECK-NEXT: [[Y:%.*]] = phi i32 [ [[I:%.*]], [[IF_THEN]] ], [ 0, [[ENTRY]] ]
1638-
; CHECK-NEXT: [[ADD:%.*]] = xor i32 [[Y]], [[X]]
1653+
; CHECK-NEXT: [[ADD:%.*]] = sub i32 [[Y]], [[X]]
16391654
; CHECK-NEXT: ret i32 [[ADD]]
16401655
;
16411656
entry:
@@ -1647,6 +1662,6 @@ if.then:
16471662
if.end:
16481663
%x = phi i32 [ 0, %if.then ], [ %j, %entry ]
16491664
%y = phi i32 [ %i, %if.then ], [ 0, %entry ]
1650-
%add = xor i32 %y, %x
1665+
%add = sub i32 %y, %x
16511666
ret i32 %add
16521667
}

0 commit comments

Comments
 (0)