Skip to content

Commit 94a98cf

Browse files
authored
[InstCombine] Remove dead phi web (#108876)
In current visitPHINode function during InstCombine, it can remove dead phi cycles (all phis have one use, which is another phi). However, it cannot deal with the case when the phis form a web (all phis have one or more uses, and all the uses are phi). This change extends the algorithm so that it can also deal with the dead phi web.
1 parent 5a8d2dd commit 94a98cf

File tree

3 files changed

+89
-31
lines changed

3 files changed

+89
-31
lines changed

llvm/lib/Transforms/InstCombine/InstCombineInternal.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -634,6 +634,11 @@ class LLVM_LIBRARY_VISIBILITY InstCombinerImpl final
634634
Instruction *foldPHIArgZextsIntoPHI(PHINode &PN);
635635
Instruction *foldPHIArgIntToPtrToPHI(PHINode &PN);
636636

637+
/// If the phi is within a phi web, which is formed by the def-use chain
638+
/// of phis and all the phis in the web are only used in the other phis.
639+
/// In this case, these phis are dead and we will remove all of them.
640+
bool foldDeadPhiWeb(PHINode &PN);
641+
637642
/// If an integer typed PHI has only one use which is an IntToPtr operation,
638643
/// replace the PHI with an existing pointer typed PHI if it exists. Otherwise
639644
/// insert a new pointer typed PHI and replace the original one.

llvm/lib/Transforms/InstCombine/InstCombinePHI.cpp

Lines changed: 33 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,34 @@ void InstCombinerImpl::PHIArgMergedDebugLoc(Instruction *Inst, PHINode &PN) {
5353
}
5454
}
5555

56+
/// If the phi is within a phi web, which is formed by the def-use chain
57+
/// of phis and all the phis in the web are only used in the other phis.
58+
/// In this case, these phis are dead and we will remove all of them.
59+
bool InstCombinerImpl::foldDeadPhiWeb(PHINode &PN) {
60+
SmallVector<PHINode *, 16> Stack;
61+
SmallPtrSet<PHINode *, 16> Visited;
62+
Stack.push_back(&PN);
63+
while (!Stack.empty()) {
64+
PHINode *Phi = Stack.pop_back_val();
65+
if (!Visited.insert(Phi).second)
66+
continue;
67+
// Early stop if the set of PHIs is large
68+
if (Visited.size() == 16)
69+
return false;
70+
for (User *Use : Phi->users()) {
71+
if (PHINode *PhiUse = dyn_cast<PHINode>(Use))
72+
Stack.push_back(PhiUse);
73+
else
74+
return false;
75+
}
76+
}
77+
for (PHINode *Phi : Visited)
78+
replaceInstUsesWith(*Phi, PoisonValue::get(Phi->getType()));
79+
for (PHINode *Phi : Visited)
80+
eraseInstFromFunction(*Phi);
81+
return true;
82+
}
83+
5684
// Replace Integer typed PHI PN if the PHI's value is used as a pointer value.
5785
// If there is an existing pointer typed PHI that produces the same value as PN,
5886
// replace PN and the IntToPtr operation with it. Otherwise, synthesize a new
@@ -976,26 +1004,6 @@ Instruction *InstCombinerImpl::foldPHIArgOpIntoPHI(PHINode &PN) {
9761004
return NewCI;
9771005
}
9781006

979-
/// Return true if this PHI node is only used by a PHI node cycle that is dead.
980-
static bool isDeadPHICycle(PHINode *PN,
981-
SmallPtrSetImpl<PHINode *> &PotentiallyDeadPHIs) {
982-
if (PN->use_empty()) return true;
983-
if (!PN->hasOneUse()) return false;
984-
985-
// Remember this node, and if we find the cycle, return.
986-
if (!PotentiallyDeadPHIs.insert(PN).second)
987-
return true;
988-
989-
// Don't scan crazily complex things.
990-
if (PotentiallyDeadPHIs.size() == 16)
991-
return false;
992-
993-
if (PHINode *PU = dyn_cast<PHINode>(PN->user_back()))
994-
return isDeadPHICycle(PU, PotentiallyDeadPHIs);
995-
996-
return false;
997-
}
998-
9991007
/// Return true if this phi node is always equal to NonPhiInVal.
10001008
/// This happens with mutually cyclic phi nodes like:
10011009
/// z = some value; x = phi (y, z); y = phi (x, z)
@@ -1474,27 +1482,21 @@ Instruction *InstCombinerImpl::visitPHINode(PHINode &PN) {
14741482
}
14751483
}
14761484

