[llvm] [SimplifyCFG][Migrated] Transform for redirecting phis between unmergeable BB and SuccBB (PR #67275)

via llvm-commits llvm-commits at lists.llvm.org
Sun Sep 24 19:12:51 PDT 2023


https://github.com/XChy created https://github.com/llvm/llvm-project/pull/67275

This patch extends function TryToSimplifyUncondBranchFromEmptyBlock to handle the similar cases below.

```llvm
define i8 @src(i8 noundef %arg) {
start:
  switch i8 %arg, label %unreachable [
    i8 0, label %case012
    i8 1, label %case1
    i8 2, label %case2
    i8 3, label %end
  ]

unreachable:
  unreachable

case1:
  br label %case012

case2:
  br label %case012

case012:
  %phi1 = phi i8 [ 3, %case2 ], [ 2, %case1 ], [ 1, %start ]
  br label %end

end:
  %phi2 = phi i8 [ %phi1, %case012 ], [ 4, %start ]
  ret i8 %phi2
}
```
The phis here should be merged into one phi, so that we can better optimize it:

```llvm
define i8 @tgt(i8 noundef %arg) {
start:
  switch i8 %arg, label %unreachable [
    i8 0, label %end
    i8 1, label %case1
    i8 2, label %case2
    i8 3, label %case3
  ]

unreachable:
  unreachable

case1:
  br label %end

case2:
  br label %end

case3:
  br label %end

end:
  %phi = phi i8 [ 4, %case3 ], [ 3, %case2 ], [ 2, %case1 ], [ 1, %start ]
  ret i8 %phi
}
```
Proof:
[normal](https://alive2.llvm.org/ce/z/vAWi88)
[multiple stages](https://alive2.llvm.org/ce/z/DDBQqp)
[multiple stages 2](https://alive2.llvm.org/ce/z/nGkeqN)
[multiple phi combinations](https://alive2.llvm.org/ce/z/VQeEdp)

And lookup table optimization should convert it into add %arg 1.
This patch just match similar CFG structure and merge the phis in different cases.

Maybe such transform can be applied to other situations besides switch,
but I'm not sure whether it's better than not merging. Therefore, I only try it in switch,

Related issue:
#63876

[Migrated](https://reviews.llvm.org/D155940)

>From 903f8205205dd13c8a6d412e6e5ee040a576bfc0 Mon Sep 17 00:00:00 2001
From: XChy <xxs_chy at outlook.com>
Date: Sat, 22 Jul 2023 16:21:55 +0800
Subject: [PATCH 1/2] Tests for merging the combination of phis in switch

---
 .../Transforms/SimplifyCFG/branch-fold.ll     |  34 ++
 .../SimplifyCFG/merge-phis-in-switch.ll       | 335 ++++++++++++++++++
 .../Transforms/SimplifyCFG/multiple-phis.ll   | 294 ++++++++++++++-
 3 files changed, 658 insertions(+), 5 deletions(-)
 create mode 100644 llvm/test/Transforms/SimplifyCFG/merge-phis-in-switch.ll

diff --git a/llvm/test/Transforms/SimplifyCFG/branch-fold.ll b/llvm/test/Transforms/SimplifyCFG/branch-fold.ll
index b8b5aaa73cf501c..026891f6f662ef8 100644
--- a/llvm/test/Transforms/SimplifyCFG/branch-fold.ll
+++ b/llvm/test/Transforms/SimplifyCFG/branch-fold.ll
@@ -114,3 +114,37 @@ bb0:
   call void @foo()
   ret void
 }
+
+define i8 @common_pred(i8 noundef %arg, i1 %c1, i1 %c2) {
+; CHECK-LABEL: @common_pred(
+; CHECK-NEXT:  Pred:
+; CHECK-NEXT:    call void @dummy()
+; CHECK-NEXT:    br i1 [[C1:%.*]], label [[COMMONPRED:%.*]], label [[BB:%.*]]
+; CHECK:       CommonPred:
+; CHECK-NEXT:    call void @dummy()
+; CHECK-NEXT:    br i1 [[C2:%.*]], label [[SUCC:%.*]], label [[BB]]
+; CHECK:       BB:
+; CHECK-NEXT:    [[PHI1:%.*]] = phi i8 [ 0, [[PRED:%.*]] ], [ 1, [[COMMONPRED]] ]
+; CHECK-NEXT:    br label [[SUCC]]
+; CHECK:       Succ:
+; CHECK-NEXT:    [[PHI2:%.*]] = phi i8 [ [[PHI1]], [[BB]] ], [ 4, [[COMMONPRED]] ]
+; CHECK-NEXT:    ret i8 [[PHI2]]
+;
+Pred:
+call void @dummy()
+  br i1 %c1, label %CommonPred, label %BB
+
+CommonPred:
+call void @dummy()
+  br i1 %c2, label %Succ, label %BB
+
+BB:
+  %phi1 = phi i8 [ 0, %Pred ], [1, %CommonPred]
+  br label %Succ
+
+Succ:
+  %phi2 = phi i8 [ %phi1, %BB ], [ 4, %CommonPred ]
+  ret i8 %phi2
+}
+
+declare void @dummy()
diff --git a/llvm/test/Transforms/SimplifyCFG/merge-phis-in-switch.ll b/llvm/test/Transforms/SimplifyCFG/merge-phis-in-switch.ll
new file mode 100644
index 000000000000000..e5aefef0271ea6b
--- /dev/null
+++ b/llvm/test/Transforms/SimplifyCFG/merge-phis-in-switch.ll
@@ -0,0 +1,335 @@
+; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --version 3
+; RUN: opt < %s -passes=simplifycfg -simplifycfg-require-and-preserve-domtree=1 -S | FileCheck %s
+
+; Test a bunch of cases where the combination of phis in switch should be merged into one phi
+
+declare void @use(i8)
+
+define i8 @phis_of_switch_minimal(i8 noundef %arg) {
+; CHECK-LABEL: define i8 @phis_of_switch_minimal
+; CHECK-SAME: (i8 noundef [[ARG:%.*]]) {
+; CHECK-NEXT:  start:
+; CHECK-NEXT:    switch i8 [[ARG]], label [[UNREACHABLE:%.*]] [
+; CHECK-NEXT:    i8 0, label [[CASE01:%.*]]
+; CHECK-NEXT:    i8 1, label [[CASE1:%.*]]
+; CHECK-NEXT:    i8 2, label [[END:%.*]]
+; CHECK-NEXT:    ]
+; CHECK:       unreachable:
+; CHECK-NEXT:    unreachable
+; CHECK:       case1:
+; CHECK-NEXT:    br label [[CASE01]]
+; CHECK:       case01:
+; CHECK-NEXT:    [[PHI1:%.*]] = phi i8 [ 2, [[CASE1]] ], [ 1, [[START:%.*]] ]
+; CHECK-NEXT:    br label [[END]]
+; CHECK:       end:
+; CHECK-NEXT:    [[PHI2:%.*]] = phi i8 [ [[PHI1]], [[CASE01]] ], [ 3, [[START]] ]
+; CHECK-NEXT:    ret i8 [[PHI2]]
+;
+start:
+  switch i8 %arg, label %unreachable [
+  i8 0, label %case01
+  i8 1, label %case1
+  i8 2, label %end
+  ]
+unreachable:
+  unreachable
+case1:
+  br label %case01
+
+case01:
+  %phi1 = phi i8 [ 2, %case1 ], [1, %start]
+  br label %end
+
+end:
+  %phi2 = phi i8 [ %phi1, %case01 ], [ 3, %start ]
+  ret i8 %phi2
+}
+
+define i8 @phis_of_switch(i8 noundef %arg) {
+; CHECK-LABEL: define i8 @phis_of_switch
+; CHECK-SAME: (i8 noundef [[ARG:%.*]]) {
+; CHECK-NEXT:  start:
+; CHECK-NEXT:    switch i8 [[ARG]], label [[UNREACHABLE:%.*]] [
+; CHECK-NEXT:    i8 0, label [[CASE012:%.*]]
+; CHECK-NEXT:    i8 1, label [[CASE1:%.*]]
+; CHECK-NEXT:    i8 2, label [[CASE2:%.*]]
+; CHECK-NEXT:    i8 3, label [[END:%.*]]
+; CHECK-NEXT:    ]
+; CHECK:       unreachable:
+; CHECK-NEXT:    unreachable
+; CHECK:       case1:
+; CHECK-NEXT:    br label [[CASE012]]
+; CHECK:       case2:
+; CHECK-NEXT:    br label [[CASE012]]
+; CHECK:       case012:
+; CHECK-NEXT:    [[PHI1:%.*]] = phi i8 [ 3, [[CASE2]] ], [ 2, [[CASE1]] ], [ 1, [[START:%.*]] ]
+; CHECK-NEXT:    br label [[END]]
+; CHECK:       end:
+; CHECK-NEXT:    [[PHI2:%.*]] = phi i8 [ [[PHI1]], [[CASE012]] ], [ 4, [[START]] ]
+; CHECK-NEXT:    ret i8 [[PHI2]]
+;
+start:
+  switch i8 %arg, label %unreachable [
+  i8 0, label %case012
+  i8 1, label %case1
+  i8 2, label %case2
+  i8 3, label %end
+  ]
+unreachable:
+  unreachable
+case1:
+  br label %case012
+
+case2:
+  br label %case012
+
+case012:
+  %phi1 = phi i8 [ 3, %case2 ], [ 2, %case1 ], [1, %start]
+  br label %end
+
+end:
+  %phi2 = phi i8 [ %phi1, %case012 ], [ 4, %start ]
+  ret i8 %phi2
+}
+
+define i8 @multiple_phis_of_switch(i8 noundef %arg) {
+; CHECK-LABEL: define i8 @multiple_phis_of_switch
+; CHECK-SAME: (i8 noundef [[ARG:%.*]]) {
+; CHECK-NEXT:  start:
+; CHECK-NEXT:    switch i8 [[ARG]], label [[UNREACHABLE:%.*]] [
+; CHECK-NEXT:    i8 0, label [[CASE012:%.*]]
+; CHECK-NEXT:    i8 1, label [[CASE1:%.*]]
+; CHECK-NEXT:    i8 2, label [[CASE2:%.*]]
+; CHECK-NEXT:    i8 3, label [[END:%.*]]
+; CHECK-NEXT:    ]
+; CHECK:       unreachable:
+; CHECK-NEXT:    unreachable
+; CHECK:       case1:
+; CHECK-NEXT:    br label [[CASE012]]
+; CHECK:       case2:
+; CHECK-NEXT:    br label [[CASE012]]
+; CHECK:       case012:
+; CHECK-NEXT:    [[PHI1_1:%.*]] = phi i8 [ 3, [[CASE2]] ], [ 2, [[CASE1]] ], [ 1, [[START:%.*]] ]
+; CHECK-NEXT:    [[PHI1_2:%.*]] = phi i8 [ 6, [[CASE2]] ], [ 5, [[CASE1]] ], [ 4, [[START]] ]
+; CHECK-NEXT:    br label [[END]]
+; CHECK:       end:
+; CHECK-NEXT:    [[PHI2_1:%.*]] = phi i8 [ [[PHI1_1]], [[CASE012]] ], [ 4, [[START]] ]
+; CHECK-NEXT:    [[PHI2_2:%.*]] = phi i8 [ [[PHI1_1]], [[CASE012]] ], [ 5, [[START]] ]
+; CHECK-NEXT:    [[PHI2_3:%.*]] = phi i8 [ [[PHI1_2]], [[CASE012]] ], [ 3, [[START]] ]
+; CHECK-NEXT:    call void @use(i8 [[PHI2_1]])
+; CHECK-NEXT:    call void @use(i8 [[PHI2_2]])
+; CHECK-NEXT:    call void @use(i8 [[PHI2_3]])
+; CHECK-NEXT:    ret i8 [[PHI2_1]]
+;
+start:
+  switch i8 %arg, label %unreachable [
+  i8 0, label %case012
+  i8 1, label %case1
+  i8 2, label %case2
+  i8 3, label %end
+  ]
+unreachable:
+  unreachable
+case1:
+  br label %case012
+
+case2:
+  br label %case012
+
+case012:
+  %phi1_1 = phi i8 [ 3, %case2 ], [ 2, %case1 ], [1, %start]
+  %phi1_2 = phi i8 [ 6, %case2 ], [ 5, %case1 ], [4, %start]
+  br label %end
+
+end:
+  %phi2_1 = phi i8 [ %phi1_1, %case012 ], [ 4, %start ]
+  %phi2_2 = phi i8 [ %phi1_1, %case012 ], [ 5, %start ]
+  %phi2_3 = phi i8 [ %phi1_2, %case012 ], [ 3, %start ]
+  call void @use(i8 %phi2_1)
+  call void @use(i8 %phi2_2)
+  call void @use(i8 %phi2_3)
+  ret i8 %phi2_1
+}
+
+define i8 @phis_of_switch_multiple_stage0(i8 noundef %arg) {
+; CHECK-LABEL: define i8 @phis_of_switch_multiple_stage0
+; CHECK-SAME: (i8 noundef [[ARG:%.*]]) {
+; CHECK-NEXT:  start:
+; CHECK-NEXT:    switch i8 [[ARG]], label [[UNREACHABLE:%.*]] [
+; CHECK-NEXT:    i8 0, label [[CASE0:%.*]]
+; CHECK-NEXT:    i8 1, label [[CASE1:%.*]]
+; CHECK-NEXT:    i8 2, label [[CASE2:%.*]]
+; CHECK-NEXT:    i8 3, label [[CASE0123:%.*]]
+; CHECK-NEXT:    i8 4, label [[CASE01234:%.*]]
+; CHECK-NEXT:    i8 5, label [[END:%.*]]
+; CHECK-NEXT:    ]
+; CHECK:       unreachable:
+; CHECK-NEXT:    unreachable
+; CHECK:       case0:
+; CHECK-NEXT:    br label [[CASE0123]]
+; CHECK:       case1:
+; CHECK-NEXT:    br label [[CASE0123]]
+; CHECK:       case2:
+; CHECK-NEXT:    br label [[CASE0123]]
+; CHECK:       case0123:
+; CHECK-NEXT:    [[PHI1:%.*]] = phi i8 [ 4, [[START:%.*]] ], [ 3, [[CASE2]] ], [ 2, [[CASE1]] ], [ 1, [[CASE0]] ]
+; CHECK-NEXT:    br label [[CASE01234]]
+; CHECK:       case01234:
+; CHECK-NEXT:    [[PHI2:%.*]] = phi i8 [ [[PHI1]], [[CASE0123]] ], [ 5, [[START]] ]
+; CHECK-NEXT:    br label [[END]]
+; CHECK:       end:
+; CHECK-NEXT:    [[PHI3:%.*]] = phi i8 [ [[PHI2]], [[CASE01234]] ], [ 6, [[START]] ]
+; CHECK-NEXT:    ret i8 [[PHI3]]
+;
+start:
+  switch i8 %arg, label %unreachable [
+  i8 0, label %case0
+  i8 1, label %case1
+  i8 2, label %case2
+  i8 3, label %case0123
+  i8 4, label %case01234
+  i8 5, label %end
+  ]
+unreachable:
+  unreachable
+
+case0:
+  br label %case0123
+
+case1:
+  br label %case0123
+
+case2:
+  br label %case0123
+
+case0123:
+  %phi1 = phi i8 [4, %start], [ 3, %case2 ], [ 2, %case1 ], [ 1, %case0 ]
+  br label %case01234
+
+case01234:
+  %phi2 = phi i8 [ %phi1, %case0123 ], [ 5, %start ]
+  br label %end
+
+end:
+  %phi3 = phi i8 [ %phi2, %case01234 ], [6, %start]
+  ret i8 %phi3
+}
+
+define i8 @phis_of_switch_multiple_stage1(i8 noundef %arg) {
+; CHECK-LABEL: define i8 @phis_of_switch_multiple_stage1
+; CHECK-SAME: (i8 noundef [[ARG:%.*]]) {
+; CHECK-NEXT:  start:
+; CHECK-NEXT:    switch i8 [[ARG]], label [[UNREACHABLE:%.*]] [
+; CHECK-NEXT:    i8 0, label [[CASE0:%.*]]
+; CHECK-NEXT:    i8 1, label [[CASE1:%.*]]
+; CHECK-NEXT:    i8 2, label [[CASE012:%.*]]
+; CHECK-NEXT:    i8 3, label [[CASE3:%.*]]
+; CHECK-NEXT:    i8 4, label [[CASE4:%.*]]
+; CHECK-NEXT:    i8 5, label [[CASE345:%.*]]
+; CHECK-NEXT:    i8 6, label [[CASE0123456:%.*]]
+; CHECK-NEXT:    ]
+; CHECK:       unreachable:
+; CHECK-NEXT:    unreachable
+; CHECK:       case0:
+; CHECK-NEXT:    br label [[CASE012]]
+; CHECK:       case1:
+; CHECK-NEXT:    br label [[CASE012]]
+; CHECK:       case012:
+; CHECK-NEXT:    [[PHI123:%.*]] = phi i8 [ 3, [[START:%.*]] ], [ 2, [[CASE1]] ], [ 1, [[CASE0]] ]
+; CHECK-NEXT:    br label [[CASE0123456]]
+; CHECK:       case3:
+; CHECK-NEXT:    br label [[CASE345]]
+; CHECK:       case4:
+; CHECK-NEXT:    br label [[CASE345]]
+; CHECK:       case345:
+; CHECK-NEXT:    [[PHI456:%.*]] = phi i8 [ 6, [[START]] ], [ 5, [[CASE4]] ], [ 4, [[CASE3]] ]
+; CHECK-NEXT:    br label [[CASE0123456]]
+; CHECK:       case0123456:
+; CHECK-NEXT:    [[PHI1234567:%.*]] = phi i8 [ 7, [[START]] ], [ [[PHI456]], [[CASE345]] ], [ [[PHI123]], [[CASE012]] ]
+; CHECK-NEXT:    ret i8 [[PHI1234567]]
+;
+start:
+  switch i8 %arg, label %unreachable [
+  i8 0, label %case0
+  i8 1, label %case1
+  i8 2, label %case012
+  i8 3, label %case3
+  i8 4, label %case4
+  i8 5, label %case345
+  i8 6, label %case0123456
+  ]
+unreachable:
+  unreachable
+case0:
+  br label %case012
+
+case1:
+  br label %case012
+
+case012:
+  %phi123 = phi i8 [3, %start], [ 2, %case1 ], [ 1, %case0 ]
+  br label %case0123456
+
+case3:
+  br label %case345
+
+case4:
+  br label %case345
+
+case345:
+  %phi456 = phi i8 [6, %start], [ 5, %case4 ], [ 4, %case3 ]
+  br label %case0123456
+
+case0123456:
+  %phi1234567 = phi i8 [7, %start], [ %phi456, %case345 ], [ %phi123, %case012 ]
+  ret i8 %phi1234567
+
+}
+
+define i8 @phis_of_switch_extra_use_fail(i8 noundef %arg) {
+; CHECK-LABEL: define i8 @phis_of_switch_extra_use_fail
+; CHECK-SAME: (i8 noundef [[ARG:%.*]]) {
+; CHECK-NEXT:  start:
+; CHECK-NEXT:    switch i8 [[ARG]], label [[UNREACHABLE:%.*]] [
+; CHECK-NEXT:    i8 0, label [[CASE012:%.*]]
+; CHECK-NEXT:    i8 1, label [[CASE1:%.*]]
+; CHECK-NEXT:    i8 2, label [[CASE2:%.*]]
+; CHECK-NEXT:    i8 3, label [[END:%.*]]
+; CHECK-NEXT:    ]
+; CHECK:       unreachable:
+; CHECK-NEXT:    unreachable
+; CHECK:       case1:
+; CHECK-NEXT:    br label [[CASE012]]
+; CHECK:       case2:
+; CHECK-NEXT:    br label [[CASE012]]
+; CHECK:       case012:
+; CHECK-NEXT:    [[PHI1:%.*]] = phi i8 [ 3, [[CASE2]] ], [ 2, [[CASE1]] ], [ 1, [[START:%.*]] ]
+; CHECK-NEXT:    call void @use(i8 [[PHI1]])
+; CHECK-NEXT:    br label [[END]]
+; CHECK:       end:
+; CHECK-NEXT:    [[PHI2:%.*]] = phi i8 [ [[PHI1]], [[CASE012]] ], [ 4, [[START]] ]
+; CHECK-NEXT:    ret i8 [[PHI2]]
+;
+start:
+  switch i8 %arg, label %unreachable [
+  i8 0, label %case012
+  i8 1, label %case1
+  i8 2, label %case2 i8 3, label %end
+  ]
+unreachable:
+  unreachable
+case1:
+  br label %case012
+
+case2:
+  br label %case012
+
+case012:
+  %phi1 = phi i8 [ 3, %case2 ], [ 2, %case1 ], [1, %start]
+  call void @use(i8 %phi1)
+  br label %end
+
+end:
+  %phi2 = phi i8 [ %phi1, %case012 ], [ 4, %start ]
+  ret i8 %phi2
+}
diff --git a/llvm/test/Transforms/SimplifyCFG/multiple-phis.ll b/llvm/test/Transforms/SimplifyCFG/multiple-phis.ll
index eae851f2ddadae9..807aeec38db3d72 100644
--- a/llvm/test/Transforms/SimplifyCFG/multiple-phis.ll
+++ b/llvm/test/Transforms/SimplifyCFG/multiple-phis.ll
@@ -1,4 +1,5 @@
-; NOTE: Assertions have been autogenerated by utils/update_test_checks.py
+; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --version 2
+
 ; RUN: opt -passes=simplifycfg -simplifycfg-require-and-preserve-domtree=1 -keep-loops=false -S < %s | FileCheck %s
 ; RUN: opt -passes='simplifycfg<no-keep-loops>' -S < %s | FileCheck %s
 
@@ -7,11 +8,12 @@
 ; SimplifyCFG if-converts one of the phis, it should do both.
 
 define i32 @upper_bound(ptr %r, i32 %high, i32 %k) nounwind {
-; CHECK-LABEL: @upper_bound(
+; CHECK-LABEL: define i32 @upper_bound
+; CHECK-SAME: (ptr [[R:%.*]], i32 [[HIGH:%.*]], i32 [[K:%.*]]) #[[ATTR0:[0-9]+]] {
 ; CHECK-NEXT:  entry:
 ; CHECK-NEXT:    br label [[WHILE_COND:%.*]]
 ; CHECK:       while.cond:
-; CHECK-NEXT:    [[HIGH_ADDR_0:%.*]] = phi i32 [ [[HIGH:%.*]], [[ENTRY:%.*]] ], [ [[SPEC_SELECT:%.*]], [[WHILE_BODY:%.*]] ]
+; CHECK-NEXT:    [[HIGH_ADDR_0:%.*]] = phi i32 [ [[HIGH]], [[ENTRY:%.*]] ], [ [[SPEC_SELECT:%.*]], [[WHILE_BODY:%.*]] ]
 ; CHECK-NEXT:    [[LOW_0:%.*]] = phi i32 [ 0, [[ENTRY]] ], [ [[SPEC_SELECT1:%.*]], [[WHILE_BODY]] ]
 ; CHECK-NEXT:    [[CMP:%.*]] = icmp ult i32 [[LOW_0]], [[HIGH_ADDR_0]]
 ; CHECK-NEXT:    br i1 [[CMP]], label [[WHILE_BODY]], label [[WHILE_END:%.*]]
@@ -19,9 +21,9 @@ define i32 @upper_bound(ptr %r, i32 %high, i32 %k) nounwind {
 ; CHECK-NEXT:    [[ADD:%.*]] = add i32 [[LOW_0]], [[HIGH_ADDR_0]]
 ; CHECK-NEXT:    [[DIV:%.*]] = udiv i32 [[ADD]], 2
 ; CHECK-NEXT:    [[IDXPROM:%.*]] = zext i32 [[DIV]] to i64
-; CHECK-NEXT:    [[ARRAYIDX:%.*]] = getelementptr inbounds i32, ptr [[R:%.*]], i64 [[IDXPROM]]
+; CHECK-NEXT:    [[ARRAYIDX:%.*]] = getelementptr inbounds i32, ptr [[R]], i64 [[IDXPROM]]
 ; CHECK-NEXT:    [[TMP0:%.*]] = load i32, ptr [[ARRAYIDX]], align 4
-; CHECK-NEXT:    [[CMP1:%.*]] = icmp ult i32 [[K:%.*]], [[TMP0]]
+; CHECK-NEXT:    [[CMP1:%.*]] = icmp ult i32 [[K]], [[TMP0]]
 ; CHECK-NEXT:    [[ADD2:%.*]] = add i32 [[DIV]], 1
 ; CHECK-NEXT:    [[SPEC_SELECT]] = select i1 [[CMP1]], i32 [[DIV]], i32 [[HIGH_ADDR_0]]
 ; CHECK-NEXT:    [[SPEC_SELECT1]] = select i1 [[CMP1]], i32 [[LOW_0]], i32 [[ADD2]]
@@ -57,3 +59,285 @@ if.else:                                          ; preds = %while.body
 while.end:                                        ; preds = %while.cond
   ret i32 %low.0
 }
+
+define i32 @merge0(i1 %c1, i1 %c2, i1 %c3) {
+; CHECK-LABEL: define i32 @merge0
+; CHECK-SAME: (i1 [[C1:%.*]], i1 [[C2:%.*]], i1 [[C3:%.*]]) {
+; CHECK-NEXT:    br i1 [[C1]], label [[IF1:%.*]], label [[ELSE1:%.*]]
+; CHECK:       if1:
+; CHECK-NEXT:    [[DOT:%.*]] = select i1 [[C2]], i32 0, i32 1
+; CHECK-NEXT:    br label [[J1:%.*]]
+; CHECK:       else1:
+; CHECK-NEXT:    br i1 [[C3]], label [[J1]], label [[J2:%.*]]
+; CHECK:       j1:
+; CHECK-NEXT:    [[PHI1:%.*]] = phi i32 [ 2, [[ELSE1]] ], [ [[DOT]], [[IF1]] ]
+; CHECK-NEXT:    br label [[J2]]
+; CHECK:       j2:
+; CHECK-NEXT:    [[PHI2:%.*]] = phi i32 [ [[PHI1]], [[J1]] ], [ 3, [[ELSE1]] ]
+; CHECK-NEXT:    ret i32 [[PHI2]]
+;
+  br i1 %c1, label %if1, label %else1
+
+if1:
+  br i1 %c2, label %if2, label %else2
+
+if2:
+  br label %j1 else2:
+  br label %j1
+
+else1:
+  br i1 %c3, label %j1, label %j2
+
+j1:
+  %phi1 = phi i32 [ 0, %if2 ], [ 1, %else2 ], [ 2, %else1 ]
+  br label %j2
+
+j2:
+  %phi2 = phi i32 [ %phi1, %j1 ], [ 3, %else1 ]
+  ret i32 %phi2
+}
+
+define i8 @merge1(i8 noundef %arg, i1 %c1, i1 %c2) {
+; CHECK-LABEL: define i8 @merge1
+; CHECK-SAME: (i8 noundef [[ARG:%.*]], i1 [[C1:%.*]], i1 [[C2:%.*]]) {
+; CHECK-NEXT:  entry:
+; CHECK-NEXT:    switch i8 [[ARG]], label [[UNREACHABLE:%.*]] [
+; CHECK-NEXT:    i8 -123, label [[CASE0:%.*]]
+; CHECK-NEXT:    i8 66, label [[BB:%.*]]
+; CHECK-NEXT:    i8 123, label [[CASE2:%.*]]
+; CHECK-NEXT:    ]
+; CHECK:       unreachable:
+; CHECK-NEXT:    unreachable
+; CHECK:       case0:
+; CHECK-NEXT:    [[C1_NOT:%.*]] = xor i1 [[C1]], true
+; CHECK-NEXT:    [[C2_NOT:%.*]] = xor i1 [[C2]], true
+; CHECK-NEXT:    [[BRMERGE:%.*]] = select i1 [[C1_NOT]], i1 true, i1 [[C2_NOT]]
+; CHECK-NEXT:    [[DOTMUX:%.*]] = select i1 [[C1_NOT]], i8 0, i8 3
+; CHECK-NEXT:    br i1 [[BRMERGE]], label [[BB]], label [[SUCC:%.*]]
+; CHECK:       case2:
+; CHECK-NEXT:    br label [[BB]]
+; CHECK:       BB:
+; CHECK-NEXT:    [[PHI1:%.*]] = phi i8 [ [[DOTMUX]], [[CASE0]] ], [ 2, [[CASE2]] ], [ 1, [[ENTRY:%.*]] ]
+; CHECK-NEXT:    br label [[SUCC]]
+; CHECK:       Succ:
+; CHECK-NEXT:    [[PHI2:%.*]] = phi i8 [ [[PHI1]], [[BB]] ], [ 4, [[CASE0]] ]
+; CHECK-NEXT:    ret i8 [[PHI2]]
+;
+entry:
+  switch i8 %arg, label %unreachable [
+  i8 -123, label %case0
+  i8 66, label %case1
+  i8 123, label %case2
+  ]
+
+unreachable:
+  unreachable
+
+case0:
+  br i1 %c1, label %CommonPred, label %BB
+
+case1:
+  br label %BB
+
+case2:
+  br label %BB
+
+CommonPred:
+  br i1 %c2, label %Succ, label %BB
+
+BB:
+  %phi1 = phi i8 [ 0, %case0 ], [1, %case1],[2, %case2],[3,%CommonPred]
+  br label %Succ
+
+Succ:
+  %phi2 = phi i8 [ %phi1, %BB ], [ 4, %CommonPred ]
+  ret i8 %phi2
+}
+
+define i8 @merge1_unfoldable_one_block(i8 noundef %arg, i1 %c1, i1 %c2) {
+; CHECK-LABEL: define i8 @merge1_unfoldable_one_block
+; CHECK-SAME: (i8 noundef [[ARG:%.*]], i1 [[C1:%.*]], i1 [[C2:%.*]]) {
+; CHECK-NEXT:  entry:
+; CHECK-NEXT:    switch i8 [[ARG]], label [[UNREACHABLE:%.*]] [
+; CHECK-NEXT:    i8 -123, label [[CASE0:%.*]]
+; CHECK-NEXT:    i8 66, label [[BB:%.*]]
+; CHECK-NEXT:    i8 123, label [[CASE2:%.*]]
+; CHECK-NEXT:    ]
+; CHECK:       unreachable:
+; CHECK-NEXT:    unreachable
+; CHECK:       case0:
+; CHECK-NEXT:    call void @dummy()
+; CHECK-NEXT:    [[C1_NOT:%.*]] = xor i1 [[C1]], true
+; CHECK-NEXT:    [[C2_NOT:%.*]] = xor i1 [[C2]], true
+; CHECK-NEXT:    [[BRMERGE:%.*]] = select i1 [[C1_NOT]], i1 true, i1 [[C2_NOT]]
+; CHECK-NEXT:    [[DOTMUX:%.*]] = select i1 [[C1_NOT]], i8 0, i8 3
+; CHECK-NEXT:    br i1 [[BRMERGE]], label [[BB]], label [[SUCC:%.*]]
+; CHECK:       case2:
+; CHECK-NEXT:    br label [[BB]]
+; CHECK:       BB:
+; CHECK-NEXT:    [[PHI1:%.*]] = phi i8 [ [[DOTMUX]], [[CASE0]] ], [ 2, [[CASE2]] ], [ 1, [[ENTRY:%.*]] ]
+; CHECK-NEXT:    br label [[SUCC]]
+; CHECK:       Succ:
+; CHECK-NEXT:    [[PHI2:%.*]] = phi i8 [ [[PHI1]], [[BB]] ], [ 4, [[CASE0]] ]
+; CHECK-NEXT:    ret i8 [[PHI2]]
+;
+entry:
+  switch i8 %arg, label %unreachable [
+  i8 -123, label %case0
+  i8 66, label %case1
+  i8 123, label %case2
+  ]
+
+unreachable:
+  unreachable
+
+case0:
+  call void @dummy()
+  br i1 %c1, label %CommonPred, label %BB
+
+case1:
+  br label %BB
+
+case2:
+  br label %BB
+
+CommonPred:
+  br i1 %c2, label %Succ, label %BB
+
+BB:
+  %phi1 = phi i8 [ 0, %case0 ], [1, %case1],[2, %case2],[3,%CommonPred]
+  br label %Succ
+
+Succ:
+  %phi2 = phi i8 [ %phi1, %BB ], [ 4, %CommonPred ]
+  ret i8 %phi2
+}
+
+define i8 @merge1_unfoldable_two_block(i8 noundef %arg, i1 %c1, i1 %c2) {
+; CHECK-LABEL: define i8 @merge1_unfoldable_two_block
+; CHECK-SAME: (i8 noundef [[ARG:%.*]], i1 [[C1:%.*]], i1 [[C2:%.*]]) {
+; CHECK-NEXT:  entry:
+; CHECK-NEXT:    switch i8 [[ARG]], label [[UNREACHABLE:%.*]] [
+; CHECK-NEXT:    i8 -123, label [[CASE0:%.*]]
+; CHECK-NEXT:    i8 66, label [[CASE1:%.*]]
+; CHECK-NEXT:    i8 123, label [[BB:%.*]]
+; CHECK-NEXT:    ]
+; CHECK:       unreachable:
+; CHECK-NEXT:    unreachable
+; CHECK:       case0:
+; CHECK-NEXT:    call void @dummy()
+; CHECK-NEXT:    [[C1_NOT:%.*]] = xor i1 [[C1]], true
+; CHECK-NEXT:    [[C2_NOT:%.*]] = xor i1 [[C2]], true
+; CHECK-NEXT:    [[BRMERGE:%.*]] = select i1 [[C1_NOT]], i1 true, i1 [[C2_NOT]]
+; CHECK-NEXT:    [[DOTMUX:%.*]] = select i1 [[C1_NOT]], i8 0, i8 3
+; CHECK-NEXT:    br i1 [[BRMERGE]], label [[BB]], label [[SUCC:%.*]]
+; CHECK:       case1:
+; CHECK-NEXT:    call void @dummy()
+; CHECK-NEXT:    br label [[BB]]
+; CHECK:       BB:
+; CHECK-NEXT:    [[PHI1:%.*]] = phi i8 [ [[DOTMUX]], [[CASE0]] ], [ 1, [[CASE1]] ], [ 2, [[ENTRY:%.*]] ]
+; CHECK-NEXT:    br label [[SUCC]]
+; CHECK:       Succ:
+; CHECK-NEXT:    [[PHI2:%.*]] = phi i8 [ [[PHI1]], [[BB]] ], [ 4, [[CASE0]] ]
+; CHECK-NEXT:    ret i8 [[PHI2]]
+;
+entry:
+  switch i8 %arg, label %unreachable [
+  i8 -123, label %case0
+  i8 66, label %case1
+  i8 123, label %case2
+  ]
+
+unreachable:
+  unreachable
+
+case0:
+call void @dummy()
+  br i1 %c1, label %CommonPred, label %BB
+
+case1:
+call void @dummy()
+  br label %BB
+
+case2:
+  br label %BB
+
+CommonPred:
+  br i1 %c2, label %Succ, label %BB
+
+BB:
+  %phi1 = phi i8 [ 0, %case0 ], [1, %case1],[2, %case2],[3,%CommonPred]
+  br label %Succ
+
+Succ:
+  %phi2 = phi i8 [ %phi1, %BB ], [ 4, %CommonPred ]
+  ret i8 %phi2
+}
+
+define i8 @merge1_unfoldable_all_block(i8 noundef %arg, i1 %c1, i1 %c2) {
+; CHECK-LABEL: define i8 @merge1_unfoldable_all_block
+; CHECK-SAME: (i8 noundef [[ARG:%.*]], i1 [[C1:%.*]], i1 [[C2:%.*]]) {
+; CHECK-NEXT:  entry:
+; CHECK-NEXT:    switch i8 [[ARG]], label [[UNREACHABLE:%.*]] [
+; CHECK-NEXT:    i8 -123, label [[CASE0:%.*]]
+; CHECK-NEXT:    i8 66, label [[CASE1:%.*]]
+; CHECK-NEXT:    i8 123, label [[CASE2:%.*]]
+; CHECK-NEXT:    ]
+; CHECK:       unreachable:
+; CHECK-NEXT:    unreachable
+; CHECK:       case0:
+; CHECK-NEXT:    call void @dummy()
+; CHECK-NEXT:    br i1 [[C1]], label [[COMMONPRED:%.*]], label [[BB:%.*]]
+; CHECK:       case1:
+; CHECK-NEXT:    call void @dummy()
+; CHECK-NEXT:    br label [[BB]]
+; CHECK:       case2:
+; CHECK-NEXT:    call void @dummy()
+; CHECK-NEXT:    br label [[BB]]
+; CHECK:       CommonPred:
+; CHECK-NEXT:    call void @dummy()
+; CHECK-NEXT:    br i1 [[C2]], label [[SUCC:%.*]], label [[BB]]
+; CHECK:       BB:
+; CHECK-NEXT:    [[PHI1:%.*]] = phi i8 [ 0, [[CASE0]] ], [ 1, [[CASE1]] ], [ 2, [[CASE2]] ], [ 3, [[COMMONPRED]] ]
+; CHECK-NEXT:    br label [[SUCC]]
+; CHECK:       Succ:
+; CHECK-NEXT:    [[PHI2:%.*]] = phi i8 [ [[PHI1]], [[BB]] ], [ 4, [[COMMONPRED]] ]
+; CHECK-NEXT:    ret i8 [[PHI2]]
+;
+entry:
+  switch i8 %arg, label %unreachable [
+  i8 -123, label %case0
+  i8 66, label %case1
+  i8 123, label %case2
+  ]
+
+unreachable:
+  unreachable
+
+case0:
+call void @dummy()
+  br i1 %c1, label %CommonPred, label %BB
+
+case1:
+call void @dummy()
+  br label %BB
+
+case2:
+call void @dummy()
+  br label %BB
+
+CommonPred:
+call void @dummy()
+  br i1 %c2, label %Succ, label %BB
+
+BB:
+  %phi1 = phi i8 [ 0, %case0 ], [1, %case1],[2, %case2],[3,%CommonPred]
+  br label %Succ
+
+Succ:
+  %phi2 = phi i8 [ %phi1, %BB ], [ 4, %CommonPred ]
+  ret i8 %phi2
+}
+
+declare void @dummy()
+

>From 355c5f717a8072e3fecb36dc826056e40e795adb Mon Sep 17 00:00:00 2001
From: XChy <xxs_chy at outlook.com>
Date: Sat, 22 Jul 2023 16:28:30 +0800
Subject: [PATCH 2/2] Transform for merging the combination of phis in switch

---
 llvm/lib/Transforms/Utils/Local.cpp           | 166 ++++++++++++++----
 llvm/test/CodeGen/ARM/jump-table-islands.ll   |   4 +
 .../Transforms/JumpThreading/codesize-loop.ll |  48 +++--
 .../Transforms/SimplifyCFG/branch-fold.ll     |   8 +-
 .../SimplifyCFG/merge-phis-in-switch.ll       |  48 +++--
 .../Transforms/SimplifyCFG/multiple-phis.ll   |  55 +++---
 .../SimplifyCFG/switch-simplify-crash2.ll     |   3 +
 7 files changed, 199 insertions(+), 133 deletions(-)

diff --git a/llvm/lib/Transforms/Utils/Local.cpp b/llvm/lib/Transforms/Utils/Local.cpp
index ddb47e693a643d8..47382fefa206aa9 100644
--- a/llvm/lib/Transforms/Utils/Local.cpp
+++ b/llvm/lib/Transforms/Utils/Local.cpp
@@ -847,17 +847,17 @@ static bool CanMergeValues(Value *First, Value *Second) {
 /// branch to Succ, into Succ.
 ///
 /// Assumption: Succ is the single successor for BB.
-static bool CanPropagatePredecessorsForPHIs(BasicBlock *BB, BasicBlock *Succ) {
+static bool
+CanPropagatePredecessorsForPHIs(BasicBlock *BB, BasicBlock *Succ,
+                                const SmallPtrSetImpl<BasicBlock *> &BBPreds) {
   assert(*succ_begin(BB) == Succ && "Succ is not successor of BB!");
 
   LLVM_DEBUG(dbgs() << "Looking to fold " << BB->getName() << " into "
                     << Succ->getName() << "\n");
   // Shortcut, if there is only a single predecessor it must be BB and merging
   // is always safe
-  if (Succ->getSinglePredecessor()) return true;
-
-  // Make a list of the predecessors of BB
-  SmallPtrSet<BasicBlock*, 16> BBPreds(pred_begin(BB), pred_end(BB));
+  if (Succ->getSinglePredecessor())
+    return true;
 
   // Look at all the phi nodes in Succ, to see if they present a conflict when
   // merging these blocks
@@ -997,6 +997,35 @@ static void replaceUndefValuesInPhi(PHINode *PN,
   }
 }
 
+// Only when they shares a single common predecessor, return true.
+// Only handles cases when BB can't be merged while its predecessors can be
+// redirected.
+static bool
+CanRedirectPredsOfEmptyBBToSucc(BasicBlock *BB, BasicBlock *Succ,
+                                const SmallPtrSetImpl<BasicBlock *> &BBPreds,
+                                const SmallPtrSetImpl<BasicBlock *> &SuccPreds,
+                                BasicBlock *&CommonPred) {
+
+  // There must be phis in BB, otherwise BB will be merged into Succ directly
+  if (BB->phis().empty() || Succ->phis().empty())
+    return false;
+
+  // BB must have predecessors not shared that can be redirected to Succ
+  if (!BB->hasNPredecessorsOrMore(2))
+    return false;
+
+  // Get single common predecessors of both BB and Succ
+  for (BasicBlock *SuccPred : SuccPreds) {
+    if (BBPreds.count(SuccPred)) {
+      if (CommonPred)
+        return false;
+      CommonPred = SuccPred;
+    }
+  }
+
+  return true;
+}
+
 /// Replace a value flowing from a block to a phi with
 /// potentially multiple instances of that value flowing from the
 /// block's predecessors to the phi.
@@ -1004,9 +1033,11 @@ static void replaceUndefValuesInPhi(PHINode *PN,
 /// \param BB The block with the value flowing into the phi.
 /// \param BBPreds The predecessors of BB.
 /// \param PN The phi that we are updating.
+/// \param CommonPred The common predecessor of BB and PN's BasicBlock
 static void redirectValuesFromPredecessorsToPhi(BasicBlock *BB,
                                                 const PredBlockVector &BBPreds,
-                                                PHINode *PN) {
+                                                PHINode *PN,
+                                                BasicBlock *CommonPred) {
   Value *OldVal = PN->removeIncomingValue(BB, false);
   assert(OldVal && "No entry in PHI for Pred BB!");
 
@@ -1034,26 +1065,39 @@ static void redirectValuesFromPredecessorsToPhi(BasicBlock *BB,
       // will trigger asserts if we try to clean it up now, without also
       // simplifying the corresponding conditional branch).
       BasicBlock *PredBB = OldValPN->getIncomingBlock(i);
+
+      if (PredBB == CommonPred)
+        continue;
+
       Value *PredVal = OldValPN->getIncomingValue(i);
-      Value *Selected = selectIncomingValueForBlock(PredVal, PredBB,
-                                                    IncomingValues);
+      Value *Selected =
+          selectIncomingValueForBlock(PredVal, PredBB, IncomingValues);
 
       // And add a new incoming value for this predecessor for the
       // newly retargeted branch.
       PN->addIncoming(Selected, PredBB);
     }
+    if (CommonPred)
+      PN->addIncoming(OldValPN->getIncomingValueForBlock(CommonPred), BB);
+
   } else {
     for (unsigned i = 0, e = BBPreds.size(); i != e; ++i) {
       // Update existing incoming values in PN for this
       // predecessor of BB.
       BasicBlock *PredBB = BBPreds[i];
-      Value *Selected = selectIncomingValueForBlock(OldVal, PredBB,
-                                                    IncomingValues);
+
+      if (PredBB == CommonPred)
+        continue;
+
+      Value *Selected =
+          selectIncomingValueForBlock(OldVal, PredBB, IncomingValues);
 
       // And add a new incoming value for this predecessor for the
       // newly retargeted branch.
       PN->addIncoming(Selected, PredBB);
     }
+    if (CommonPred)
+      PN->addIncoming(OldVal, BB);
   }
 
   replaceUndefValuesInPhi(PN, IncomingValues);
@@ -1064,13 +1108,30 @@ bool llvm::TryToSimplifyUncondBranchFromEmptyBlock(BasicBlock *BB,
   assert(BB != &BB->getParent()->getEntryBlock() &&
          "TryToSimplifyUncondBranchFromEmptyBlock called on entry block!");
 
-  // We can't eliminate infinite loops.
+  // We can't simplify infinite loops.
   BasicBlock *Succ = cast<BranchInst>(BB->getTerminator())->getSuccessor(0);
-  if (BB == Succ) return false;
+  if (BB == Succ)
+    return false;
+
+  SmallPtrSet<BasicBlock *, 16> BBPreds(pred_begin(BB), pred_end(BB));
+  SmallPtrSet<BasicBlock *, 16> SuccPreds(pred_begin(Succ), pred_end(Succ));
 
-  // Check to see if merging these blocks would cause conflicts for any of the
-  // phi nodes in BB or Succ. If not, we can safely merge.
-  if (!CanPropagatePredecessorsForPHIs(BB, Succ)) return false;
+  // The single common predecessor of BB and Succ when BB cannot be killed
+  BasicBlock *CommonPred = nullptr;
+
+  bool BBKillable = CanPropagatePredecessorsForPHIs(BB, Succ, BBPreds);
+
+  // Even if we can not fold bB into Succ, we may be able to redirect the
+  // predecessors of BB to Succ.
+  bool BBPhisMergeable =
+      BBKillable ||
+      CanRedirectPredsOfEmptyBBToSucc(BB, Succ, BBPreds, SuccPreds, CommonPred);
+
+  if (!BBKillable && !BBPhisMergeable)
+    return false;
+
+  // Check to see if merging these blocks/phis would cause conflicts for any of
+  // the phi nodes in BB or Succ. If not, we can safely merge.
 
   // Check for cases where Succ has multiple predecessors and a PHI node in BB
   // has uses which will not disappear when the PHI nodes are merged.  It is
@@ -1099,6 +1160,11 @@ bool llvm::TryToSimplifyUncondBranchFromEmptyBlock(BasicBlock *BB,
     }
   }
 
+  if (BBPhisMergeable && CommonPred)
+    LLVM_DEBUG(dbgs() << "Found Common Predecessor between: " << BB->getName()
+                      << " and " << Succ->getName() << " : "
+                      << CommonPred->getName() << "\n");
+
   // 'BB' and 'BB->Pred' are loop latches, bail out to presrve inner loop
   // metadata.
   //
@@ -1171,25 +1237,37 @@ bool llvm::TryToSimplifyUncondBranchFromEmptyBlock(BasicBlock *BB,
           if (PredTI->hasMetadata(LLVMContext::MD_loop))
             return false;
 
-  LLVM_DEBUG(dbgs() << "Killing Trivial BB: \n" << *BB);
+  if (BBKillable)
+    LLVM_DEBUG(dbgs() << "Killing Trivial BB: \n" << *BB);
+  else if (BBPhisMergeable)
+    LLVM_DEBUG(dbgs() << "Merge Phis in Trivial BB: \n" << *BB);
 
   SmallVector<DominatorTree::UpdateType, 32> Updates;
+
   if (DTU) {
     // To avoid processing the same predecessor more than once.
     SmallPtrSet<BasicBlock *, 8> SeenPreds;
-    // All predecessors of BB will be moved to Succ.
-    SmallPtrSet<BasicBlock *, 8> PredsOfSucc(pred_begin(Succ), pred_end(Succ));
+    // All predecessors of BB (except the common predecessor) will be moved to
+    // Succ.
     Updates.reserve(Updates.size() + 2 * pred_size(BB) + 1);
-    for (auto *PredOfBB : predecessors(BB))
-      // This predecessor of BB may already have Succ as a successor.
-      if (!PredsOfSucc.contains(PredOfBB))
+
+    for (auto *PredOfBB : predecessors(BB)) {
+      // Do not modify those common predecessors of BB and Succ
+      if (!SuccPreds.contains(PredOfBB))
         if (SeenPreds.insert(PredOfBB).second)
           Updates.push_back({DominatorTree::Insert, PredOfBB, Succ});
+    }
+
     SeenPreds.clear();
+
     for (auto *PredOfBB : predecessors(BB))
-      if (SeenPreds.insert(PredOfBB).second)
+      // When BB cannot be killed, do not remove the edge between BB and
+      // CommonPred.
+      if (SeenPreds.insert(PredOfBB).second && PredOfBB != CommonPred)
         Updates.push_back({DominatorTree::Delete, PredOfBB, BB});
-    Updates.push_back({DominatorTree::Delete, BB, Succ});
+
+    if (BBKillable)
+      Updates.push_back({DominatorTree::Delete, BB, Succ});
   }
 
   if (isa<PHINode>(Succ->begin())) {
@@ -1201,21 +1279,19 @@ bool llvm::TryToSimplifyUncondBranchFromEmptyBlock(BasicBlock *BB,
     // Loop over all of the PHI nodes in the successor of BB.
     for (BasicBlock::iterator I = Succ->begin(); isa<PHINode>(I); ++I) {
       PHINode *PN = cast<PHINode>(I);
-
-      redirectValuesFromPredecessorsToPhi(BB, BBPreds, PN);
+      redirectValuesFromPredecessorsToPhi(BB, BBPreds, PN, CommonPred);
     }
   }
 
   if (Succ->getSinglePredecessor()) {
     // BB is the only predecessor of Succ, so Succ will end up with exactly
     // the same predecessors BB had.
-
     // Copy over any phi, debug or lifetime instruction.
     BB->getTerminator()->eraseFromParent();
     Succ->splice(Succ->getFirstNonPHI()->getIterator(), BB);
   } else {
     while (PHINode *PN = dyn_cast<PHINode>(&BB->front())) {
-      // We explicitly check for such uses in CanPropagatePredecessorsForPHIs.
+      // We explicitly check for such uses for merging phis.
       assert(PN->use_empty() && "There shouldn't be any uses here!");
       PN->eraseFromParent();
     }
@@ -1228,21 +1304,35 @@ bool llvm::TryToSimplifyUncondBranchFromEmptyBlock(BasicBlock *BB,
       for (BasicBlock *Pred : predecessors(BB))
         Pred->getTerminator()->setMetadata(LLVMContext::MD_loop, LoopMD);
 
-  // Everything that jumped to BB now goes to Succ.
-  BB->replaceAllUsesWith(Succ);
-  if (!Succ->hasName()) Succ->takeName(BB);
-
-  // Clear the successor list of BB to match updates applying to DTU later.
-  if (BB->getTerminator())
-    BB->back().eraseFromParent();
-  new UnreachableInst(BB->getContext(), BB);
-  assert(succ_empty(BB) && "The successor list of BB isn't empty before "
-                           "applying corresponding DTU updates.");
+  if (BBKillable) {
+    // Everything that jumped to BB now goes to Succ.
+    BB->replaceAllUsesWith(Succ);
+
+    if (!Succ->hasName())
+      Succ->takeName(BB);
+
+    // Clear the successor list of BB to match updates applying to DTU later.
+    if (BB->getTerminator())
+      BB->back().eraseFromParent();
+
+    new UnreachableInst(BB->getContext(), BB);
+    assert(succ_empty(BB) && "The successor list of BB isn't empty before "
+                             "applying corresponding DTU updates.");
+  } else if (BBPhisMergeable) {
+    //  Everything except CommonPred that jumped to BB now goes to Succ.
+    BB->replaceUsesWithIf(Succ, [BBPreds, CommonPred](Use &U) -> bool {
+      if (Instruction *UseInst = dyn_cast<Instruction>(U.getUser()))
+        return UseInst->getParent() != CommonPred &&
+               BBPreds.contains(UseInst->getParent());
+      return false;
+    });
+  }
 
   if (DTU)
     DTU->applyUpdates(Updates);
 
-  DeleteDeadBlock(BB, DTU);
+  if (BBKillable)
+    DeleteDeadBlock(BB, DTU);
 
   return true;
 }
diff --git a/llvm/test/CodeGen/ARM/jump-table-islands.ll b/llvm/test/CodeGen/ARM/jump-table-islands.ll
index c327affc04539b3..e774930bd2bb0b9 100644
--- a/llvm/test/CodeGen/ARM/jump-table-islands.ll
+++ b/llvm/test/CodeGen/ARM/jump-table-islands.ll
@@ -2,6 +2,8 @@
 
 %BigInt = type i8500
 
+declare void @use(%BigInt)
+
 define %BigInt @test_moved_jumptable(i1 %tst, i32 %sw, %BigInt %l) {
 ; CHECK-LABEL: test_moved_jumptable:
 
@@ -34,6 +36,8 @@ other:
 
 end:
   %val = phi %BigInt [ %l, %complex ], [ -1, %simple ]
+; Prevent SimplifyCFG from simplifying the phi node above.
+  call void @use(%BigInt %val)
   ret %BigInt %val
 }
 
diff --git a/llvm/test/Transforms/JumpThreading/codesize-loop.ll b/llvm/test/Transforms/JumpThreading/codesize-loop.ll
index a1a2b1dfd15edb2..f01c149ac45a396 100644
--- a/llvm/test/Transforms/JumpThreading/codesize-loop.ll
+++ b/llvm/test/Transforms/JumpThreading/codesize-loop.ll
@@ -42,16 +42,14 @@ define i32 @test_minsize(i32 %argc, ptr nocapture readonly %argv) local_unnamed_
 ; OVERIDE-NEXT:    [[TMP3:%.*]] = mul i32 [[CALL]], [[TMP2]]
 ; OVERIDE-NEXT:    [[TMP4:%.*]] = icmp sgt i32 [[CALL]], 0
 ; OVERIDE-NEXT:    [[COND_FR:%.*]] = freeze i1 [[TMP4]]
-; OVERIDE-NEXT:    br i1 [[COND_FR]], label [[COND_END_THREAD]], label [[TMP6:%.*]]
+; OVERIDE-NEXT:    br i1 [[COND_FR]], label [[TMP5:%.*]], label [[COND_END_THREAD]]
+; OVERIDE:       5:
+; OVERIDE-NEXT:    br label [[COND_END_THREAD]]
 ; OVERIDE:       cond.end.thread:
-; OVERIDE-NEXT:    [[TMP5:%.*]] = phi i32 [ [[TMP3]], [[COND_END]] ], [ 205962976, [[ENTRY:%.*]] ]
-; OVERIDE-NEXT:    [[COND3:%.*]] = phi i32 [ [[CALL]], [[COND_END]] ], [ 46, [[ENTRY]] ]
-; OVERIDE-NEXT:    br label [[TMP6]]
-; OVERIDE:       6:
-; OVERIDE-NEXT:    [[TMP7:%.*]] = phi i32 [ [[TMP5]], [[COND_END_THREAD]] ], [ [[TMP3]], [[COND_END]] ]
-; OVERIDE-NEXT:    [[TMP8:%.*]] = phi i32 [ [[COND3]], [[COND_END_THREAD]] ], [ 0, [[COND_END]] ]
-; OVERIDE-NEXT:    [[TMP9:%.*]] = mul i32 [[TMP7]], [[TMP8]]
-; OVERIDE-NEXT:    [[CALL33:%.*]] = tail call i32 (ptr, ...) @printf(ptr nonnull dereferenceable(1) @.str, i32 [[TMP9]])
+; OVERIDE-NEXT:    [[TMP6:%.*]] = phi i32 [ [[TMP3]], [[COND_END]] ], [ [[TMP3]], [[TMP5]] ], [ 205962976, [[ENTRY:%.*]] ]
+; OVERIDE-NEXT:    [[TMP7:%.*]] = phi i32 [ 0, [[COND_END]] ], [ [[CALL]], [[TMP5]] ], [ 46, [[ENTRY]] ]
+; OVERIDE-NEXT:    [[TMP8:%.*]] = mul i32 [[TMP6]], [[TMP7]]
+; OVERIDE-NEXT:    [[CALL33:%.*]] = tail call i32 (ptr, ...) @printf(ptr nonnull dereferenceable(1) @.str, i32 [[TMP8]])
 ; OVERIDE-NEXT:    ret i32 0
 ;
 entry:
@@ -90,16 +88,14 @@ define i32 @test_optsize(i32 %argc, ptr nocapture readonly %argv) local_unnamed_
 ; DEFAULT-NEXT:    [[TMP3:%.*]] = mul i32 [[CALL]], [[TMP2]]
 ; DEFAULT-NEXT:    [[TMP4:%.*]] = icmp sgt i32 [[CALL]], 0
 ; DEFAULT-NEXT:    [[COND_FR:%.*]] = freeze i1 [[TMP4]]
-; DEFAULT-NEXT:    br i1 [[COND_FR]], label [[COND_END_THREAD]], label [[TMP6:%.*]]
+; DEFAULT-NEXT:    br i1 [[COND_FR]], label [[TMP5:%.*]], label [[COND_END_THREAD]]
+; DEFAULT:       5:
+; DEFAULT-NEXT:    br label [[COND_END_THREAD]]
 ; DEFAULT:       cond.end.thread:
-; DEFAULT-NEXT:    [[TMP5:%.*]] = phi i32 [ [[TMP3]], [[COND_END]] ], [ 205962976, [[ENTRY:%.*]] ]
-; DEFAULT-NEXT:    [[COND3:%.*]] = phi i32 [ [[CALL]], [[COND_END]] ], [ 46, [[ENTRY]] ]
-; DEFAULT-NEXT:    br label [[TMP6]]
-; DEFAULT:       6:
-; DEFAULT-NEXT:    [[TMP7:%.*]] = phi i32 [ [[TMP5]], [[COND_END_THREAD]] ], [ [[TMP3]], [[COND_END]] ]
-; DEFAULT-NEXT:    [[TMP8:%.*]] = phi i32 [ [[COND3]], [[COND_END_THREAD]] ], [ 0, [[COND_END]] ]
-; DEFAULT-NEXT:    [[TMP9:%.*]] = mul i32 [[TMP7]], [[TMP8]]
-; DEFAULT-NEXT:    [[CALL33:%.*]] = tail call i32 (ptr, ...) @printf(ptr nonnull dereferenceable(1) @.str, i32 [[TMP9]])
+; DEFAULT-NEXT:    [[TMP6:%.*]] = phi i32 [ [[TMP3]], [[COND_END]] ], [ [[TMP3]], [[TMP5]] ], [ 205962976, [[ENTRY:%.*]] ]
+; DEFAULT-NEXT:    [[TMP7:%.*]] = phi i32 [ 0, [[COND_END]] ], [ [[CALL]], [[TMP5]] ], [ 46, [[ENTRY]] ]
+; DEFAULT-NEXT:    [[TMP8:%.*]] = mul i32 [[TMP6]], [[TMP7]]
+; DEFAULT-NEXT:    [[CALL33:%.*]] = tail call i32 (ptr, ...) @printf(ptr nonnull dereferenceable(1) @.str, i32 [[TMP8]])
 ; DEFAULT-NEXT:    ret i32 0
 ;
 ; OVERIDE-LABEL: @test_optsize(
@@ -115,16 +111,14 @@ define i32 @test_optsize(i32 %argc, ptr nocapture readonly %argv) local_unnamed_
 ; OVERIDE-NEXT:    [[TMP3:%.*]] = mul i32 [[CALL]], [[TMP2]]
 ; OVERIDE-NEXT:    [[TMP4:%.*]] = icmp sgt i32 [[CALL]], 0
 ; OVERIDE-NEXT:    [[COND_FR:%.*]] = freeze i1 [[TMP4]]
-; OVERIDE-NEXT:    br i1 [[COND_FR]], label [[COND_END_THREAD]], label [[TMP6:%.*]]
+; OVERIDE-NEXT:    br i1 [[COND_FR]], label [[TMP5:%.*]], label [[COND_END_THREAD]]
+; OVERIDE:       5:
+; OVERIDE-NEXT:    br label [[COND_END_THREAD]]
 ; OVERIDE:       cond.end.thread:
-; OVERIDE-NEXT:    [[TMP5:%.*]] = phi i32 [ [[TMP3]], [[COND_END]] ], [ 205962976, [[ENTRY:%.*]] ]
-; OVERIDE-NEXT:    [[COND3:%.*]] = phi i32 [ [[CALL]], [[COND_END]] ], [ 46, [[ENTRY]] ]
-; OVERIDE-NEXT:    br label [[TMP6]]
-; OVERIDE:       6:
-; OVERIDE-NEXT:    [[TMP7:%.*]] = phi i32 [ [[TMP5]], [[COND_END_THREAD]] ], [ [[TMP3]], [[COND_END]] ]
-; OVERIDE-NEXT:    [[TMP8:%.*]] = phi i32 [ [[COND3]], [[COND_END_THREAD]] ], [ 0, [[COND_END]] ]
-; OVERIDE-NEXT:    [[TMP9:%.*]] = mul i32 [[TMP7]], [[TMP8]]
-; OVERIDE-NEXT:    [[CALL33:%.*]] = tail call i32 (ptr, ...) @printf(ptr nonnull dereferenceable(1) @.str, i32 [[TMP9]])
+; OVERIDE-NEXT:    [[TMP6:%.*]] = phi i32 [ [[TMP3]], [[COND_END]] ], [ [[TMP3]], [[TMP5]] ], [ 205962976, [[ENTRY:%.*]] ]
+; OVERIDE-NEXT:    [[TMP7:%.*]] = phi i32 [ 0, [[COND_END]] ], [ [[CALL]], [[TMP5]] ], [ 46, [[ENTRY]] ]
+; OVERIDE-NEXT:    [[TMP8:%.*]] = mul i32 [[TMP6]], [[TMP7]]
+; OVERIDE-NEXT:    [[CALL33:%.*]] = tail call i32 (ptr, ...) @printf(ptr nonnull dereferenceable(1) @.str, i32 [[TMP8]])
 ; OVERIDE-NEXT:    ret i32 0
 ;
 entry:
diff --git a/llvm/test/Transforms/SimplifyCFG/branch-fold.ll b/llvm/test/Transforms/SimplifyCFG/branch-fold.ll
index 026891f6f662ef8..2f5fb4f33013d2e 100644
--- a/llvm/test/Transforms/SimplifyCFG/branch-fold.ll
+++ b/llvm/test/Transforms/SimplifyCFG/branch-fold.ll
@@ -119,15 +119,13 @@ define i8 @common_pred(i8 noundef %arg, i1 %c1, i1 %c2) {
 ; CHECK-LABEL: @common_pred(
 ; CHECK-NEXT:  Pred:
 ; CHECK-NEXT:    call void @dummy()
-; CHECK-NEXT:    br i1 [[C1:%.*]], label [[COMMONPRED:%.*]], label [[BB:%.*]]
+; CHECK-NEXT:    br i1 [[C1:%.*]], label [[COMMONPRED:%.*]], label [[SUCC:%.*]]
 ; CHECK:       CommonPred:
 ; CHECK-NEXT:    call void @dummy()
-; CHECK-NEXT:    br i1 [[C2:%.*]], label [[SUCC:%.*]], label [[BB]]
-; CHECK:       BB:
-; CHECK-NEXT:    [[PHI1:%.*]] = phi i8 [ 0, [[PRED:%.*]] ], [ 1, [[COMMONPRED]] ]
+; CHECK-NEXT:    [[SPEC_SELECT:%.*]] = select i1 [[C2:%.*]], i8 4, i8 1
 ; CHECK-NEXT:    br label [[SUCC]]
 ; CHECK:       Succ:
-; CHECK-NEXT:    [[PHI2:%.*]] = phi i8 [ [[PHI1]], [[BB]] ], [ 4, [[COMMONPRED]] ]
+; CHECK-NEXT:    [[PHI2:%.*]] = phi i8 [ 0, [[PRED:%.*]] ], [ [[SPEC_SELECT]], [[COMMONPRED]] ]
 ; CHECK-NEXT:    ret i8 [[PHI2]]
 ;
 Pred:
diff --git a/llvm/test/Transforms/SimplifyCFG/merge-phis-in-switch.ll b/llvm/test/Transforms/SimplifyCFG/merge-phis-in-switch.ll
index e5aefef0271ea6b..0ffa53a5c9e1049 100644
--- a/llvm/test/Transforms/SimplifyCFG/merge-phis-in-switch.ll
+++ b/llvm/test/Transforms/SimplifyCFG/merge-phis-in-switch.ll
@@ -17,12 +17,11 @@ define i8 @phis_of_switch_minimal(i8 noundef %arg) {
 ; CHECK:       unreachable:
 ; CHECK-NEXT:    unreachable
 ; CHECK:       case1:
-; CHECK-NEXT:    br label [[CASE01]]
+; CHECK-NEXT:    br label [[END]]
 ; CHECK:       case01:
-; CHECK-NEXT:    [[PHI1:%.*]] = phi i8 [ 2, [[CASE1]] ], [ 1, [[START:%.*]] ]
 ; CHECK-NEXT:    br label [[END]]
 ; CHECK:       end:
-; CHECK-NEXT:    [[PHI2:%.*]] = phi i8 [ [[PHI1]], [[CASE01]] ], [ 3, [[START]] ]
+; CHECK-NEXT:    [[PHI2:%.*]] = phi i8 [ 3, [[START:%.*]] ], [ 2, [[CASE1]] ], [ 1, [[CASE01]] ]
 ; CHECK-NEXT:    ret i8 [[PHI2]]
 ;
 start:
@@ -58,14 +57,13 @@ define i8 @phis_of_switch(i8 noundef %arg) {
 ; CHECK:       unreachable:
 ; CHECK-NEXT:    unreachable
 ; CHECK:       case1:
-; CHECK-NEXT:    br label [[CASE012]]
+; CHECK-NEXT:    br label [[END]]
 ; CHECK:       case2:
-; CHECK-NEXT:    br label [[CASE012]]
+; CHECK-NEXT:    br label [[END]]
 ; CHECK:       case012:
-; CHECK-NEXT:    [[PHI1:%.*]] = phi i8 [ 3, [[CASE2]] ], [ 2, [[CASE1]] ], [ 1, [[START:%.*]] ]
 ; CHECK-NEXT:    br label [[END]]
 ; CHECK:       end:
-; CHECK-NEXT:    [[PHI2:%.*]] = phi i8 [ [[PHI1]], [[CASE012]] ], [ 4, [[START]] ]
+; CHECK-NEXT:    [[PHI2:%.*]] = phi i8 [ 4, [[START:%.*]] ], [ 3, [[CASE2]] ], [ 2, [[CASE1]] ], [ 1, [[CASE012]] ]
 ; CHECK-NEXT:    ret i8 [[PHI2]]
 ;
 start:
@@ -105,17 +103,15 @@ define i8 @multiple_phis_of_switch(i8 noundef %arg) {
 ; CHECK:       unreachable:
 ; CHECK-NEXT:    unreachable
 ; CHECK:       case1:
-; CHECK-NEXT:    br label [[CASE012]]
+; CHECK-NEXT:    br label [[END]]
 ; CHECK:       case2:
-; CHECK-NEXT:    br label [[CASE012]]
+; CHECK-NEXT:    br label [[END]]
 ; CHECK:       case012:
-; CHECK-NEXT:    [[PHI1_1:%.*]] = phi i8 [ 3, [[CASE2]] ], [ 2, [[CASE1]] ], [ 1, [[START:%.*]] ]
-; CHECK-NEXT:    [[PHI1_2:%.*]] = phi i8 [ 6, [[CASE2]] ], [ 5, [[CASE1]] ], [ 4, [[START]] ]
 ; CHECK-NEXT:    br label [[END]]
 ; CHECK:       end:
-; CHECK-NEXT:    [[PHI2_1:%.*]] = phi i8 [ [[PHI1_1]], [[CASE012]] ], [ 4, [[START]] ]
-; CHECK-NEXT:    [[PHI2_2:%.*]] = phi i8 [ [[PHI1_1]], [[CASE012]] ], [ 5, [[START]] ]
-; CHECK-NEXT:    [[PHI2_3:%.*]] = phi i8 [ [[PHI1_2]], [[CASE012]] ], [ 3, [[START]] ]
+; CHECK-NEXT:    [[PHI2_1:%.*]] = phi i8 [ 4, [[START:%.*]] ], [ 3, [[CASE2]] ], [ 2, [[CASE1]] ], [ 1, [[CASE012]] ]
+; CHECK-NEXT:    [[PHI2_2:%.*]] = phi i8 [ 5, [[START]] ], [ 3, [[CASE2]] ], [ 2, [[CASE1]] ], [ 1, [[CASE012]] ]
+; CHECK-NEXT:    [[PHI2_3:%.*]] = phi i8 [ 3, [[START]] ], [ 6, [[CASE2]] ], [ 5, [[CASE1]] ], [ 4, [[CASE012]] ]
 ; CHECK-NEXT:    call void @use(i8 [[PHI2_1]])
 ; CHECK-NEXT:    call void @use(i8 [[PHI2_2]])
 ; CHECK-NEXT:    call void @use(i8 [[PHI2_3]])
@@ -166,19 +162,17 @@ define i8 @phis_of_switch_multiple_stage0(i8 noundef %arg) {
 ; CHECK:       unreachable:
 ; CHECK-NEXT:    unreachable
 ; CHECK:       case0:
-; CHECK-NEXT:    br label [[CASE0123]]
+; CHECK-NEXT:    br label [[END]]
 ; CHECK:       case1:
-; CHECK-NEXT:    br label [[CASE0123]]
+; CHECK-NEXT:    br label [[END]]
 ; CHECK:       case2:
-; CHECK-NEXT:    br label [[CASE0123]]
+; CHECK-NEXT:    br label [[END]]
 ; CHECK:       case0123:
-; CHECK-NEXT:    [[PHI1:%.*]] = phi i8 [ 4, [[START:%.*]] ], [ 3, [[CASE2]] ], [ 2, [[CASE1]] ], [ 1, [[CASE0]] ]
-; CHECK-NEXT:    br label [[CASE01234]]
+; CHECK-NEXT:    br label [[END]]
 ; CHECK:       case01234:
-; CHECK-NEXT:    [[PHI2:%.*]] = phi i8 [ [[PHI1]], [[CASE0123]] ], [ 5, [[START]] ]
 ; CHECK-NEXT:    br label [[END]]
 ; CHECK:       end:
-; CHECK-NEXT:    [[PHI3:%.*]] = phi i8 [ [[PHI2]], [[CASE01234]] ], [ 6, [[START]] ]
+; CHECK-NEXT:    [[PHI3:%.*]] = phi i8 [ 6, [[START:%.*]] ], [ 3, [[CASE2]] ], [ 2, [[CASE1]] ], [ 1, [[CASE0]] ], [ 4, [[CASE0123]] ], [ 5, [[CASE01234]] ]
 ; CHECK-NEXT:    ret i8 [[PHI3]]
 ;
 start:
@@ -231,21 +225,19 @@ define i8 @phis_of_switch_multiple_stage1(i8 noundef %arg) {
 ; CHECK:       unreachable:
 ; CHECK-NEXT:    unreachable
 ; CHECK:       case0:
-; CHECK-NEXT:    br label [[CASE012]]
+; CHECK-NEXT:    br label [[CASE0123456]]
 ; CHECK:       case1:
-; CHECK-NEXT:    br label [[CASE012]]
+; CHECK-NEXT:    br label [[CASE0123456]]
 ; CHECK:       case012:
-; CHECK-NEXT:    [[PHI123:%.*]] = phi i8 [ 3, [[START:%.*]] ], [ 2, [[CASE1]] ], [ 1, [[CASE0]] ]
 ; CHECK-NEXT:    br label [[CASE0123456]]
 ; CHECK:       case3:
-; CHECK-NEXT:    br label [[CASE345]]
+; CHECK-NEXT:    br label [[CASE0123456]]
 ; CHECK:       case4:
-; CHECK-NEXT:    br label [[CASE345]]
+; CHECK-NEXT:    br label [[CASE0123456]]
 ; CHECK:       case345:
-; CHECK-NEXT:    [[PHI456:%.*]] = phi i8 [ 6, [[START]] ], [ 5, [[CASE4]] ], [ 4, [[CASE3]] ]
 ; CHECK-NEXT:    br label [[CASE0123456]]
 ; CHECK:       case0123456:
-; CHECK-NEXT:    [[PHI1234567:%.*]] = phi i8 [ 7, [[START]] ], [ [[PHI456]], [[CASE345]] ], [ [[PHI123]], [[CASE012]] ]
+; CHECK-NEXT:    [[PHI1234567:%.*]] = phi i8 [ 7, [[START:%.*]] ], [ 2, [[CASE1]] ], [ 1, [[CASE0]] ], [ 3, [[CASE012]] ], [ 5, [[CASE4]] ], [ 4, [[CASE3]] ], [ 6, [[CASE345]] ]
 ; CHECK-NEXT:    ret i8 [[PHI1234567]]
 ;
 start:
diff --git a/llvm/test/Transforms/SimplifyCFG/multiple-phis.ll b/llvm/test/Transforms/SimplifyCFG/multiple-phis.ll
index 807aeec38db3d72..d63973eab71e474 100644
--- a/llvm/test/Transforms/SimplifyCFG/multiple-phis.ll
+++ b/llvm/test/Transforms/SimplifyCFG/multiple-phis.ll
@@ -63,17 +63,10 @@ while.end:                                        ; preds = %while.cond
 define i32 @merge0(i1 %c1, i1 %c2, i1 %c3) {
 ; CHECK-LABEL: define i32 @merge0
 ; CHECK-SAME: (i1 [[C1:%.*]], i1 [[C2:%.*]], i1 [[C3:%.*]]) {
-; CHECK-NEXT:    br i1 [[C1]], label [[IF1:%.*]], label [[ELSE1:%.*]]
-; CHECK:       if1:
+; CHECK-NEXT:  j2:
 ; CHECK-NEXT:    [[DOT:%.*]] = select i1 [[C2]], i32 0, i32 1
-; CHECK-NEXT:    br label [[J1:%.*]]
-; CHECK:       else1:
-; CHECK-NEXT:    br i1 [[C3]], label [[J1]], label [[J2:%.*]]
-; CHECK:       j1:
-; CHECK-NEXT:    [[PHI1:%.*]] = phi i32 [ 2, [[ELSE1]] ], [ [[DOT]], [[IF1]] ]
-; CHECK-NEXT:    br label [[J2]]
-; CHECK:       j2:
-; CHECK-NEXT:    [[PHI2:%.*]] = phi i32 [ [[PHI1]], [[J1]] ], [ 3, [[ELSE1]] ]
+; CHECK-NEXT:    [[SPEC_SELECT:%.*]] = select i1 [[C3]], i32 2, i32 3
+; CHECK-NEXT:    [[PHI2:%.*]] = select i1 [[C1]], i32 [[DOT]], i32 [[SPEC_SELECT]]
 ; CHECK-NEXT:    ret i32 [[PHI2]]
 ;
   br i1 %c1, label %if1, label %else1
@@ -103,7 +96,7 @@ define i8 @merge1(i8 noundef %arg, i1 %c1, i1 %c2) {
 ; CHECK-NEXT:  entry:
 ; CHECK-NEXT:    switch i8 [[ARG]], label [[UNREACHABLE:%.*]] [
 ; CHECK-NEXT:    i8 -123, label [[CASE0:%.*]]
-; CHECK-NEXT:    i8 66, label [[BB:%.*]]
+; CHECK-NEXT:    i8 66, label [[SUCC:%.*]]
 ; CHECK-NEXT:    i8 123, label [[CASE2:%.*]]
 ; CHECK-NEXT:    ]
 ; CHECK:       unreachable:
@@ -113,14 +106,12 @@ define i8 @merge1(i8 noundef %arg, i1 %c1, i1 %c2) {
 ; CHECK-NEXT:    [[C2_NOT:%.*]] = xor i1 [[C2]], true
 ; CHECK-NEXT:    [[BRMERGE:%.*]] = select i1 [[C1_NOT]], i1 true, i1 [[C2_NOT]]
 ; CHECK-NEXT:    [[DOTMUX:%.*]] = select i1 [[C1_NOT]], i8 0, i8 3
-; CHECK-NEXT:    br i1 [[BRMERGE]], label [[BB]], label [[SUCC:%.*]]
+; CHECK-NEXT:    [[SPEC_SELECT:%.*]] = select i1 [[BRMERGE]], i8 [[DOTMUX]], i8 4
+; CHECK-NEXT:    br label [[SUCC]]
 ; CHECK:       case2:
-; CHECK-NEXT:    br label [[BB]]
-; CHECK:       BB:
-; CHECK-NEXT:    [[PHI1:%.*]] = phi i8 [ [[DOTMUX]], [[CASE0]] ], [ 2, [[CASE2]] ], [ 1, [[ENTRY:%.*]] ]
 ; CHECK-NEXT:    br label [[SUCC]]
 ; CHECK:       Succ:
-; CHECK-NEXT:    [[PHI2:%.*]] = phi i8 [ [[PHI1]], [[BB]] ], [ 4, [[CASE0]] ]
+; CHECK-NEXT:    [[PHI2:%.*]] = phi i8 [ 2, [[CASE2]] ], [ 1, [[ENTRY:%.*]] ], [ [[SPEC_SELECT]], [[CASE0]] ]
 ; CHECK-NEXT:    ret i8 [[PHI2]]
 ;
 entry:
@@ -160,7 +151,7 @@ define i8 @merge1_unfoldable_one_block(i8 noundef %arg, i1 %c1, i1 %c2) {
 ; CHECK-NEXT:  entry:
 ; CHECK-NEXT:    switch i8 [[ARG]], label [[UNREACHABLE:%.*]] [
 ; CHECK-NEXT:    i8 -123, label [[CASE0:%.*]]
-; CHECK-NEXT:    i8 66, label [[BB:%.*]]
+; CHECK-NEXT:    i8 66, label [[SUCC:%.*]]
 ; CHECK-NEXT:    i8 123, label [[CASE2:%.*]]
 ; CHECK-NEXT:    ]
 ; CHECK:       unreachable:
@@ -171,14 +162,12 @@ define i8 @merge1_unfoldable_one_block(i8 noundef %arg, i1 %c1, i1 %c2) {
 ; CHECK-NEXT:    [[C2_NOT:%.*]] = xor i1 [[C2]], true
 ; CHECK-NEXT:    [[BRMERGE:%.*]] = select i1 [[C1_NOT]], i1 true, i1 [[C2_NOT]]
 ; CHECK-NEXT:    [[DOTMUX:%.*]] = select i1 [[C1_NOT]], i8 0, i8 3
-; CHECK-NEXT:    br i1 [[BRMERGE]], label [[BB]], label [[SUCC:%.*]]
+; CHECK-NEXT:    [[SPEC_SELECT:%.*]] = select i1 [[BRMERGE]], i8 [[DOTMUX]], i8 4
+; CHECK-NEXT:    br label [[SUCC]]
 ; CHECK:       case2:
-; CHECK-NEXT:    br label [[BB]]
-; CHECK:       BB:
-; CHECK-NEXT:    [[PHI1:%.*]] = phi i8 [ [[DOTMUX]], [[CASE0]] ], [ 2, [[CASE2]] ], [ 1, [[ENTRY:%.*]] ]
 ; CHECK-NEXT:    br label [[SUCC]]
 ; CHECK:       Succ:
-; CHECK-NEXT:    [[PHI2:%.*]] = phi i8 [ [[PHI1]], [[BB]] ], [ 4, [[CASE0]] ]
+; CHECK-NEXT:    [[PHI2:%.*]] = phi i8 [ 2, [[CASE2]] ], [ 1, [[ENTRY:%.*]] ], [ [[SPEC_SELECT]], [[CASE0]] ]
 ; CHECK-NEXT:    ret i8 [[PHI2]]
 ;
 entry:
@@ -220,7 +209,7 @@ define i8 @merge1_unfoldable_two_block(i8 noundef %arg, i1 %c1, i1 %c2) {
 ; CHECK-NEXT:    switch i8 [[ARG]], label [[UNREACHABLE:%.*]] [
 ; CHECK-NEXT:    i8 -123, label [[CASE0:%.*]]
 ; CHECK-NEXT:    i8 66, label [[CASE1:%.*]]
-; CHECK-NEXT:    i8 123, label [[BB:%.*]]
+; CHECK-NEXT:    i8 123, label [[SUCC:%.*]]
 ; CHECK-NEXT:    ]
 ; CHECK:       unreachable:
 ; CHECK-NEXT:    unreachable
@@ -230,15 +219,13 @@ define i8 @merge1_unfoldable_two_block(i8 noundef %arg, i1 %c1, i1 %c2) {
 ; CHECK-NEXT:    [[C2_NOT:%.*]] = xor i1 [[C2]], true
 ; CHECK-NEXT:    [[BRMERGE:%.*]] = select i1 [[C1_NOT]], i1 true, i1 [[C2_NOT]]
 ; CHECK-NEXT:    [[DOTMUX:%.*]] = select i1 [[C1_NOT]], i8 0, i8 3
-; CHECK-NEXT:    br i1 [[BRMERGE]], label [[BB]], label [[SUCC:%.*]]
+; CHECK-NEXT:    [[SPEC_SELECT:%.*]] = select i1 [[BRMERGE]], i8 [[DOTMUX]], i8 4
+; CHECK-NEXT:    br label [[SUCC]]
 ; CHECK:       case1:
 ; CHECK-NEXT:    call void @dummy()
-; CHECK-NEXT:    br label [[BB]]
-; CHECK:       BB:
-; CHECK-NEXT:    [[PHI1:%.*]] = phi i8 [ [[DOTMUX]], [[CASE0]] ], [ 1, [[CASE1]] ], [ 2, [[ENTRY:%.*]] ]
 ; CHECK-NEXT:    br label [[SUCC]]
 ; CHECK:       Succ:
-; CHECK-NEXT:    [[PHI2:%.*]] = phi i8 [ [[PHI1]], [[BB]] ], [ 4, [[CASE0]] ]
+; CHECK-NEXT:    [[PHI2:%.*]] = phi i8 [ 1, [[CASE1]] ], [ 2, [[ENTRY:%.*]] ], [ [[SPEC_SELECT]], [[CASE0]] ]
 ; CHECK-NEXT:    ret i8 [[PHI2]]
 ;
 entry:
@@ -287,21 +274,19 @@ define i8 @merge1_unfoldable_all_block(i8 noundef %arg, i1 %c1, i1 %c2) {
 ; CHECK-NEXT:    unreachable
 ; CHECK:       case0:
 ; CHECK-NEXT:    call void @dummy()
-; CHECK-NEXT:    br i1 [[C1]], label [[COMMONPRED:%.*]], label [[BB:%.*]]
+; CHECK-NEXT:    br i1 [[C1]], label [[COMMONPRED:%.*]], label [[SUCC:%.*]]
 ; CHECK:       case1:
 ; CHECK-NEXT:    call void @dummy()
-; CHECK-NEXT:    br label [[BB]]
+; CHECK-NEXT:    br label [[SUCC]]
 ; CHECK:       case2:
 ; CHECK-NEXT:    call void @dummy()
-; CHECK-NEXT:    br label [[BB]]
+; CHECK-NEXT:    br label [[SUCC]]
 ; CHECK:       CommonPred:
 ; CHECK-NEXT:    call void @dummy()
-; CHECK-NEXT:    br i1 [[C2]], label [[SUCC:%.*]], label [[BB]]
-; CHECK:       BB:
-; CHECK-NEXT:    [[PHI1:%.*]] = phi i8 [ 0, [[CASE0]] ], [ 1, [[CASE1]] ], [ 2, [[CASE2]] ], [ 3, [[COMMONPRED]] ]
+; CHECK-NEXT:    [[SPEC_SELECT:%.*]] = select i1 [[C2]], i8 4, i8 3
 ; CHECK-NEXT:    br label [[SUCC]]
 ; CHECK:       Succ:
-; CHECK-NEXT:    [[PHI2:%.*]] = phi i8 [ [[PHI1]], [[BB]] ], [ 4, [[COMMONPRED]] ]
+; CHECK-NEXT:    [[PHI2:%.*]] = phi i8 [ 0, [[CASE0]] ], [ 1, [[CASE1]] ], [ 2, [[CASE2]] ], [ [[SPEC_SELECT]], [[COMMONPRED]] ]
 ; CHECK-NEXT:    ret i8 [[PHI2]]
 ;
 entry:
diff --git a/llvm/test/Transforms/SimplifyCFG/switch-simplify-crash2.ll b/llvm/test/Transforms/SimplifyCFG/switch-simplify-crash2.ll
index eb0947397a6992b..63985ec565bb9ef 100644
--- a/llvm/test/Transforms/SimplifyCFG/switch-simplify-crash2.ll
+++ b/llvm/test/Transforms/SimplifyCFG/switch-simplify-crash2.ll
@@ -6,6 +6,9 @@ define i8 @test() {
 ; CHECK-NEXT:  entry:
 ; CHECK-NEXT:    br label [[LOOP2:%.*]]
 ; CHECK:       loop2:
+; CHECK-NEXT:    [[PHI2:%.*]] = phi i8 [ 0, [[ENTRY:%.*]] ], [ [[SPEC_SELECT:%.*]], [[LOOP2]] ]
+; CHECK-NEXT:    [[COND:%.*]] = icmp eq i8 [[PHI2]], 0
+; CHECK-NEXT:    [[SPEC_SELECT]] = select i1 [[COND]], i8 0, i8 [[PHI2]]
 ; CHECK-NEXT:    br label [[LOOP2]]
 ;
 entry:



More information about the llvm-commits mailing list