Skip to content

Commit 96ea48f

Browse files
committed
[SimplifyCFG] Hoist common instructions on Switch.
Sink common instructions are not always performance friendly. We need to implement hoist common instructions on switch instruction to solve the following problem: ``` define i1 @foo(i64 %a, i64 %b, i64 %c, i64 %d) { start: %test = icmp eq i64 %a, %d br i1 %test, label %switch_bb, label %exit switch_bb: ; preds = %start switch i64 %a, label %bb0 [ i64 1, label %bb1 i64 2, label %bb2 ] bb0: ; preds = %switch_bb %0 = icmp eq i64 %b, %c br label %exit bb1: ; preds = %switch_bb %1 = icmp eq i64 %b, %c br label %exit bb2: ; preds = %switch_bb %2 = icmp eq i64 %b, %c br label %exit exit: ; preds = %bb2, %bb1, %bb0, %start %result = phi i1 [ false, %start ], [ %0, %bb0 ], [ %1, %bb1 ], [ %2, %bb2 ] ret i1 %result } ``` The pre-commit test is D156617. Reviewed By: XChy, nikic Differential Revision: https://reviews.llvm.org/D155711
1 parent 40b0ab2 commit 96ea48f

File tree

7 files changed

+927
-317
lines changed

7 files changed

+927
-317
lines changed

llvm/lib/Transforms/Utils/SimplifyCFG.cpp

Lines changed: 224 additions & 146 deletions
Large diffs are not rendered by default.

llvm/test/CodeGen/AArch64/patchable-function-entry-bti.ll

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -70,7 +70,7 @@ entry:
7070
i64 4, label %sw.bb4
7171
]
7272
sw.bb0:
73-
call void asm sideeffect "", ""()
73+
call void asm sideeffect "nop", ""()
7474
ret void
7575
sw.bb1:
7676
call void asm sideeffect "", ""()

llvm/test/Transforms/SimplifyCFG/HoistCode.ll

Lines changed: 2 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -19,21 +19,9 @@ F: ; preds = %0
1919