1477-
// If this is a trivial cycle in the PHI node graph, remove it. Basically, if
1478-
// this PHI only has a single use (a PHI), and if that PHI only has one use (a
1479-
// PHI)... break the cycle.
1485+
if (foldDeadPhiWeb(PN))
1486+
return nullptr;
1487+
1488+
// Optimization when the phi only has one use
14801489
if (PN.hasOneUse()) {
14811490
if (foldIntegerTypedPHI(PN))
14821491
return nullptr;
14831492

1484-
Instruction *PHIUser = cast<Instruction>(PN.user_back());
1485-
if (PHINode *PU = dyn_cast<PHINode>(PHIUser)) {
1486-
SmallPtrSet<PHINode*, 16> PotentiallyDeadPHIs;
1487-
PotentiallyDeadPHIs.insert(&PN);
1488-
if (isDeadPHICycle(PU, PotentiallyDeadPHIs))
1489-
return replaceInstUsesWith(PN, PoisonValue::get(PN.getType()));
1490-
}
1491-
14921493
// If this phi has a single use, and if that use just computes a value for
14931494
// the next iteration of a loop, delete the phi. This occurs with unused
14941495
// induction variables, e.g. "for (int j = 0; ; ++j);". Detecting this
14951496
// common case here is good because the only other things that catch this
14961497
// are induction variable analysis (sometimes) and ADCE, which is only run
14971498
// late.
1499+
Instruction *PHIUser = cast<Instruction>(PN.user_back());
14981500
if (PHIUser->hasOneUse() &&
14991501
(isa<BinaryOperator>(PHIUser) || isa<UnaryOperator>(PHIUser) ||
15001502
isa<GetElementPtrInst>(PHIUser)) &&

llvm/test/Transforms/InstCombine/phi.ll

Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2742,3 +2742,54 @@ loop.latch:
27422742
call void @use(i32 %and)
27432743
br label %loop
27442744
}
2745+
2746+
define void @test_dead_phi_web(i64 %index, i1 %cond) {
2747+
; CHECK-LABEL: @test_dead_phi_web(
2748+
; CHECK-NEXT: entry:
2749+
; CHECK-NEXT: br label [[BB0:%.*]]
2750+
; CHECK: BB0:
2751+
; CHECK-NEXT: switch i64 [[INDEX:%.*]], label [[BB4:%.*]] [
2752+
; CHECK-NEXT: i64 0, label [[BB1:%.*]]
2753+
; CHECK-NEXT: i64 1, label [[BB2:%.*]]
2754+
; CHECK-NEXT: i64 2, label [[BB3:%.*]]
2755+
; CHECK-NEXT: ]
2756+
; CHECK: BB1:
2757+
; CHECK-NEXT: br i1 [[COND:%.*]], label [[BB2]], label [[BB4]]
2758+
; CHECK: BB2:
2759+
; CHECK-NEXT: br i1 [[COND]], label [[BB3]], label [[BB4]]
2760+
; CHECK: BB3:
2761+
; CHECK-NEXT: br label [[BB4]]
2762+
; CHECK: BB4:
2763+
; CHECK-NEXT: br i1 [[COND]], label [[BB0]], label [[BB5:%.*]]
2764+
; CHECK: BB5:
2765+
; CHECK-NEXT: ret void
2766+
;
2767+
entry:
2768+
br label %BB0
2769+
2770+
BB0: ; preds = %BB4, %entry
2771+
%a = phi float [ 0.0, %entry ], [ %x, %BB4 ]
2772+
switch i64 %index, label %BB4 [
2773+
i64 0, label %BB1
2774+
i64 1, label %BB2
2775+
i64 2, label %BB3
2776+
]
2777+
2778+
BB1: ; preds = %BB0
2779+
br i1 %cond, label %BB2, label %BB4
2780+
2781+
BB2: ; preds = %BB1, %BB0
2782+
%b = phi float [ 2.0, %BB0 ], [ %a, %BB1 ]
2783+
br i1 %cond, label %BB3, label %BB4
2784+
2785+
BB3: ; preds = %BB2, %BB0
2786+
%c = phi float [ 3.0, %BB0 ], [ %b, %BB2 ]
2787+
br label %BB4
2788+
2789+
BB4: ; preds = %BB3, %BB2, %BB1, %BB0
2790+
%x = phi float [ %a, %BB0 ], [ %a, %BB1 ], [ %b, %BB2 ], [ %c, %BB3 ]
2791+
br i1 %cond, label %BB0, label %BB5
2792+
2793+
BB5: ; preds = %BB4
2794+
ret void
2795+
}

0 commit comments

Comments
 (0)