Skip to content

Commit

Permalink
Reland "[SimplifyCFG] Hoist common instructions on switch" (#67077)
Browse files Browse the repository at this point in the history
This relands commit 96ea48f.
  • Loading branch information
DianQK committed Sep 22, 2023
1 parent aa70f4d commit d200bd1
Show file tree
Hide file tree
Showing 7 changed files with 961 additions and 317 deletions.
371 changes: 225 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
105 changes: 84 additions & 21 deletions llvm/test/Transforms/SimplifyCFG/hoist-common-code-with-unreachable.ll
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,46 +37,126 @@ 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
}

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
%result = phi i1 [ %0, %bb0 ], [ %1, %bb1 ], [ %2, %bb2 ]
ret i1 %result
}

; If we can hoist a musttail call,
; we can and have to hoist subsequent bitcast and ret instructions.
define ptr @switch_musttail_call(ptr %arg) {
; CHECK-LABEL: @switch_musttail_call(
; CHECK-NEXT: bb:
; CHECK-NEXT: [[P0:%.*]] = musttail call ptr @musttail_call(ptr [[ARG:%.*]])
; CHECK-NEXT: ret ptr [[P0]]
;
bb:
%load = load i16, ptr %arg, align 2
switch i16 %load, label %unreachable [
i16 0, label %bb0
i16 1, label %bb1
i16 2, label %bb2
]

unreachable:
unreachable

bb0:
%p0 = musttail call ptr @musttail_call(ptr %arg)
ret ptr %p0

bb1:
%p1 = musttail call ptr @musttail_call(ptr %arg)
ret ptr %p1

bb2:
%p2 = musttail call ptr @musttail_call(ptr %arg)
ret ptr %p2
}

declare void @no_return()
declare void @foo()
declare ptr @musttail_call(ptr)
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 d200bd1

Please sign in to comment.