Skip to content

Commit e4688b9

Browse files
authored
[SimplifyCFG] Avoid increasing too many phi entries when removing empty blocks (#104887)
Now in the simplifycfg and jumpthreading passes, we will remove the empty blocks (blocks only have phis and an unconditional branch). However, in some cases, this will increase size of the IR and slow down the compile of other passes dramatically. For example, we have the following CFG: 1. BB1 has 100 predecessors, and unconditionally branches to BB2 (does not have any other instructions). 2. BB2 has 100 phis. Then in this case, if we remove BB1, for every phi in BB2, we need to increase 99 entries (replace the incoming edge from BB1 with 100 edges from its predecessors). Then in total, we will increase 9900 phi entries, which can slow down the compile time for many other passes. Therefore, in this change, we add a check to see whether removing the empty blocks will increase lots of phi entries. Now, the threshold is 1000 (can be controlled by the command line option `max-phi-entries-increase-after-removing-empty-block`), which means that we will not remove an empty block if it will increase the total number of phi entries by 1000. This threshold is conservative and for most of the cases, we will not have such a large phi. So, this will only be triggered in some unusual IRs.
1 parent ce6c236 commit e4688b9

File tree

2 files changed

+198
-1
lines changed

2 files changed

+198
-1
lines changed

llvm/lib/Transforms/Utils/Local.cpp

+34-1
Original file line numberDiff line numberDiff line change
@@ -112,6 +112,12 @@ static cl::opt<unsigned> PHICSENumPHISmallSize(
112112
"When the basic block contains not more than this number of PHI nodes, "
113113
"perform a (faster!) exhaustive search instead of set-driven one."));
114114

115+
static cl::opt<unsigned> MaxPhiEntriesIncreaseAfterRemovingEmptyBlock(
116+
"max-phi-entries-increase-after-removing-empty-block", cl::init(1000),
117+
cl::Hidden,
118+
cl::desc("Stop removing an empty block if removing it will introduce more "
119+
"than this number of phi entries in its successor"));
120+
115121
// Max recursion depth for collectBitParts used when detecting bswap and
116122
// bitreverse idioms.
117123
static const unsigned BitPartRecursionMaxDepth = 48;
@@ -1047,6 +1053,33 @@ CanRedirectPredsOfEmptyBBToSucc(BasicBlock *BB, BasicBlock *Succ,
10471053
return true;
10481054
}
10491055

