Skip to content

Commit

Permalink
[SimplifyCFG] Hoist common instructions on Switch.
Browse files Browse the repository at this point in the history
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
  • Loading branch information
DianQK committed Sep 19, 2023
1 parent 40b0ab2 commit 96ea48f
Show file tree
Hide file tree
Showing 7 changed files with 927 additions and 317 deletions.
370 changes: 224 additions & 146 deletions llvm/lib/Transforms/Utils/SimplifyCFG.cpp

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion llvm/test/CodeGen/AArch64/patchable-function-entry-bti.ll
Original file line number Diff line number Diff line change
Expand Up @@ -70,7 +70,7 @@ entry:
i64 4, label %sw.bb4
]
sw.bb0:
call void asm sideeffect "", ""()
call void asm sideeffect "nop", ""()
ret void
sw.bb1:
call void asm sideeffect "", ""()
Expand Down
16 changes: 2 additions & 14 deletions llvm/test/Transforms/SimplifyCFG/HoistCode.ll
Original file line number Diff line number Diff line change
Expand Up @@ -19,21 +19,9 @@ F: ; preds = %0

define void @foo_switch(i64 %C, ptr %P) {
; CHECK-LABEL: @foo_switch(
; CHECK-NEXT: switch i64 [[C:%.*]], label [[BB0:%.*]] [
; CHECK-NEXT: i64 1, label [[BB1:%.*]]
; CHECK-NEXT: i64 2, label [[BB2:%.*]]
; CHECK-NEXT: ]
; CHECK: common.ret:
; CHECK-NEXT: ret void
; CHECK: bb0:
; CHECK-NEXT: common.ret:
; CHECK-NEXT: store i32 7, ptr [[P:%.*]], align 4
; CHECK-NEXT: br label [[COMMON_RET:%.*]]
; CHECK: bb1:
; CHECK-NEXT: store i32 7, ptr [[P]], align 4
; CHECK-NEXT: br label [[COMMON_RET]]
; CHECK: bb2:
; CHECK-NEXT: store i32 7, ptr [[P]], align 4
; CHECK-NEXT: br label [[COMMON_RET]]
; CHECK-NEXT: ret void
;
switch i64 %C, label %bb0 [
i64 1, label %bb1
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,25 +4,8 @@
define i1 @common_instr_with_unreachable(i64 %a, i64 %b, i64 %c) {
; CHECK-LABEL: @common_instr_with_unreachable(
; CHECK-NEXT: start:
; CHECK-NEXT: switch i64 [[A:%.*]], label [[UNREACHABLE:%.*]] [
; CHECK-NEXT: i64 0, label [[BB0:%.*]]
; CHECK-NEXT: i64 1, label [[BB1:%.*]]
; CHECK-NEXT: i64 2, label [[BB2:%.*]]
; CHECK-NEXT: ]
; CHECK: unreachable:
; CHECK-NEXT: unreachable
; CHECK: bb0:
; CHECK-NEXT: [[TMP0:%.*]] = icmp eq i64 [[B:%.*]], [[C:%.*]]
; CHECK-NEXT: br label [[EXIT:%.*]]
; CHECK: bb1:
; CHECK-NEXT: [[TMP1:%.*]] = icmp eq i64 [[B]], [[C]]
; CHECK-NEXT: br label [[EXIT]]
; CHECK: bb2:
; CHECK-NEXT: [[TMP2:%.*]] = icmp eq i64 [[B]], [[C]]
; CHECK-NEXT: br label [[EXIT]]
; CHECK: exit:
; CHECK-NEXT: [[RESULT:%.*]] = phi i1 [ [[TMP0]], [[BB0]] ], [ [[TMP1]], [[BB1]] ], [ [[TMP2]], [[BB2]] ]
; CHECK-NEXT: ret i1 [[RESULT]]
; CHECK-NEXT: ret i1 [[TMP0]]
;
start:
switch i64 %a, label %unreachable [
Expand Down Expand Up @@ -54,43 +37,90 @@ exit: ; preds = %bb2, %bb1, %bb0
define i1 @common_instr_with_unreachable_2(i64 %a, i64 %b, i64 %c) {
; CHECK-LABEL: @common_instr_with_unreachable_2(
; CHECK-NEXT: start:
; CHECK-NEXT: switch i64 [[A:%.*]], label [[BB1:%.*]] [
; CHECK-NEXT: [[TMP0:%.*]] = icmp eq i64 [[B:%.*]], [[C:%.*]]
; CHECK-NEXT: ret i1 [[TMP0]]
;
start:
switch i64 %a, label %bb1 [
i64 0, label %bb0
i64 1, label %unreachable
i64 2, label %bb2
]

unreachable:
unreachable

bb0: ; preds = %start
%0 = icmp eq i64 %b, %c
br label %exit

bb1: ; preds = %start
%1 = icmp eq i64 %b, %c
br label %exit

bb2: ; preds = %start
%2 = icmp eq i64 %b, %c
br label %exit

exit: ; preds = %bb2, %bb1, %bb0
%result = phi i1 [ %0, %bb0 ], [ %1, %bb1 ], [ %2, %bb2 ]
ret i1 %result
}

declare void @no_return()
declare void @foo()

define i1 @not_only_unreachable(i64 %a, i64 %b, i64 %c) {
; CHECK-LABEL: @not_only_unreachable(
; CHECK-NEXT: start:
; CHECK-NEXT: switch i64 [[A:%.*]], label [[UNREACHABLE:%.*]] [
; CHECK-NEXT: i64 0, label [[BB0:%.*]]
; CHECK-NEXT: i64 1, label [[BB1:%.*]]
; CHECK-NEXT: i64 2, label [[BB2:%.*]]
; CHECK-NEXT: ]
; CHECK: unreachable:
; CHECK-NEXT: call void @no_return()
; CHECK-NEXT: unreachable
; CHECK: bb0:
; CHECK-NEXT: [[TMP0:%.*]] = icmp eq i64 [[B:%.*]], [[C:%.*]]
; CHECK-NEXT: call void @foo()
; CHECK-NEXT: br label [[EXIT:%.*]]
; CHECK: bb1:
; CHECK-NEXT: [[TMP1:%.*]] = icmp eq i64 [[B]], [[C]]
; CHECK-NEXT: call void @foo()
; CHECK-NEXT: br label [[EXIT]]
; CHECK: bb2:
; CHECK-NEXT: [[TMP2:%.*]] = icmp eq i64 [[B]], [[C]]
; CHECK-NEXT: call void @foo()
; CHECK-NEXT: br label [[EXIT]]
; CHECK: exit:
; CHECK-NEXT: [[RESULT:%.*]] = phi i1 [ [[TMP0]], [[BB0]] ], [ [[TMP1]], [[BB1]] ], [ [[TMP2]], [[BB2]] ]
; CHECK-NEXT: ret i1 [[RESULT]]
;
start:
switch i64 %a, label %bb1 [
switch i64 %a, label %unreachable [
i64 0, label %bb0
i64 1, label %unreachable
i64 1, label %bb1
i64 2, label %bb2
]

unreachable:
call void @no_return()
unreachable

bb0: ; preds = %start
%0 = icmp eq i64 %b, %c
call void @foo()
br label %exit

bb1: ; preds = %start
%1 = icmp eq i64 %b, %c
call void @foo()
br label %exit

bb2: ; preds = %start
%2 = icmp eq i64 %b, %c
call void @foo()
br label %exit

exit: ; preds = %bb2, %bb1, %bb0
Expand Down
66 changes: 33 additions & 33 deletions llvm/test/Transforms/SimplifyCFG/hoist-common-code.ll
Original file line number Diff line number Diff line change
Expand Up @@ -26,27 +26,11 @@ F: ; preds = %0

define void @test_switch(i64 %i, ptr %Q) {
; CHECK-LABEL: @test_switch(
; CHECK-NEXT: switch i64 [[I:%.*]], label [[BB0:%.*]] [
; CHECK-NEXT: i64 1, label [[BB1:%.*]]
; CHECK-NEXT: i64 2, label [[BB2:%.*]]
; CHECK-NEXT: ]
; CHECK: common.ret:
; CHECK-NEXT: ret void
; CHECK: bb0:
; CHECK-NEXT: common.ret:
; CHECK-NEXT: store i32 1, ptr [[Q:%.*]], align 4
; CHECK-NEXT: [[A:%.*]] = load i32, ptr [[Q]], align 4
; CHECK-NEXT: call void @bar(i32 [[A]])
; CHECK-NEXT: br label [[COMMON_RET:%.*]]
; CHECK: bb1:
; CHECK-NEXT: store i32 1, ptr [[Q]], align 4
; CHECK-NEXT: [[B:%.*]] = load i32, ptr [[Q]], align 4
; CHECK-NEXT: call void @bar(i32 [[B]])
; CHECK-NEXT: br label [[COMMON_RET]]
; CHECK: bb2:
; CHECK-NEXT: store i32 1, ptr [[Q]], align 4
; CHECK-NEXT: [[C:%.*]] = load i32, ptr [[Q]], align 4
; CHECK-NEXT: call void @bar(i32 [[C]])
; CHECK-NEXT: br label [[COMMON_RET]]
; CHECK-NEXT: ret void
;
switch i64 %i, label %bb0 [
i64 1, label %bb1
Expand All @@ -69,25 +53,41 @@ bb2: ; preds = %0
ret void
}

define i1 @common_instr_on_switch(i64 %a, i64 %b, i64 %c) unnamed_addr {
; CHECK-LABEL: @common_instr_on_switch(
; CHECK-NEXT: start:
; CHECK-NEXT: switch i64 [[A:%.*]], label [[BB0:%.*]] [
; We ensure that we examine all instructions during each iteration to confirm the presence of a terminating one.
define void @test_switch_reach_terminator(i64 %i, ptr %p) {
; CHECK-LABEL: @test_switch_reach_terminator(
; CHECK-NEXT: switch i64 [[I:%.*]], label [[BB0:%.*]] [
; CHECK-NEXT: i64 1, label [[BB1:%.*]]
; CHECK-NEXT: i64 2, label [[BB2:%.*]]
; CHECK-NEXT: i64 2, label [[COMMON_RET:%.*]]
; CHECK-NEXT: ]
; CHECK: common.ret:
; CHECK-NEXT: ret void
; CHECK: bb0:
; CHECK-NEXT: [[TMP0:%.*]] = icmp eq i64 [[B:%.*]], [[C:%.*]]
; CHECK-NEXT: br label [[EXIT:%.*]]
; CHECK-NEXT: store i32 1, ptr [[P:%.*]], align 4
; CHECK-NEXT: br label [[COMMON_RET]]
; CHECK: bb1:
; CHECK-NEXT: [[TMP1:%.*]] = icmp eq i64 [[B]], [[C]]
; CHECK-NEXT: br label [[EXIT]]
; CHECK: bb2:
; CHECK-NEXT: [[TMP2:%.*]] = icmp eq i64 [[B]], [[C]]
; CHECK-NEXT: br label [[EXIT]]
; CHECK: exit:
; CHECK-NEXT: [[RESULT:%.*]] = phi i1 [ [[TMP0]], [[BB0]] ], [ [[TMP1]], [[BB1]] ], [ [[TMP2]], [[BB2]] ]
; CHECK-NEXT: ret i1 [[RESULT]]
; CHECK-NEXT: store i32 2, ptr [[P]], align 4
; CHECK-NEXT: br label [[COMMON_RET]]
;
switch i64 %i, label %bb0 [
i64 1, label %bb1
i64 2, label %bb2
]
bb0: ; preds = %0
store i32 1, ptr %p
ret void
bb1: ; preds = %0
store i32 2, ptr %p
ret void
bb2: ; preds = %0
ret void
}

define i1 @common_instr_on_switch(i64 %a, i64 %b, i64 %c) unnamed_addr {
; CHECK-LABEL: @common_instr_on_switch(
; CHECK-NEXT: start:
; CHECK-NEXT: [[TMP0:%.*]] = icmp eq i64 [[B:%.*]], [[C:%.*]]
; CHECK-NEXT: ret i1 [[TMP0]]
;
start:
switch i64 %a, label %bb0 [
Expand Down

0 comments on commit 96ea48f

Please sign in to comment.