Chengjun e4688b98cd
[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.
2024-09-25 12:41:13 +02:00

165 lines
8.5 KiB
LLVM

; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --version 5
; RUN: opt < %s -max-phi-entries-increase-after-removing-empty-block=12 -passes=simplifycfg -S | FileCheck --check-prefixes=CHECK-12 %s
; RUN: opt < %s -max-phi-entries-increase-after-removing-empty-block=11 -passes=simplifycfg -S | FileCheck --check-prefixes=CHECK-11 %s
; RUN: opt < %s -max-phi-entries-increase-after-removing-empty-block=4 -passes=simplifycfg -S | FileCheck --check-prefixes=CHECK-4 %s
;
; This test has the following CFG:
; 1. entry has a switch to 4 blocks: B1 - B4
; 2. For B1 and B2, it branches to B5 and B6
; 3. For B3 and B4, it branches to B5 and B7
; 4. In B5, %val is defined as phi taking values from B1 to B4
; 5. B5, B6, B7 branch to block Merge unconditionally
; 6. Block Merge has 5 phis(%x1 - %x4 and %val_merge).
;
; 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
; is defined in B5, it will not increase the number of phi entries (it can be considered as move the entries from %val to
; %val_merge). Therefore, removing B5 will increase the number of phi entries by 12 (not (4 - 1) * 5 = 15).
;
; If we remove B6 / B7, it will increase the number of phi entries by (2 - 1) * 5 = 5.
;
; In the first test, max-phi-entries-increase-after-removing-empty-block is set to be 12, then B5 will be removed.
; In the second test, max-phi-entries-increase-after-removing-empty-block is set to be 11, then B5 should not be removed,
; but B6 and B7 can be removed.
; In the third test, max-phi-entries-increase-after-removing-empty-block is set to be 4, then no BB can be removed.
;
define void @foo(i32 %a, i32 %val1, i32 %val2, i32 %val3, i32 %val4) {
; CHECK-12-LABEL: define void @foo(
; CHECK-12-SAME: i32 [[A:%.*]], i32 [[VAL1:%.*]], i32 [[VAL2:%.*]], i32 [[VAL3:%.*]], i32 [[VAL4:%.*]]) {
; CHECK-12-NEXT: [[ENTRY:.*:]]
; CHECK-12-NEXT: switch i32 [[A]], label %[[B1:.*]] [
; CHECK-12-NEXT: i32 4, label %[[B4:.*]]
; CHECK-12-NEXT: i32 2, label %[[B2:.*]]
; CHECK-12-NEXT: i32 3, label %[[B3:.*]]
; CHECK-12-NEXT: ]
; CHECK-12: [[B1]]:
; CHECK-12-NEXT: [[CMP1:%.*]] = icmp eq i32 [[VAL1]], 1
; CHECK-12-NEXT: br i1 [[CMP1]], label %[[B6:.*]], label %[[MERGE:.*]]
; CHECK-12: [[B2]]:
; CHECK-12-NEXT: [[CMP2:%.*]] = icmp eq i32 [[VAL2]], 2
; CHECK-12-NEXT: br i1 [[CMP2]], label %[[B6]], label %[[MERGE]]
; CHECK-12: [[B3]]:
; CHECK-12-NEXT: [[CMP3:%.*]] = icmp eq i32 [[VAL3]], 3
; CHECK-12-NEXT: br i1 [[CMP3]], label %[[B7:.*]], label %[[MERGE]]
; CHECK-12: [[B4]]:
; CHECK-12-NEXT: [[CMP4:%.*]] = icmp eq i32 [[VAL4]], 4
; CHECK-12-NEXT: br i1 [[CMP4]], label %[[B7]], label %[[MERGE]]
; CHECK-12: [[B6]]:
; CHECK-12-NEXT: br label %[[MERGE]]
; CHECK-12: [[B7]]:
; CHECK-12-NEXT: br label %[[MERGE]]
; CHECK-12: [[MERGE]]:
; CHECK-12-NEXT: [[X1:%.*]] = phi i16 [ 0, %[[B6]] ], [ 2, %[[B7]] ], [ 1, %[[B4]] ], [ 1, %[[B3]] ], [ 1, %[[B2]] ], [ 1, %[[B1]] ]
; CHECK-12-NEXT: [[X2:%.*]] = phi i16 [ 0, %[[B6]] ], [ 2, %[[B7]] ], [ 2, %[[B4]] ], [ 2, %[[B3]] ], [ 2, %[[B2]] ], [ 2, %[[B1]] ]
; CHECK-12-NEXT: [[X3:%.*]] = phi i16 [ 0, %[[B6]] ], [ 2, %[[B7]] ], [ 3, %[[B4]] ], [ 3, %[[B3]] ], [ 3, %[[B2]] ], [ 3, %[[B1]] ]
; CHECK-12-NEXT: [[X4:%.*]] = phi i16 [ 0, %[[B6]] ], [ 2, %[[B7]] ], [ 4, %[[B4]] ], [ 4, %[[B3]] ], [ 4, %[[B2]] ], [ 4, %[[B1]] ]
; CHECK-12-NEXT: [[VAL_MERGE:%.*]] = phi i32 [ 0, %[[B6]] ], [ 2, %[[B7]] ], [ [[VAL1]], %[[B1]] ], [ [[VAL2]], %[[B2]] ], [ [[VAL3]], %[[B3]] ], [ [[VAL4]], %[[B4]] ]
; CHECK-12-NEXT: ret void
;
; CHECK-11-LABEL: define void @foo(
; CHECK-11-SAME: i32 [[A:%.*]], i32 [[VAL1:%.*]], i32 [[VAL2:%.*]], i32 [[VAL3:%.*]], i32 [[VAL4:%.*]]) {
; CHECK-11-NEXT: [[ENTRY:.*:]]
; CHECK-11-NEXT: switch i32 [[A]], label %[[B1:.*]] [
; CHECK-11-NEXT: i32 4, label %[[B4:.*]]
; CHECK-11-NEXT: i32 2, label %[[B2:.*]]
; CHECK-11-NEXT: i32 3, label %[[B3:.*]]
; CHECK-11-NEXT: ]
; CHECK-11: [[B1]]:
; CHECK-11-NEXT: [[CMP1:%.*]] = icmp eq i32 [[VAL1]], 1
; CHECK-11-NEXT: br i1 [[CMP1]], label %[[MERGE:.*]], label %[[B5:.*]]
; CHECK-11: [[B2]]:
; CHECK-11-NEXT: [[CMP2:%.*]] = icmp eq i32 [[VAL2]], 2
; CHECK-11-NEXT: br i1 [[CMP2]], label %[[MERGE]], label %[[B5]]
; CHECK-11: [[B3]]:
; CHECK-11-NEXT: [[CMP3:%.*]] = icmp eq i32 [[VAL3]], 3
; CHECK-11-NEXT: br i1 [[CMP3]], label %[[MERGE]], label %[[B5]]
; CHECK-11: [[B4]]:
; CHECK-11-NEXT: [[CMP4:%.*]] = icmp eq i32 [[VAL4]], 4
; CHECK-11-NEXT: br i1 [[CMP4]], label %[[MERGE]], label %[[B5]]
; CHECK-11: [[B5]]:
; CHECK-11-NEXT: [[VAL:%.*]] = phi i32 [ [[VAL1]], %[[B1]] ], [ [[VAL2]], %[[B2]] ], [ [[VAL3]], %[[B3]] ], [ [[VAL4]], %[[B4]] ]
; CHECK-11-NEXT: br label %[[MERGE]]
; CHECK-11: [[MERGE]]:
; CHECK-11-NEXT: [[X1:%.*]] = phi i16 [ 1, %[[B5]] ], [ 0, %[[B2]] ], [ 0, %[[B1]] ], [ 2, %[[B4]] ], [ 2, %[[B3]] ]
; CHECK-11-NEXT: [[X2:%.*]] = phi i16 [ 2, %[[B5]] ], [ 0, %[[B2]] ], [ 0, %[[B1]] ], [ 2, %[[B4]] ], [ 2, %[[B3]] ]
; CHECK-11-NEXT: [[X3:%.*]] = phi i16 [ 3, %[[B5]] ], [ 0, %[[B2]] ], [ 0, %[[B1]] ], [ 2, %[[B4]] ], [ 2, %[[B3]] ]
; CHECK-11-NEXT: [[X4:%.*]] = phi i16 [ 4, %[[B5]] ], [ 0, %[[B2]] ], [ 0, %[[B1]] ], [ 2, %[[B4]] ], [ 2, %[[B3]] ]
; CHECK-11-NEXT: [[VAL_MERGE:%.*]] = phi i32 [ [[VAL]], %[[B5]] ], [ 0, %[[B2]] ], [ 0, %[[B1]] ], [ 2, %[[B4]] ], [ 2, %[[B3]] ]
; CHECK-11-NEXT: ret void
;
; CHECK-4-LABEL: define void @foo(
; CHECK-4-SAME: i32 [[A:%.*]], i32 [[VAL1:%.*]], i32 [[VAL2:%.*]], i32 [[VAL3:%.*]], i32 [[VAL4:%.*]]) {
; CHECK-4-NEXT: [[ENTRY:.*:]]
; CHECK-4-NEXT: switch i32 [[A]], label %[[B1:.*]] [
; CHECK-4-NEXT: i32 4, label %[[B4:.*]]
; CHECK-4-NEXT: i32 2, label %[[B2:.*]]
; CHECK-4-NEXT: i32 3, label %[[B3:.*]]
; CHECK-4-NEXT: ]
; CHECK-4: [[B1]]:
; CHECK-4-NEXT: [[CMP1:%.*]] = icmp eq i32 [[VAL1]], 1
; CHECK-4-NEXT: br i1 [[CMP1]], label %[[B6:.*]], label %[[B5:.*]]
; CHECK-4: [[B2]]:
; CHECK-4-NEXT: [[CMP2:%.*]] = icmp eq i32 [[VAL2]], 2
; CHECK-4-NEXT: br i1 [[CMP2]], label %[[B6]], label %[[B5]]
; CHECK-4: [[B3]]:
; CHECK-4-NEXT: [[CMP3:%.*]] = icmp eq i32 [[VAL3]], 3
; CHECK-4-NEXT: br i1 [[CMP3]], label %[[B7:.*]], label %[[B5]]
; CHECK-4: [[B4]]:
; CHECK-4-NEXT: [[CMP4:%.*]] = icmp eq i32 [[VAL4]], 4
; CHECK-4-NEXT: br i1 [[CMP4]], label %[[B7]], label %[[B5]]
; CHECK-4: [[B5]]:
; CHECK-4-NEXT: [[VAL:%.*]] = phi i32 [ [[VAL1]], %[[B1]] ], [ [[VAL2]], %[[B2]] ], [ [[VAL3]], %[[B3]] ], [ [[VAL4]], %[[B4]] ]
; CHECK-4-NEXT: br label %[[MERGE:.*]]
; CHECK-4: [[B6]]:
; CHECK-4-NEXT: br label %[[MERGE]]
; CHECK-4: [[B7]]:
; CHECK-4-NEXT: br label %[[MERGE]]
; CHECK-4: [[MERGE]]:
; CHECK-4-NEXT: [[X1:%.*]] = phi i16 [ 1, %[[B5]] ], [ 0, %[[B6]] ], [ 2, %[[B7]] ]
; CHECK-4-NEXT: [[X2:%.*]] = phi i16 [ 2, %[[B5]] ], [ 0, %[[B6]] ], [ 2, %[[B7]] ]
; CHECK-4-NEXT: [[X3:%.*]] = phi i16 [ 3, %[[B5]] ], [ 0, %[[B6]] ], [ 2, %[[B7]] ]
; CHECK-4-NEXT: [[X4:%.*]] = phi i16 [ 4, %[[B5]] ], [ 0, %[[B6]] ], [ 2, %[[B7]] ]
; CHECK-4-NEXT: [[VAL_MERGE:%.*]] = phi i32 [ [[VAL]], %[[B5]] ], [ 0, %[[B6]] ], [ 2, %[[B7]] ]
; CHECK-4-NEXT: ret void
;
entry:
switch i32 %a, label %B1 [
i32 4, label %B4
i32 2, label %B2
i32 3, label %B3
]
B1: ; preds = %entry
%cmp1 = icmp eq i32 %val1, 1
br i1 %cmp1, label %B6, label %B5
B2: ; preds = %entry
%cmp2 = icmp eq i32 %val2, 2
br i1 %cmp2, label %B6, label %B5
B3: ; preds = %entry
%cmp3 = icmp eq i32 %val3, 3
br i1 %cmp3, label %B7, label %B5
B4: ; preds = %entry
%cmp4 = icmp eq i32 %val4, 4
br i1 %cmp4, label %B7, label %B5
B5: ; preds = %B4, %B3, %B2, %B1
%val = phi i32 [ %val1, %B1 ], [ %val2, %B2 ], [ %val3, %B3 ], [ %val4, %B4 ]
br label %Merge
B6: ; preds = %B2, %B1
br label %Merge
B7: ; preds = %B4, %B3
br label %Merge
Merge: ; preds = %B7, %B6, %B5
%x1 = phi i16 [ 1, %B5 ], [ 0, %B6 ], [ 2, %B7 ]
%x2 = phi i16 [ 2, %B5 ], [ 0, %B6 ], [ 2, %B7 ]
%x3 = phi i16 [ 3, %B5 ], [ 0, %B6 ], [ 2, %B7 ]
%x4 = phi i16 [ 4, %B5 ], [ 0, %B6 ], [ 2, %B7 ]
%val_merge = phi i32 [ %val, %B5 ], [ 0, %B6 ], [ 2, %B7 ]
ret void
}