1056+
/// Check whether removing \p BB will make the phis in its \p Succ have too
1057+
/// many incoming entries. This function does not check whether \p BB is
1058+
/// foldable or not.
1059+
static bool introduceTooManyPhiEntries(BasicBlock *BB, BasicBlock *Succ) {
1060+
// If BB only has one predecessor, then removing it will not introduce more
1061+
// incoming edges for phis.
1062+
if (BB->hasNPredecessors(1))
1063+
return false;
1064+
unsigned NumPreds = pred_size(BB);
1065+
unsigned NumChangedPhi = 0;
1066+
for (auto &Phi : Succ->phis()) {
1067+
// If the incoming value is a phi and the phi is defined in BB,
1068+
// then removing BB will not increase the total phi entries of the ir.
1069+
if (auto *IncomingPhi = dyn_cast<PHINode>(Phi.getIncomingValueForBlock(BB)))
1070+
if (IncomingPhi->getParent() == BB)
1071+
continue;
1072+
// Otherwise, we need to add entries to the phi
1073+
NumChangedPhi++;
1074+
}
1075+
// For every phi that needs to be changed, (NumPreds - 1) new entries will be
1076+
// added. If the total increase in phi entries exceeds
1077+
// MaxPhiEntriesIncreaseAfterRemovingEmptyBlock, it will be considered as
1078+
// introducing too many new phi entries.
1079+
return (NumPreds - 1) * NumChangedPhi >
1080+
MaxPhiEntriesIncreaseAfterRemovingEmptyBlock;
1081+
}
1082+
10501083
/// Replace a value flowing from a block to a phi with
10511084
/// potentially multiple instances of that value flowing from the
10521085
/// block's predecessors to the phi.
@@ -1146,7 +1179,7 @@ bool llvm::TryToSimplifyUncondBranchFromEmptyBlock(BasicBlock *BB,
11461179
BBKillable ||
11471180
CanRedirectPredsOfEmptyBBToSucc(BB, Succ, BBPreds, SuccPreds, CommonPred);
11481181

1149-
if (!BBKillable && !BBPhisMergeable)
1182+
if ((!BBKillable && !BBPhisMergeable) || introduceTooManyPhiEntries(BB, Succ))
11501183
return false;
11511184

11521185
// Check to see if merging these blocks/phis would cause conflicts for any of
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,164 @@
1+
; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --version 5
2+
; RUN: opt < %s -max-phi-entries-increase-after-removing-empty-block=12 -passes=simplifycfg -S | FileCheck --check-prefixes=CHECK-12 %s
3+
; RUN: opt < %s -max-phi-entries-increase-after-removing-empty-block=11 -passes=simplifycfg -S | FileCheck --check-prefixes=CHECK-11 %s
4+
; RUN: opt < %s -max-phi-entries-increase-after-removing-empty-block=4 -passes=simplifycfg -S | FileCheck --check-prefixes=CHECK-4 %s
5+
;
6+
; This test has the following CFG:
7+
; 1. entry has a switch to 4 blocks: B1 - B4
8+
; 2. For B1 and B2, it branches to B5 and B6
9+
; 3. For B3 and B4, it branches to B5 and B7
10+
; 4. In B5, %val is defined as phi taking values from B1 to B4
11+
; 5. B5, B6, B7 branch to block Merge unconditionally
12+
; 6. Block Merge has 5 phis(%x1 - %x4 and %val_merge).
13+
;
14+
; If we remove B5, %x1 - %x4 will increase the number of phi entries by (4 - 1) * 4 = 12. For %val_merge, since the value taking from B5
15+
; is defined in B5, it will not increase the number of phi entries (it can be considered as move the entries from %val to
16+
; %val_merge). Therefore, removing B5 will increase the number of phi entries by 12 (not (4 - 1) * 5 = 15).
17+
;
18+
; If we remove B6 / B7, it will increase the number of phi entries by (2 - 1) * 5 = 5.
19+
;
20+
; In the first test, max-phi-entries-increase-after-removing-empty-block is set to be 12, then B5 will be removed.
21+
; In the second test, max-phi-entries-increase-after-removing-empty-block is set to be 11, then B5 should not be removed,
22+
; but B6 and B7 can be removed.
23+
; In the third test, max-phi-entries-increase-after-removing-empty-block is set to be 4, then no BB can be removed.
24+
;
25+
define void @foo(i32 %a, i32 %val1, i32 %val2, i32 %val3, i32 %val4) {
26+
; CHECK-12-LABEL: define void @foo(
27+
; CHECK-12-SAME: i32 [[A:%.*]], i32 [[VAL1:%.*]], i32 [[VAL2:%.*]], i32 [[VAL3:%.*]], i32 [[VAL4:%.*]]) {
28+
; CHECK-12-NEXT: [[ENTRY:.*:]]
29+
; CHECK-12-NEXT: switch i32 [[A]], label %[[B1:.*]] [
30+
; CHECK-12-NEXT: i32 4, label %[[B4:.*]]
31+
; CHECK-12-NEXT: i32 2, label %[[B2:.*]]
32+
; CHECK-12-NEXT: i32 3, label %[[B3:.*]]
33+
; CHECK-12-NEXT: ]
34+
; CHECK-12: [[B1]]:
35+
; CHECK-12-NEXT: [[CMP1:%.*]] = icmp eq i32 [[VAL1]], 1
36+
; CHECK-12-NEXT: br i1 [[CMP1]], label %[[B6:.*]], label %[[MERGE:.*]]
37+
; CHECK-12: [[B2]]:
38+
; CHECK-12-NEXT: [[CMP2:%.*]] = icmp eq i32 [[VAL2]], 2
39+
; CHECK-12-NEXT: br i1 [[CMP2]], label %[[B6]], label %[[MERGE]]
40+
; CHECK-12: [[B3]]:
41+
; CHECK-12-NEXT: [[CMP3:%.*]] = icmp eq i32 [[VAL3]], 3
42+
; CHECK-12-NEXT: br i1 [[CMP3]], label %[[B7:.*]], label %[[MERGE]]
43+
; CHECK-12: [[B4]]:
44+
; CHECK-12-NEXT: [[CMP4:%.*]] = icmp eq i32 [[VAL4]], 4
45+
; CHECK-12-NEXT: br i1 [[CMP4]], label %[[B7]], label %[[MERGE]]
46+
; CHECK-12: [[B6]]:
47+
; CHECK-12-NEXT: br label %[[MERGE]]
48+
; CHECK-12: [[B7]]:
49+
; CHECK-12-NEXT: br label %[[MERGE]]
50+
; CHECK-12: [[MERGE]]:
51+
; CHECK-12-NEXT: [[X1:%.*]] = phi i16 [ 0, %[[B6]] ], [ 2, %[[B7]] ], [ 1, %[[B4]] ], [ 1, %[[B3]] ], [ 1, %[[B2]] ], [ 1, %[[B1]] ]
52+
; CHECK-12-NEXT: [[X2:%.*]] = phi i16 [ 0, %[[B6]] ], [ 2, %[[B7]] ], [ 2, %[[B4]] ], [ 2, %[[B3]] ], [ 2, %[[B2]] ], [ 2, %[[B1]] ]
53+
; CHECK-12-NEXT: [[X3:%.*]] = phi i16 [ 0, %[[B6]] ], [ 2, %[[B7]] ], [ 3, %[[B4]] ], [ 3, %[[B3]] ], [ 3, %[[B2]] ], [ 3, %[[B1]] ]
54+
; CHECK-12-NEXT: [[X4:%.*]] = phi i16 [ 0, %[[B6]] ], [ 2, %[[B7]] ], [ 4, %[[B4]] ], [ 4, %[[B3]] ], [ 4, %[[B2]] ], [ 4, %[[B1]] ]
55+
; CHECK-12-NEXT: [[VAL_MERGE:%.*]] = phi i32 [ 0, %[[B6]] ], [ 2, %[[B7]] ], [ [[VAL1]], %[[B1]] ], [ [[VAL2]], %[[B2]] ], [ [[VAL3]], %[[B3]] ], [ [[VAL4]], %[[B4]] ]
56+
; CHECK-12-NEXT: ret void
57+
;
58+
; CHECK-11-LABEL: define void @foo(
59+
; CHECK-11-SAME: i32 [[A:%.*]], i32 [[VAL1:%.*]], i32 [[VAL2:%.*]], i32 [[VAL3:%.*]], i32 [[VAL4:%.*]]) {
60+
; CHECK-11-NEXT: [[ENTRY:.*:]]
61+
; CHECK-11-NEXT: switch i32 [[A]], label %[[B1:.*]] [
62+
; CHECK-11-NEXT: i32 4, label %[[B4:.*]]
63+
; CHECK-11-NEXT: i32 2, label %[[B2:.*]]
64+
; CHECK-11-NEXT: i32 3, label %[[B3:.*]]
65+
; CHECK-11-NEXT: ]
66+
; CHECK-11: [[B1]]:
67+
; CHECK-11-NEXT: [[CMP1:%.*]] = icmp eq i32 [[VAL1]], 1
68+
; CHECK-11-NEXT: br i1 [[CMP1]], label %[[MERGE:.*]], label %[[B5:.*]]
69+
; CHECK-11: [[B2]]:
70+
; CHECK-11-NEXT: [[CMP2:%.*]] = icmp eq i32 [[VAL2]], 2
71+
; CHECK-11-NEXT: br i1 [[CMP2]], label %[[MERGE]], label %[[B5]]
72+
; CHECK-11: [[B3]]:
73+
; CHECK-11-NEXT: [[CMP3:%.*]] = icmp eq i32 [[VAL3]], 3
74+
; CHECK-11-NEXT: br i1 [[CMP3]], label %[[MERGE]], label %[[B5]]
75+
; CHECK-11: [[B4]]:
76+
; CHECK-11-NEXT: [[CMP4:%.*]] = icmp eq i32 [[VAL4]], 4
77+
; CHECK-11-NEXT: br i1 [[CMP4]], label %[[MERGE]], label %[[B5]]
78+
; CHECK-11: [[B5]]:
79+
; CHECK-11-NEXT: [[VAL:%.*]] = phi i32 [ [[VAL1]], %[[B1]] ], [ [[VAL2]], %[[B2]] ], [ [[VAL3]], %[[B3]] ], [ [[VAL4]], %[[B4]] ]
80+
; CHECK-11-NEXT: br label %[[MERGE]]
81+
; CHECK-11: [[MERGE]]:
82+
; CHECK-11-NEXT: [[X1:%.*]] = phi i16 [ 1, %[[B5]] ], [ 0, %[[B2]] ], [ 0, %[[B1]] ], [ 2, %[[B4]] ], [ 2, %[[B3]] ]
83+
; CHECK-11-NEXT: [[X2:%.*]] = phi i16 [ 2, %[[B5]] ], [ 0, %[[B2]] ], [ 0, %[[B1]] ], [ 2, %[[B4]] ], [ 2, %[[B3]] ]
84+
; CHECK-11-NEXT: [[X3:%.*]] = phi i16 [ 3, %[[B5]] ], [ 0, %[[B2]] ], [ 0, %[[B1]] ], [ 2, %[[B4]] ], [ 2, %[[B3]] ]
85+
; CHECK-11-NEXT: [[X4:%.*]] = phi i16 [ 4, %[[B5]] ], [ 0, %[[B2]] ], [ 0, %[[B1]] ], [ 2, %[[B4]] ], [ 2, %[[B3]] ]
86+
; CHECK-11-NEXT: [[VAL_MERGE:%.*]] = phi i32 [ [[VAL]], %[[B5]] ], [ 0, %[[B2]] ], [ 0, %[[B1]] ], [ 2, %[[B4]] ], [ 2, %[[B3]] ]
87+
; CHECK-11-NEXT: ret void
88+
;
89+
; CHECK-4-LABEL: define void @foo(
90+
; CHECK-4-SAME: i32 [[A:%.*]], i32 [[VAL1:%.*]], i32 [[VAL2:%.*]], i32 [[VAL3:%.*]], i32 [[VAL4:%.*]]) {
91+
; CHECK-4-NEXT: [[ENTRY:.*:]]
92+
; CHECK-4-NEXT: switch i32 [[A]], label %[[B1:.*]] [
93+
; CHECK-4-NEXT: i32 4, label %[[B4:.*]]
94+
; CHECK-4-NEXT: i32 2, label %[[B2:.*]]
95+
; CHECK-4-NEXT: i32 3, label %[[B3:.*]]
96+
; CHECK-4-NEXT: ]
97+
; CHECK-4: [[B1]]:
98+
; CHECK-4-NEXT: [[CMP1:%.*]] = icmp eq i32 [[VAL1]], 1
99+
; CHECK-4-NEXT: br i1 [[CMP1]], label %[[B6:.*]], label %[[B5:.*]]
100+
; CHECK-4: [[B2]]:
101+
; CHECK-4-NEXT: [[CMP2:%.*]] = icmp eq i32 [[VAL2]], 2
102+
; CHECK-4-NEXT: br i1 [[CMP2]], label %[[B6]], label %[[B5]]
103+
; CHECK-4: [[B3]]:
104+
; CHECK-4-NEXT: [[CMP3:%.*]] = icmp eq i32 [[VAL3]], 3
105+
; CHECK-4-NEXT: br i1 [[CMP3]], label %[[B7:.*]], label %[[B5]]
106+
; CHECK-4: [[B4]]:
107+
; CHECK-4-NEXT: [[CMP4:%.*]] = icmp eq i32 [[VAL4]], 4
108+
; CHECK-4-NEXT: br i1 [[CMP4]], label %[[B7]], label %[[B5]]
109+
; CHECK-4: [[B5]]:
110+
; CHECK-4-NEXT: [[VAL:%.*]] = phi i32 [ [[VAL1]], %[[B1]] ], [ [[VAL2]], %[[B2]] ], [ [[VAL3]], %[[B3]] ], [ [[VAL4]], %[[B4]] ]
111+
; CHECK-4-NEXT: br label %[[MERGE:.*]]
112+
; CHECK-4: [[B6]]:
113+
; CHECK-4-NEXT: br label %[[MERGE]]
114+
; CHECK-4: [[B7]]:
115+
; CHECK-4-NEXT: br label %[[MERGE]]
116+
; CHECK-4: [[MERGE]]:
117+
; CHECK-4-NEXT: [[X1:%.*]] = phi i16 [ 1, %[[B5]] ], [ 0, %[[B6]] ], [ 2, %[[B7]] ]
118+
; CHECK-4-NEXT: [[X2:%.*]] = phi i16 [ 2, %[[B5]] ], [ 0, %[[B6]] ], [ 2, %[[B7]] ]
119+
; CHECK-4-NEXT: [[X3:%.*]] = phi i16 [ 3, %[[B5]] ], [ 0, %[[B6]] ], [ 2, %[[B7]] ]
120+
; CHECK-4-NEXT: [[X4:%.*]] = phi i16 [ 4, %[[B5]] ], [ 0, %[[B6]] ], [ 2, %[[B7]] ]
121+
; CHECK-4-NEXT: [[VAL_MERGE:%.*]] = phi i32 [ [[VAL]], %[[B5]] ], [ 0, %[[B6]] ], [ 2, %[[B7]] ]
122+
; CHECK-4-NEXT: ret void
123+
;
124+
entry:
125+
switch i32 %a, label %B1 [
126+
i32 4, label %B4
127+
i32 2, label %B2
128+
i32 3, label %B3
129+
]
130+
131+
B1: ; preds = %entry
132+
%cmp1 = icmp eq i32 %val1, 1
133+
br i1 %cmp1, label %B6, label %B5
134+
135+
B2: ; preds = %entry
136+
%cmp2 = icmp eq i32 %val2, 2
137+
br i1 %cmp2, label %B6, label %B5
138+
139+
B3: ; preds = %entry
140+
%cmp3 = icmp eq i32 %val3, 3
141+
br i1 %cmp3, label %B7, label %B5
142+
143+
B4: ; preds = %entry
144+
%cmp4 = icmp eq i32 %val4, 4
145+
br i1 %cmp4, label %B7, label %B5
146+
147+
B5: ; preds = %B4, %B3, %B2, %B1
148+
%val = phi i32 [ %val1, %B1 ], [ %val2, %B2 ], [ %val3, %B3 ], [ %val4, %B4 ]
149+
br label %Merge
150+
151+
B6: ; preds = %B2, %B1
152+
br label %Merge
153+
154+
B7: ; preds = %B4, %B3
155+
br label %Merge
156+
157+
Merge: ; preds = %B7, %B6, %B5
158+
%x1 = phi i16 [ 1, %B5 ], [ 0, %B6 ], [ 2, %B7 ]
159+
%x2 = phi i16 [ 2, %B5 ], [ 0, %B6 ], [ 2, %B7 ]
160+
%x3 = phi i16 [ 3, %B5 ], [ 0, %B6 ], [ 2, %B7 ]
161+
%x4 = phi i16 [ 4, %B5 ], [ 0, %B6 ], [ 2, %B7 ]
162+
%val_merge = phi i32 [ %val, %B5 ], [ 0, %B6 ], [ 2, %B7 ]
163+
ret void
164+
}

0 commit comments

Comments
 (0)