2020
define void @foo_switch(i64 %C, ptr %P) {
2121
; CHECK-LABEL: @foo_switch(
22-
; CHECK-NEXT: switch i64 [[C:%.*]], label [[BB0:%.*]] [
23-
; CHECK-NEXT: i64 1, label [[BB1:%.*]]
24-
; CHECK-NEXT: i64 2, label [[BB2:%.*]]
25-
; CHECK-NEXT: ]
26-
; CHECK: common.ret:
27-
; CHECK-NEXT: ret void
28-
; CHECK: bb0:
22+
; CHECK-NEXT: common.ret:
2923
; CHECK-NEXT: store i32 7, ptr [[P:%.*]], align 4
30-
; CHECK-NEXT: br label [[COMMON_RET:%.*]]
31-
; CHECK: bb1:
32-
; CHECK-NEXT: store i32 7, ptr [[P]], align 4
33-
; CHECK-NEXT: br label [[COMMON_RET]]
34-
; CHECK: bb2:
35-
; CHECK-NEXT: store i32 7, ptr [[P]], align 4
36-
; CHECK-NEXT: br label [[COMMON_RET]]
24+
; CHECK-NEXT: ret void
3725
;
3826
switch i64 %C, label %bb0 [
3927
i64 1, label %bb1

llvm/test/Transforms/SimplifyCFG/hoist-common-code-with-unreachable.ll

Lines changed: 51 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -4,25 +4,8 @@
44
define i1 @common_instr_with_unreachable(i64 %a, i64 %b, i64 %c) {
55
; CHECK-LABEL: @common_instr_with_unreachable(
66
; CHECK-NEXT: start:
7-
; CHECK-NEXT: switch i64 [[A:%.*]], label [[UNREACHABLE:%.*]] [
8-
; CHECK-NEXT: i64 0, label [[BB0:%.*]]
9-
; CHECK-NEXT: i64 1, label [[BB1:%.*]]
10-
; CHECK-NEXT: i64 2, label [[BB2:%.*]]
11-
; CHECK-NEXT: ]
12-
; CHECK: unreachable:
13-
; CHECK-NEXT: unreachable
14-
; CHECK: bb0:
157
; CHECK-NEXT: [[TMP0:%.*]] = icmp eq i64 [[B:%.*]], [[C:%.*]]
16-
; CHECK-NEXT: br label [[EXIT:%.*]]
17-
; CHECK: bb1:
18-
; CHECK-NEXT: [[TMP1:%.*]] = icmp eq i64 [[B]], [[C]]
19-
; CHECK-NEXT: br label [[EXIT]]
20-
; CHECK: bb2:
21-
; CHECK-NEXT: [[TMP2:%.*]] = icmp eq i64 [[B]], [[C]]
22-
; CHECK-NEXT: br label [[EXIT]]
23-
; CHECK: exit:
24-
; CHECK-NEXT: [[RESULT:%.*]] = phi i1 [ [[TMP0]], [[BB0]] ], [ [[TMP1]], [[BB1]] ], [ [[TMP2]], [[BB2]] ]
25-
; CHECK-NEXT: ret i1 [[RESULT]]
8+
; CHECK-NEXT: ret i1 [[TMP0]]
269
;
2710
start:
2811
switch i64 %a, label %unreachable [
@@ -54,43 +37,90 @@ exit: ; preds = %bb2, %bb1, %bb0
5437
define i1 @common_instr_with_unreachable_2(i64 %a, i64 %b, i64 %c) {
5538
; CHECK-LABEL: @common_instr_with_unreachable_2(
5639
; CHECK-NEXT: start:
57-
; CHECK-NEXT: switch i64 [[A:%.*]], label [[BB1:%.*]] [
40+
; CHECK-NEXT: [[TMP0:%.*]] = icmp eq i64 [[B:%.*]], [[C:%.*]]
41+
; CHECK-NEXT: ret i1 [[TMP0]]
42+
;
43+
start:
44+
switch i64 %a, label %bb1 [
45+
i64 0, label %bb0
46+
i64 1, label %unreachable
47+
i64 2, label %bb2
48+
]
49+
50+
unreachable:
51+
unreachable
52+
53+
bb0: ; preds = %start
54+
%0 = icmp eq i64 %b, %c
55+
br label %exit
56+
57+
bb1: ; preds = %start
58+
%1 = icmp eq i64 %b, %c
59+
br label %exit
60+
61+
bb2: ; preds = %start
62+
%2 = icmp eq i64 %b, %c
63+
br label %exit
64+
65+
exit: ; preds = %bb2, %bb1, %bb0
66+
%result = phi i1 [ %0, %bb0 ], [ %1, %bb1 ], [ %2, %bb2 ]
67+
ret i1 %result
68+
}
69+
70+
declare void @no_return()
71+
declare void @foo()
72+
73+
define i1 @not_only_unreachable(i64 %a, i64 %b, i64 %c) {
74+
; CHECK-LABEL: @not_only_unreachable(
75+
; CHECK-NEXT: start:
76+
; CHECK-NEXT: switch i64 [[A:%.*]], label [[UNREACHABLE:%.*]] [
5877
; CHECK-NEXT: i64 0, label [[BB0:%.*]]
78+
; CHECK-NEXT: i64 1, label [[BB1:%.*]]
5979
; CHECK-NEXT: i64 2, label [[BB2:%.*]]
6080
; CHECK-NEXT: ]
81+
; CHECK: unreachable:
82+
; CHECK-NEXT: call void @no_return()
83+
; CHECK-NEXT: unreachable
6184
; CHECK: bb0:
6285
; CHECK-NEXT: [[TMP0:%.*]] = icmp eq i64 [[B:%.*]], [[C:%.*]]
86+
; CHECK-NEXT: call void @foo()
6387
; CHECK-NEXT: br label [[EXIT:%.*]]
6488
; CHECK: bb1:
6589
; CHECK-NEXT: [[TMP1:%.*]] = icmp eq i64 [[B]], [[C]]
90+
; CHECK-NEXT: call void @foo()
6691
; CHECK-NEXT: br label [[EXIT]]
6792
; CHECK: bb2:
6893
; CHECK-NEXT: [[TMP2:%.*]] = icmp eq i64 [[B]], [[C]]
94+
; CHECK-NEXT: call void @foo()
6995
; CHECK-NEXT: br label [[EXIT]]
7096
; CHECK: exit:
7197
; CHECK-NEXT: [[RESULT:%.*]] = phi i1 [ [[TMP0]], [[BB0]] ], [ [[TMP1]], [[BB1]] ], [ [[TMP2]], [[BB2]] ]
7298
; CHECK-NEXT: ret i1 [[RESULT]]
7399
;
74100
start:
75-
switch i64 %a, label %bb1 [
101+
switch i64 %a, label %unreachable [
76102
i64 0, label %bb0
77-
i64 1, label %unreachable
103+
i64 1, label %bb1
78104
i64 2, label %bb2
79105
]
80106

81107
unreachable:
108+
call void @no_return()
82109
unreachable
83110

84111
bb0: ; preds = %start
85112
%0 = icmp eq i64 %b, %c
113+
call void @foo()
86114
br label %exit
87115

88116
bb1: ; preds = %start
89117
%1 = icmp eq i64 %b, %c
118+
call void @foo()
90119
br label %exit
91120

92121
bb2: ; preds = %start
93122
%2 = icmp eq i64 %b, %c
123+
call void @foo()
94124
br label %exit
95125

96126
exit: ; preds = %bb2, %bb1, %bb0

llvm/test/Transforms/SimplifyCFG/hoist-common-code.ll

Lines changed: 33 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -26,27 +26,11 @@ F: ; preds = %0
2626

2727
define void @test_switch(i64 %i, ptr %Q) {
2828
; CHECK-LABEL: @test_switch(
29-
; CHECK-NEXT: switch i64 [[I:%.*]], label [[BB0:%.*]] [
30-
; CHECK-NEXT: i64 1, label [[BB1:%.*]]
31-
; CHECK-NEXT: i64 2, label [[BB2:%.*]]
32-
; CHECK-NEXT: ]
33-
; CHECK: common.ret:
34-
; CHECK-NEXT: ret void
35-
; CHECK: bb0:
29+
; CHECK-NEXT: common.ret:
3630
; CHECK-NEXT: store i32 1, ptr [[Q:%.*]], align 4
3731
; CHECK-NEXT: [[A:%.*]] = load i32, ptr [[Q]], align 4
3832
; CHECK-NEXT: call void @bar(i32 [[A]])
39-
; CHECK-NEXT: br label [[COMMON_RET:%.*]]
40-
; CHECK: bb1:
41-
; CHECK-NEXT: store i32 1, ptr [[Q]], align 4
42-
; CHECK-NEXT: [[B:%.*]] = load i32, ptr [[Q]], align 4
43-
; CHECK-NEXT: call void @bar(i32 [[B]])
44-
; CHECK-NEXT: br label [[COMMON_RET]]
45-
; CHECK: bb2:
46-
; CHECK-NEXT: store i32 1, ptr [[Q]], align 4
47-
; CHECK-NEXT: [[C:%.*]] = load i32, ptr [[Q]], align 4
48-
; CHECK-NEXT: call void @bar(i32 [[C]])
49-
; CHECK-NEXT: br label [[COMMON_RET]]
33+
; CHECK-NEXT: ret void
5034
;
5135
switch i64 %i, label %bb0 [
5236
i64 1, label %bb1
@@ -69,25 +53,41 @@ bb2: ; preds = %0
6953
ret void
7054
}
7155

72-
define i1 @common_instr_on_switch(i64 %a, i64 %b, i64 %c) unnamed_addr {
73-
; CHECK-LABEL: @common_instr_on_switch(
74-
; CHECK-NEXT: start:
75-
; CHECK-NEXT: switch i64 [[A:%.*]], label [[BB0:%.*]] [
56+
; We ensure that we examine all instructions during each iteration to confirm the presence of a terminating one.
57+
define void @test_switch_reach_terminator(i64 %i, ptr %p) {
58+
; CHECK-LABEL: @test_switch_reach_terminator(
59+
; CHECK-NEXT: switch i64 [[I:%.*]], label [[BB0:%.*]] [
7660
; CHECK-NEXT: i64 1, label [[BB1:%.*]]
77-
; CHECK-NEXT: i64 2, label [[BB2:%.*]]
61+
; CHECK-NEXT: i64 2, label [[COMMON_RET:%.*]]
7862
; CHECK-NEXT: ]
63+
; CHECK: common.ret:
64+
; CHECK-NEXT: ret void
7965
; CHECK: bb0:
80-
; CHECK-NEXT: [[TMP0:%.*]] = icmp eq i64 [[B:%.*]], [[C:%.*]]
81-
; CHECK-NEXT: br label [[EXIT:%.*]]
66+
; CHECK-NEXT: store i32 1, ptr [[P:%.*]], align 4
67+
; CHECK-NEXT: br label [[COMMON_RET]]
8268
; CHECK: bb1:
83-
; CHECK-NEXT: [[TMP1:%.*]] = icmp eq i64 [[B]], [[C]]
84-
; CHECK-NEXT: br label [[EXIT]]
85-
; CHECK: bb2:
86-
; CHECK-NEXT: [[TMP2:%.*]] = icmp eq i64 [[B]], [[C]]
87-
; CHECK-NEXT: br label [[EXIT]]
88-
; CHECK: exit:
89-
; CHECK-NEXT: [[RESULT:%.*]] = phi i1 [ [[TMP0]], [[BB0]] ], [ [[TMP1]], [[BB1]] ], [ [[TMP2]], [[BB2]] ]
90-
; CHECK-NEXT: ret i1 [[RESULT]]
69+
; CHECK-NEXT: store i32 2, ptr [[P]], align 4
70+
; CHECK-NEXT: br label [[COMMON_RET]]
71+
;
72+
switch i64 %i, label %bb0 [
73+
i64 1, label %bb1
74+
i64 2, label %bb2
75+
]
76+
bb0: ; preds = %0
77+
store i32 1, ptr %p
78+
ret void
79+
bb1: ; preds = %0
80+
store i32 2, ptr %p
81+
ret void
82+
bb2: ; preds = %0
83+
ret void
84+
}
85+
86+
define i1 @common_instr_on_switch(i64 %a, i64 %b, i64 %c) unnamed_addr {
87+
; CHECK-LABEL: @common_instr_on_switch(
88+
; CHECK-NEXT: start:
89+
; CHECK-NEXT: [[TMP0:%.*]] = icmp eq i64 [[B:%.*]], [[C:%.*]]
90+
; CHECK-NEXT: ret i1 [[TMP0]]
9191
;
9292
start:
9393
switch i64 %a, label %bb0 [

0 commit comments

Comments
 (0)