[llvm] [SimplifyCFG] Convert switch to cmp/select sequence (PR #82795)

Acim Maravic via llvm-commits llvm-commits at lists.llvm.org
Thu May 30 05:06:30 PDT 2024


https://github.com/Acim-Maravic updated https://github.com/llvm/llvm-project/pull/82795

>From 25e94349e67efb7448a9dae2af0f544aa030dac7 Mon Sep 17 00:00:00 2001
From: Acim Maravic <acim.maravic at syrmia.com>
Date: Thu, 23 May 2024 13:52:37 +0200
Subject: [PATCH 1/2] [NFC][SimplifyCFG] Convert switch to cmp/select sequence

Added tests that will show changes
---
 .../SimplifyCFG/switch-to-select.ll           | 319 ++++++++++++++++++
 1 file changed, 319 insertions(+)
 create mode 100644 llvm/test/Transforms/SimplifyCFG/switch-to-select.ll

diff --git a/llvm/test/Transforms/SimplifyCFG/switch-to-select.ll b/llvm/test/Transforms/SimplifyCFG/switch-to-select.ll
new file mode 100644
index 0000000000000..c431d18b072f9
--- /dev/null
+++ b/llvm/test/Transforms/SimplifyCFG/switch-to-select.ll
@@ -0,0 +1,319 @@
+; NOTE: Assertions have been autogenerated by utils/update_test_checks.py
+; RUN: opt -S -passes=simplifycfg < %s | FileCheck -check-prefix=ALL %s
+
+define float @constant_single_PHInode(i32 %a, i32 %b, float %c, float %d) {
+; ALL-LABEL: @constant_single_PHInode(
+; ALL-NEXT:  .entry:
+; ALL-NEXT:    [[TMP0:%.*]] = icmp eq i32 [[A:%.*]], 1
+; ALL-NEXT:    br i1 [[TMP0]], label [[SW:%.*]], label [[RETURN:%.*]]
+; ALL:       sw:
+; ALL-NEXT:    [[SCALE_I0:%.*]] = fmul reassoc nnan nsz arcp contract afn float [[C:%.*]], 2.000000e+00
+; ALL-NEXT:    [[DOTI0:%.*]] = fadd reassoc nnan nsz arcp contract afn float [[SCALE_I0]], -1.000000e+00
+; ALL-NEXT:    [[DOTI1:%.*]] = fadd reassoc nnan nsz arcp contract afn float [[D:%.*]], -3.000000e+00
+; ALL-NEXT:    switch i32 [[B:%.*]], label [[RETURN]] [
+; ALL-NEXT:      i32 0, label [[SW_BB1:%.*]]
+; ALL-NEXT:      i32 1, label [[SW_BB2:%.*]]
+; ALL-NEXT:      i32 2, label [[SW_BB3:%.*]]
+; ALL-NEXT:      i32 3, label [[SW_BB4:%.*]]
+; ALL-NEXT:    ]
+; ALL:       sw.bb1:
+; ALL-NEXT:    br label [[RETURN]]
+; ALL:       sw.bb2:
+; ALL-NEXT:    br label [[RETURN]]
+; ALL:       sw.bb3:
+; ALL-NEXT:    [[TMP1:%.*]] = fneg reassoc nnan nsz arcp contract afn float [[DOTI0]]
+; ALL-NEXT:    br label [[RETURN]]
+; ALL:       sw.bb4:
+; ALL-NEXT:    br label [[RETURN]]
+; ALL:       return:
+; ALL-NEXT:    [[SAMPLEPOS_1_I0:%.*]] = phi float [ 0.000000e+00, [[DOTENTRY:%.*]] ], [ -5.000000e+00, [[SW_BB4]] ], [ -1.000000e+00, [[SW_BB3]] ], [ 7.000000e+00, [[SW_BB2]] ], [ 1.000000e+00, [[SW_BB1]] ], [ 4.000000e+00, [[SW]] ]
+; ALL-NEXT:    ret float [[SAMPLEPOS_1_I0]]
+;
+.entry:
+  %5 = icmp eq i32 %a, 1
+  br i1 %5, label %sw, label %return
+
+sw:
+  %scale.i0 = fmul reassoc nnan nsz arcp contract afn float %c, 2.000000e+00
+  %.i0 = fadd reassoc nnan nsz arcp contract afn float %scale.i0, -1.000000e+00
+  %.i1 = fadd reassoc nnan nsz arcp contract afn float %d, -3.000000e+00
+  switch i32 %b, label %return [
+  i32 0, label %sw.bb1
+  i32 1, label %sw.bb2
+  i32 2, label %sw.bb3
+  i32 3, label %sw.bb4
+  ]
+sw.bb1:                                               ; preds = %sw
+  br label %return
+
+sw.bb2:                                               ; preds = %sw
+  br label %return
+
+sw.bb3:                                               ; preds = %sw
+  %18 = fneg reassoc nnan nsz arcp contract afn float %.i0
+  br label %return
+
+sw.bb4:                                               ; preds = %sw
+  br label %return
+
+return:                                               ; preds = %sw.bb1, %sw.bb2, %sw.bb3, %sw.bb4, %sw, %.entry
+  %samplePos.1.i0 = phi float [ 0.000000e+00, %.entry ], [ -5.000000e+00, %sw.bb4 ], [ -1.000000e+00, %sw.bb3 ], [ 7.000000e+00, %sw.bb2 ], [ 1.000000e+00, %sw.bb1 ], [ 4.000000e+00, %sw ]
+  ret float %samplePos.1.i0
+}
+
+
+define float @constant_multiple_PHInode(i32 %a, i32 %b, float %c, float %d) {
+; ALL-LABEL: @constant_multiple_PHInode(
+; ALL-NEXT:  .entry:
+; ALL-NEXT:    [[TMP0:%.*]] = icmp eq i32 [[A:%.*]], 1
+; ALL-NEXT:    br i1 [[TMP0]], label [[SW:%.*]], label [[RETURN:%.*]]
+; ALL:       sw:
+; ALL-NEXT:    [[SCALE_I0:%.*]] = fmul reassoc nnan nsz arcp contract afn float [[C:%.*]], 2.000000e+00
+; ALL-NEXT:    [[DOTI0:%.*]] = fadd reassoc nnan nsz arcp contract afn float [[SCALE_I0]], -1.000000e+00
+; ALL-NEXT:    [[DOTI1:%.*]] = fadd reassoc nnan nsz arcp contract afn float [[D:%.*]], -3.000000e+00
+; ALL-NEXT:    switch i32 [[B:%.*]], label [[RETURN]] [
+; ALL-NEXT:      i32 0, label [[SW_BB1:%.*]]
+; ALL-NEXT:      i32 1, label [[SW_BB2:%.*]]
+; ALL-NEXT:      i32 2, label [[SW_BB3:%.*]]
+; ALL-NEXT:    ]
+; ALL:       sw.bb1:
+; ALL-NEXT:    br label [[RETURN]]
+; ALL:       sw.bb2:
+; ALL-NEXT:    br label [[RETURN]]
+; ALL:       sw.bb3:
+; ALL-NEXT:    br label [[RETURN]]
+; ALL:       return:
+; ALL-NEXT:    [[SAMPLEPOS_1_I0:%.*]] = phi float [ 0.000000e+00, [[DOTENTRY:%.*]] ], [ 3.000000e+00, [[SW_BB3]] ], [ 2.000000e+00, [[SW_BB2]] ], [ 1.000000e+00, [[SW_BB1]] ], [ 4.000000e+00, [[SW]] ]
+; ALL-NEXT:    [[SAMPLEPOS_1_I1:%.*]] = phi float [ 0.000000e+00, [[DOTENTRY]] ], [ -3.000000e+00, [[SW_BB3]] ], [ -2.000000e+00, [[SW_BB2]] ], [ -1.000000e+00, [[SW_BB1]] ], [ -4.000000e+00, [[SW]] ]
+; ALL-NEXT:    [[SAMPLEPOS_1_I2:%.*]] = phi float [ 0.000000e+00, [[DOTENTRY]] ], [ -3.000000e+00, [[SW_BB3]] ], [ 2.000000e+00, [[SW_BB2]] ], [ -1.000000e+00, [[SW_BB1]] ], [ 4.000000e+00, [[SW]] ]
+; ALL-NEXT:    [[RETVAL1:%.*]] = fadd float [[SAMPLEPOS_1_I0]], [[SAMPLEPOS_1_I1]]
+; ALL-NEXT:    [[RETVAL:%.*]] = fadd float [[RETVAL1]], [[SAMPLEPOS_1_I2]]
+; ALL-NEXT:    ret float [[RETVAL]]
+;
+.entry:
+  %5 = icmp eq i32 %a, 1
+  br i1 %5, label %sw, label %return
+
+sw:
+  %scale.i0 = fmul reassoc nnan nsz arcp contract afn float %c, 2.000000e+00
+  %.i0 = fadd reassoc nnan nsz arcp contract afn float %scale.i0, -1.000000e+00
+  %.i1 = fadd reassoc nnan nsz arcp contract afn float %d, -3.000000e+00
+  switch i32 %b, label %return [
+  i32 0, label %sw.bb1
+  i32 1, label %sw.bb2
+  i32 2, label %sw.bb3
+  i32 3, label %sw.bb4
+  ]
+sw.bb1:                                               ; preds = %sw
+  br label %return
+
+sw.bb2:                                               ; preds = %sw
+  br label %return
+
+sw.bb3:                                               ; preds = %sw
+  br label %return
+
+sw.bb4:                                               ; preds = %sw
+  br label %return
+
+return:                                               ; preds = %sw.bb1, %sw.bb2, %sw.bb3, %sw.bb4, %sw, %.entry
+  %samplePos.1.i0 = phi float [ 0.000000e+00, %.entry ], [ 4.000000e+00, %sw.bb4 ], [ 3.000000e+00, %sw.bb3 ], [ 2.000000e+00, %sw.bb2 ], [ 1.000000e+00, %sw.bb1 ], [ 4.000000e+00, %sw ]
+  %samplePos.1.i1 = phi float [ 0.000000e+00, %.entry ], [ -4.000000e+00, %sw.bb4 ], [ -3.000000e+00, %sw.bb3 ], [ -2.000000e+00, %sw.bb2 ], [ -1.000000e+00, %sw.bb1 ], [ -4.000000e+00, %sw ]
+  %samplePos.1.i2 = phi float [ 0.000000e+00, %.entry ], [ 4.000000e+00, %sw.bb4 ], [ -3.000000e+00, %sw.bb3 ], [ 2.000000e+00, %sw.bb2 ], [ -1.000000e+00, %sw.bb1 ], [ 4.000000e+00, %sw ]
+  %retVal1 = fadd float %samplePos.1.i0, %samplePos.1.i1
+  %retVal = fadd float %retVal1, %samplePos.1.i2
+  ret float %retVal
+}
+
+define float @partial_constant_single_PHInode(i32 %a, i32 %b, float %c, float %d) {
+; ALL-LABEL: @partial_constant_single_PHInode(
+; ALL-NEXT:  .entry:
+; ALL-NEXT:    [[TMP0:%.*]] = icmp eq i32 [[A:%.*]], 1
+; ALL-NEXT:    br i1 [[TMP0]], label [[SW:%.*]], label [[RETURN:%.*]]
+; ALL:       sw:
+; ALL-NEXT:    [[SCALE_I0:%.*]] = fmul reassoc nnan nsz arcp contract afn float [[C:%.*]], 2.000000e+00
+; ALL-NEXT:    [[DOTI0:%.*]] = fadd reassoc nnan nsz arcp contract afn float [[SCALE_I0]], -1.000000e+00
+; ALL-NEXT:    [[DOTI1:%.*]] = fadd reassoc nnan nsz arcp contract afn float [[D:%.*]], -3.000000e+00
+; ALL-NEXT:    switch i32 [[B:%.*]], label [[RETURN]] [
+; ALL-NEXT:      i32 0, label [[SW_BB1:%.*]]
+; ALL-NEXT:      i32 1, label [[SW_BB2:%.*]]
+; ALL-NEXT:      i32 2, label [[SW_BB3:%.*]]
+; ALL-NEXT:      i32 3, label [[SW_BB4:%.*]]
+; ALL-NEXT:    ]
+; ALL:       sw.bb1:
+; ALL-NEXT:    br label [[RETURN]]
+; ALL:       sw.bb2:
+; ALL-NEXT:    br label [[RETURN]]
+; ALL:       sw.bb3:
+; ALL-NEXT:    [[TMP1:%.*]] = fneg reassoc nnan nsz arcp contract afn float [[DOTI0]]
+; ALL-NEXT:    br label [[RETURN]]
+; ALL:       sw.bb4:
+; ALL-NEXT:    [[TMP2:%.*]] = fneg reassoc nnan nsz arcp contract afn float [[DOTI0]]
+; ALL-NEXT:    br label [[RETURN]]
+; ALL:       return:
+; ALL-NEXT:    [[SAMPLEPOS_1_I0:%.*]] = phi float [ 0.000000e+00, [[DOTENTRY:%.*]] ], [ [[TMP2]], [[SW_BB4]] ], [ -1.000000e+00, [[SW_BB3]] ], [ [[DOTI0]], [[SW_BB2]] ], [ 1.000000e+00, [[SW_BB1]] ], [ 4.000000e+00, [[SW]] ]
+; ALL-NEXT:    ret float [[SAMPLEPOS_1_I0]]
+;
+.entry:
+  %5 = icmp eq i32 %a, 1
+  br i1 %5, label %sw, label %return
+
+sw:
+  %scale.i0 = fmul reassoc nnan nsz arcp contract afn float %c, 2.000000e+00
+  %.i0 = fadd reassoc nnan nsz arcp contract afn float %scale.i0, -1.000000e+00
+  %.i1 = fadd reassoc nnan nsz arcp contract afn float %d, -3.000000e+00
+  switch i32 %b, label %return [
+  i32 0, label %sw.bb1
+  i32 1, label %sw.bb2
+  i32 2, label %sw.bb3
+  i32 3, label %sw.bb4
+  ]
+sw.bb1:                                               ; preds = %sw
+  br label %return
+
+sw.bb2:                                               ; preds = %sw
+  br label %return
+
+sw.bb3:                                               ; preds = %sw
+  %18 = fneg reassoc nnan nsz arcp contract afn float %.i0
+  br label %return
+
+sw.bb4:                                               ; preds = %sw
+  %20 = fneg reassoc nnan nsz arcp contract afn float %.i0
+  br label %return
+return:                                               ; preds = %sw.bb1, %sw.bb2, %sw.bb3, %sw.bb4, %sw, %.entry
+  %samplePos.1.i0 = phi float [ 0.000000e+00, %.entry ], [ %20, %sw.bb4 ], [ -1.000000e+00, %sw.bb3 ], [ %.i0, %sw.bb2 ], [ 1.000000e+00, %sw.bb1 ], [ 4.000000e+00, %sw ]
+  ret float %samplePos.1.i0
+}
+
+define float @partial_constant_multiple_PHInode(i32 %a, i32 %b, float %c, float %d) {
+; ALL-LABEL: @partial_constant_multiple_PHInode(
+; ALL-NEXT:  .entry:
+; ALL-NEXT:    [[TMP0:%.*]] = icmp eq i32 [[A:%.*]], 1
+; ALL-NEXT:    br i1 [[TMP0]], label [[SW:%.*]], label [[RETURN:%.*]]
+; ALL:       sw:
+; ALL-NEXT:    [[SCALE_I0:%.*]] = fmul reassoc nnan nsz arcp contract afn float [[C:%.*]], 2.000000e+00
+; ALL-NEXT:    [[DOTI0:%.*]] = fadd reassoc nnan nsz arcp contract afn float [[SCALE_I0]], -1.000000e+00
+; ALL-NEXT:    [[DOTI1:%.*]] = fadd reassoc nnan nsz arcp contract afn float [[D:%.*]], -3.000000e+00
+; ALL-NEXT:    switch i32 [[B:%.*]], label [[RETURN]] [
+; ALL-NEXT:      i32 0, label [[SW_BB1:%.*]]
+; ALL-NEXT:      i32 1, label [[SW_BB2:%.*]]
+; ALL-NEXT:      i32 2, label [[SW_BB3:%.*]]
+; ALL-NEXT:      i32 3, label [[SW_BB4:%.*]]
+; ALL-NEXT:    ]
+; ALL:       sw.bb1:
+; ALL-NEXT:    br label [[RETURN]]
+; ALL:       sw.bb2:
+; ALL-NEXT:    br label [[RETURN]]
+; ALL:       sw.bb3:
+; ALL-NEXT:    [[TMP1:%.*]] = fneg reassoc nnan nsz arcp contract afn float [[DOTI0]]
+; ALL-NEXT:    br label [[RETURN]]
+; ALL:       sw.bb4:
+; ALL-NEXT:    [[TMP2:%.*]] = fneg reassoc nnan nsz arcp contract afn float [[DOTI0]]
+; ALL-NEXT:    br label [[RETURN]]
+; ALL:       return:
+; ALL-NEXT:    [[SAMPLEPOS_1_I0:%.*]] = phi float [ 0.000000e+00, [[DOTENTRY:%.*]] ], [ [[TMP2]], [[SW_BB4]] ], [ -1.000000e+00, [[SW_BB3]] ], [ [[DOTI0]], [[SW_BB2]] ], [ 1.000000e+00, [[SW_BB1]] ], [ 4.000000e+00, [[SW]] ]
+; ALL-NEXT:    [[SAMPLEPOS_1_I1:%.*]] = phi float [ 0.000000e+00, [[DOTENTRY]] ], [ [[DOTI1]], [[SW_BB4]] ], [ [[DOTI1]], [[SW_BB3]] ], [ [[DOTI1]], [[SW_BB2]] ], [ 2.000000e+00, [[SW_BB1]] ], [ 4.000000e+00, [[SW]] ]
+; ALL-NEXT:    [[SAMPLEPOS_1_I2:%.*]] = phi float [ 0.000000e+00, [[DOTENTRY]] ], [ -1.000000e+00, [[SW_BB4]] ], [ [[TMP1]], [[SW_BB3]] ], [ 1.000000e+00, [[SW_BB2]] ], [ 3.000000e+00, [[SW_BB1]] ], [ 4.000000e+00, [[SW]] ]
+; ALL-NEXT:    [[RETVAL1:%.*]] = fadd float [[SAMPLEPOS_1_I0]], [[SAMPLEPOS_1_I1]]
+; ALL-NEXT:    [[RETVAL:%.*]] = fadd float [[RETVAL1]], [[SAMPLEPOS_1_I2]]
+; ALL-NEXT:    ret float [[RETVAL]]
+;
+.entry:
+  %5 = icmp eq i32 %a, 1
+  br i1 %5, label %sw, label %return
+
+sw:
+  %scale.i0 = fmul reassoc nnan nsz arcp contract afn float %c, 2.000000e+00
+  %.i0 = fadd reassoc nnan nsz arcp contract afn float %scale.i0, -1.000000e+00
+  %.i1 = fadd reassoc nnan nsz arcp contract afn float %d, -3.000000e+00
+  switch i32 %b, label %return [
+  i32 0, label %sw.bb1
+  i32 1, label %sw.bb2
+  i32 2, label %sw.bb3
+  i32 3, label %sw.bb4
+  ]
+sw.bb1:                                               ; preds = %sw
+  br label %return
+
+sw.bb2:                                               ; preds = %sw
+  br label %return
+
+sw.bb3:                                               ; preds = %sw
+  %18 = fneg reassoc nnan nsz arcp contract afn float %.i0
+  br label %return
+
+sw.bb4:                                               ; preds = %sw
+  %20 = fneg reassoc nnan nsz arcp contract afn float %.i0
+  br label %return
+return:                                               ; preds = %sw.bb1, %sw.bb2, %sw.bb3, %sw.bb4, %sw, %.entry
+  %samplePos.1.i0 = phi float [ 0.000000e+00, %.entry ], [ %20, %sw.bb4 ], [ -1.000000e+00, %sw.bb3 ], [ %.i0, %sw.bb2 ], [ 1.000000e+00, %sw.bb1 ], [ 4.000000e+00, %sw ]
+  %samplePos.1.i1 = phi float [ 0.000000e+00, %.entry ], [ %.i1, %sw.bb4 ], [ %.i1, %sw.bb3 ], [ %.i1, %sw.bb2 ], [ 2.000000e+00, %sw.bb1 ], [ 4.000000e+00, %sw ]
+  %samplePos.1.i2 = phi float [ 0.000000e+00, %.entry ], [ -1.000000e+00, %sw.bb4 ], [ %18, %sw.bb3 ], [ 1.000000e+00, %sw.bb2 ], [ 3.000000e+00, %sw.bb1 ], [ 4.000000e+00, %sw ]
+  %retVal1 = fadd float %samplePos.1.i0, %samplePos.1.i1
+  %retVal = fadd float %retVal1, %samplePos.1.i2
+  ret float %retVal
+}
+
+define float @two_instructions_in_bb(i32 %a, i32 %b, float %c, float %d) {
+; ALL-LABEL: @two_instructions_in_bb(
+; ALL-NEXT:  .entry:
+; ALL-NEXT:    [[TMP0:%.*]] = icmp eq i32 [[A:%.*]], 1
+; ALL-NEXT:    br i1 [[TMP0]], label [[SW:%.*]], label [[RETURN:%.*]]
+; ALL:       sw:
+; ALL-NEXT:    [[SCALE_I0:%.*]] = fmul reassoc nnan nsz arcp contract afn float [[C:%.*]], 2.000000e+00
+; ALL-NEXT:    [[DOTI0:%.*]] = fadd reassoc nnan nsz arcp contract afn float [[SCALE_I0]], -1.000000e+00
+; ALL-NEXT:    [[DOTI1:%.*]] = fadd reassoc nnan nsz arcp contract afn float [[D:%.*]], -3.000000e+00
+; ALL-NEXT:    switch i32 [[B:%.*]], label [[RETURN]] [
+; ALL-NEXT:      i32 0, label [[SW_BB1:%.*]]
+; ALL-NEXT:      i32 1, label [[SW_BB2:%.*]]
+; ALL-NEXT:      i32 2, label [[SW_BB3:%.*]]
+; ALL-NEXT:      i32 3, label [[SW_BB4:%.*]]
+; ALL-NEXT:    ]
+; ALL:       sw.bb1:
+; ALL-NEXT:    br label [[RETURN]]
+; ALL:       sw.bb2:
+; ALL-NEXT:    br label [[RETURN]]
+; ALL:       sw.bb3:
+; ALL-NEXT:    [[TMP1:%.*]] = fneg reassoc nnan nsz arcp contract afn float [[DOTI0]]
+; ALL-NEXT:    br label [[RETURN]]
+; ALL:       sw.bb4:
+; ALL-NEXT:    [[TMP2:%.*]] = fneg reassoc nnan nsz arcp contract afn float [[DOTI0]]
+; ALL-NEXT:    [[TMP3:%.*]] = fneg reassoc nnan nsz arcp contract afn float [[DOTI1]]
+; ALL-NEXT:    br label [[RETURN]]
+; ALL:       return:
+; ALL-NEXT:    [[SAMPLEPOS_1_I0:%.*]] = phi float [ 0.000000e+00, [[DOTENTRY:%.*]] ], [ [[TMP2]], [[SW_BB4]] ], [ -1.000000e+00, [[SW_BB3]] ], [ [[DOTI0]], [[SW_BB2]] ], [ 1.000000e+00, [[SW_BB1]] ], [ 4.000000e+00, [[SW]] ]
+; ALL-NEXT:    ret float [[SAMPLEPOS_1_I0]]
+;
+.entry:
+  %5 = icmp eq i32 %a, 1
+  br i1 %5, label %sw, label %return
+
+sw:
+  %scale.i0 = fmul reassoc nnan nsz arcp contract afn float %c, 2.000000e+00
+  %.i0 = fadd reassoc nnan nsz arcp contract afn float %scale.i0, -1.000000e+00
+  %.i1 = fadd reassoc nnan nsz arcp contract afn float %d, -3.000000e+00
+  switch i32 %b, label %return [
+  i32 0, label %sw.bb1
+  i32 1, label %sw.bb2
+  i32 2, label %sw.bb3
+  i32 3, label %sw.bb4
+  ]
+sw.bb1:                                               ; preds = %sw
+  br label %return
+
+sw.bb2:                                               ; preds = %sw
+  br label %return
+
+sw.bb3:                                               ; preds = %sw
+  %18 = fneg reassoc nnan nsz arcp contract afn float %.i0
+  br label %return
+
+sw.bb4:                                               ; preds = %sw
+  %20 = fneg reassoc nnan nsz arcp contract afn float %.i0
+  %21 = fneg reassoc nnan nsz arcp contract afn float %.i1
+  br label %return
+return:                                               ; preds = %sw.bb1, %sw.bb2, %sw.bb3, %sw.bb4, %sw, %.entry
+  %samplePos.1.i0 = phi float [ 0.000000e+00, %.entry ], [ %20, %sw.bb4 ], [ -1.000000e+00, %sw.bb3 ], [ %.i0, %sw.bb2 ], [ 1.000000e+00, %sw.bb1 ], [ 4.000000e+00, %sw ]
+  ret float %samplePos.1.i0
+}

>From be1511a6537999b630f120a99835df58712ad355 Mon Sep 17 00:00:00 2001
From: Acim Maravic <acim.maravic at syrmia.com>
Date: Thu, 30 May 2024 14:02:54 +0200
Subject: [PATCH 2/2] [SimplifyCFG] Convert switch to cmp/select sequence

---
 .../Transforms/Utils/SimplifyCFGOptions.h     |   6 +
 llvm/lib/Passes/PassBuilder.cpp               |   2 +
 llvm/lib/Passes/PassRegistry.def              |   1 +
 .../lib/Transforms/Scalar/SimplifyCFGPass.cpp |   5 +
 llvm/lib/Transforms/Utils/SimplifyCFG.cpp     | 267 ++++++++++++++++++
 .../SimplifyCFG/switch-to-select.ll           | 227 ++++++++++-----
 6 files changed, 436 insertions(+), 72 deletions(-)

diff --git a/llvm/include/llvm/Transforms/Utils/SimplifyCFGOptions.h b/llvm/include/llvm/Transforms/Utils/SimplifyCFGOptions.h
index 8008fc6e8422d..40aafcbdc1899 100644
--- a/llvm/include/llvm/Transforms/Utils/SimplifyCFGOptions.h
+++ b/llvm/include/llvm/Transforms/Utils/SimplifyCFGOptions.h
@@ -30,6 +30,7 @@ struct SimplifyCFGOptions {
   bool SinkCommonInsts = false;
   bool SimplifyCondBranch = true;
   bool SpeculateBlocks = true;
+  bool ConvertSwitchToSelect = false;
 
   AssumptionCache *AC = nullptr;
 
@@ -75,6 +76,11 @@ struct SimplifyCFGOptions {
     SpeculateBlocks = B;
     return *this;
   }
+
+  SimplifyCFGOptions &convertSwitchToSelect(bool B) {
+    ConvertSwitchToSelect = B;
+    return *this;
+  }
 };
 
 } // namespace llvm
diff --git a/llvm/lib/Passes/PassBuilder.cpp b/llvm/lib/Passes/PassBuilder.cpp
index 734ca4d5deec9..65d4aa369548f 100644
--- a/llvm/lib/Passes/PassBuilder.cpp
+++ b/llvm/lib/Passes/PassBuilder.cpp
@@ -842,6 +842,8 @@ Expected<SimplifyCFGOptions> parseSimplifyCFGOptions(StringRef Params) {
                     ParamName).str(),
             inconvertibleErrorCode());
       Result.bonusInstThreshold(BonusInstThreshold.getSExtValue());
+    } else if (ParamName == "switch-to-select") {
+      Result.convertSwitchToSelect(Enable);
     } else {
       return make_error<StringError>(
           formatv("invalid SimplifyCFG pass parameter '{0}' ", ParamName).str(),
diff --git a/llvm/lib/Passes/PassRegistry.def b/llvm/lib/Passes/PassRegistry.def
index 50682ca4970f1..00aa401ad91da 100644
--- a/llvm/lib/Passes/PassRegistry.def
+++ b/llvm/lib/Passes/PassRegistry.def
@@ -570,6 +570,7 @@ FUNCTION_PASS_WITH_PARAMS(
     "no-forward-switch-cond;forward-switch-cond;no-switch-range-to-icmp;"
     "switch-range-to-icmp;no-switch-to-lookup;switch-to-lookup;no-keep-loops;"
     "keep-loops;no-hoist-common-insts;hoist-common-insts;no-sink-common-insts;"
+    "switch-to-select;"
     "sink-common-insts;bonus-inst-threshold=N")
 FUNCTION_PASS_WITH_PARAMS(
     "speculative-execution", "SpeculativeExecutionPass",
diff --git a/llvm/lib/Transforms/Scalar/SimplifyCFGPass.cpp b/llvm/lib/Transforms/Scalar/SimplifyCFGPass.cpp
index 7017f6adf3a2b..bf1e3d438380d 100644
--- a/llvm/lib/Transforms/Scalar/SimplifyCFGPass.cpp
+++ b/llvm/lib/Transforms/Scalar/SimplifyCFGPass.cpp
@@ -77,6 +77,9 @@ static cl::opt<bool> UserSinkCommonInsts(
     "sink-common-insts", cl::Hidden, cl::init(false),
     cl::desc("Sink common instructions (default = false)"));
 
+static cl::opt<bool> UserSwitchToSelect(
+    "switch-to-select", cl::Hidden, cl::init(false),
+    cl::desc("Convert switches into icmp + select (default = false)"));
 
 STATISTIC(NumSimpl, "Number of blocks simplified");
 
@@ -323,6 +326,8 @@ static void applyCommandLineOverridesToOptions(SimplifyCFGOptions &Options) {
     Options.HoistCommonInsts = UserHoistCommonInsts;
   if (UserSinkCommonInsts.getNumOccurrences())
     Options.SinkCommonInsts = UserSinkCommonInsts;
+  if (UserSwitchToSelect.getNumOccurrences())
+    Options.ConvertSwitchToSelect = UserSwitchToSelect;
 }
 
 SimplifyCFGPass::SimplifyCFGPass() {
diff --git a/llvm/lib/Transforms/Utils/SimplifyCFG.cpp b/llvm/lib/Transforms/Utils/SimplifyCFG.cpp
index fe6ec8819ff99..3b4d594150692 100644
--- a/llvm/lib/Transforms/Utils/SimplifyCFG.cpp
+++ b/llvm/lib/Transforms/Utils/SimplifyCFG.cpp
@@ -6197,6 +6197,268 @@ static bool trySwitchToSelect(SwitchInst *SI, IRBuilder<> &Builder,
   return true;
 }
 
+// The first field contains the value that the switch produces when a certain
+// case group is selected, and the second field is a vector containing the
+// cases composing the case group.
+using SwitchCaseResultVectorTy2 =
+    SmallVector<std::pair<Value *, SmallVector<Value *, 4>>, 2>;
+
+// The first field contains the phi node that generates a result of the switch
+// and the second field contains the value generated for a certain case in the
+// switch for that PHI.
+using SwitchCaseResultsTy2 = SmallVector<std::pair<PHINode *, Value *>, 4>;
+
+using PHINodeToCaseEntryValueMapTy =
+    std::map<PHINode *, SmallVector<std::pair<ConstantInt *, Value *>, 4>>;
+
+// Helper function that checks if all PHI Nodes have default value
+bool allPHINodesHaveDefaultValue(const SwitchCaseResultsTy2 &Results) {
+  for (const auto &Pair : Results)
+    if (Pair.second == nullptr)
+      return false;
+  return true;
+}
+
+static bool getCaseResultsWithoutConstants(
+    SwitchInst *SI, BasicBlock *CaseDest, BasicBlock **CommonDest,
+    SmallVectorImpl<std::pair<PHINode *, Value *>> &Res,
+    bool IsDefault = false) {
+
+  BasicBlock *Pred = SI->getParent();
+
+  if (!IsDefault) {
+    for (Instruction &I : CaseDest->instructionsWithoutDebug(false)) {
+
+      if (I.isTerminator()) {
+        // If the terminator is a simple branch, continue to the next block.
+        if (I.getNumSuccessors() != 1 || I.isSpecialTerminator())
+          return false;
+
+        Pred = CaseDest;
+        CaseDest = I.getSuccessor(0);
+      } else {
+        for (auto &Use : I.uses()) {
+          User *User = Use.getUser();
+
+          if (Instruction *I = dyn_cast<Instruction>(User))
+            if (I->getParent() == CaseDest)
+              continue;
+
+          if (PHINode *Phi = dyn_cast<PHINode>(User))
+            if (Phi->getIncomingBlock(Use) == CaseDest)
+              continue;
+
+          return false;
+        }
+      }
+    }
+  }
+
+  if (!IsDefault) {
+    auto SwitchPos =
+        std::find_if(SI->getParent()->begin(), SI->getParent()->end(),
+                     [](Instruction &I) { return isa<SwitchInst>(&I); });
+    assert(SwitchPos != SI->getParent()->end() &&
+           "Switch instruction not found in previous block");
+
+    // Iterate over the instructions in CaseDest and move them
+    for (auto it = Pred->begin(), end = Pred->end(); it != end;) {
+      Instruction &I = *it++;
+      if (!I.isTerminator())
+        I.moveBefore(&*SwitchPos);
+    }
+  }
+
+  // If we did not have a CommonDest before, use the current one.
+  if (!*CommonDest)
+    *CommonDest = CaseDest;
+  // If the destination isn't the common one, abort.
+  if (CaseDest != *CommonDest)
+    return false;
+
+  // Get the values for this case from phi nodes in the destination block.
+  for (PHINode &PHI : (*CommonDest)->phis()) {
+    int Idx = PHI.getBasicBlockIndex(Pred);
+    if (Idx == -1)
+      continue;
+
+    Value *Val = PHI.getIncomingValue(Idx);
+
+    if (!Val)
+      return false;
+
+    Res.push_back(std::make_pair(&PHI, Val));
+  }
+  return !Res.empty();
+}
+
+static void mapCaseToResultWithMap(SwitchCaseResultsTy2 &Results,
+                                   PHINodeToCaseEntryValueMapTy &Map,
+                                   ConstantInt *CaseVal,
+                                   SwitchCaseResultVectorTy2 &UniqueResults,
+                                   Value *Result) {
+  // fill in PHINodeToCaseEntryValueMapTy &Map
+  for (const auto &Pair : Results) {
+    PHINode *PHI = Pair.first;
+    Value *ReturnValue = Pair.second;
+    Map[PHI].emplace_back(std::make_pair(CaseVal, ReturnValue));
+  }
+
+  // fill in SwitchCaseResultVectorTy2 &UniqueResults
+  for (auto &I : UniqueResults) {
+    if (I.first == Result) {
+      I.second.push_back(CaseVal);
+      return;
+    }
+  }
+  UniqueResults.push_back(
+      std::make_pair(Result, SmallVector<Value *, 4>(1, CaseVal)));
+}
+
+static bool initializeUniqueCasesWithoutConstants(
+    SwitchInst *SI, BasicBlock *&CommonDest, PHINodeToCaseEntryValueMapTy &Map,
+    SwitchCaseResultVectorTy2 &UniqueResults, PHINode *&PHI,
+    SwitchCaseResultsTy2 &DefaultResults) {
+
+  for (const auto &Case : SI->cases()) {
+    SwitchCaseResultsTy2 Results;
+    ConstantInt *CaseVal = Case.getCaseValue();
+
+    if (!getCaseResultsWithoutConstants(SI, Case.getCaseSuccessor(),
+                                        &CommonDest, Results))
+      return false;
+
+    mapCaseToResultWithMap(Results, Map, CaseVal, UniqueResults,
+                           Results.begin()->second);
+
+    // Check the PHI consistency.
+    if (!PHI)
+      PHI = Results[0].first;
+    else if (PHI != Results[0].first)
+      return false;
+  }
+
+  BasicBlock *DefaultDest = SI->getDefaultDest();
+
+  if (!getCaseResultsWithoutConstants(SI, DefaultDest, &CommonDest,
+                                      DefaultResults, true))
+    return false;
+
+  if (!allPHINodesHaveDefaultValue(DefaultResults) &&
+      !isa<UnreachableInst>(DefaultDest->getFirstNonPHIOrDbg()))
+    return false;
+
+  return true;
+}
+
+Value *createSelectChain(Value *Condition, Value *DefaultResult,
+                         const SwitchCaseResultVectorTy2 &ResultVector,
+                         unsigned StartIndex, PHINode *PHI, SwitchInst *SI,
+                         IRBuilder<> &Builder, DomTreeUpdater *DTU) {
+
+  if (StartIndex >= ResultVector.size() && DefaultResult)
+    return DefaultResult;
+
+  if (StartIndex >= ResultVector.size() && !DefaultResult)
+    return nullptr;
+
+  Value *CurrentCase = ResultVector[StartIndex].second[0];
+
+  Value *ValueCompare =
+      Builder.CreateICmpEQ(Condition, CurrentCase, "switch.selectcmp");
+  Value *NextSelect = createSelectChain(Condition, DefaultResult, ResultVector,
+                                        StartIndex + 1, PHI, SI, Builder, DTU);
+  Value *SelectedValue =
+      Builder.CreateSelect(ValueCompare, ResultVector[StartIndex].first,
+                           NextSelect, "switch.select");
+
+  if (DTU) {
+    DTU->applyUpdates(
+        {{DominatorTree::Delete, SI->getParent(), SI->getDefaultDest()}});
+  }
+
+  return SelectedValue;
+}
+
+static Value *foldSwitchToSelect2(const SwitchCaseResultVectorTy2 &ResultVector,
+                                  Value *DefaultResult, Value *Condition,
+                                  PHINode *&PHI, SwitchInst *SI,
+                                  IRBuilder<> &Builder, DomTreeUpdater *DTU) {
+  if (ResultVector.size() > 2) {
+    Value *FinalSelect = createSelectChain(
+        Condition, DefaultResult, ResultVector, 0, PHI, SI, Builder, DTU);
+
+    if (FinalSelect)
+      return FinalSelect;
+  }
+
+  return nullptr;
+}
+
+/// Helper function that will try to convert switch to cmp/select sequence
+static bool convertSwitchToCmpAndSelect(SwitchInst *SI, IRBuilder<> &Builder,
+                                        DomTreeUpdater *DTU,
+                                        const DataLayout &DL,
+                                        const TargetTransformInfo &TTI) {
+
+  BasicBlock *CommonDest = nullptr;
+  PHINodeToCaseEntryValueMapTy Map;
+  SwitchCaseResultVectorTy2 UniqueResults;
+  PHINode *PHI = nullptr;
+  SwitchCaseResultsTy2 DefaultResults;
+
+  if (!initializeUniqueCasesWithoutConstants(SI, CommonDest, Map, UniqueResults,
+                                             PHI, DefaultResults))
+    return false;
+
+  // for each PHI, call function foldSwitchToSelect
+  for (const auto &Entry : Map) {
+    PHI = Entry.first;
+    SwitchCaseResultVectorTy2 ResultVector;
+
+    for (const auto &ValuePair : Entry.second) {
+      ConstantInt *CaseVal = ValuePair.first;
+      Value *ReturnValue = ValuePair.second;
+      ResultVector.push_back(
+          std::make_pair(ReturnValue, SmallVector<Value *, 4>(1, CaseVal)));
+    }
+
+    Value *DefaultResult = nullptr;
+    for (const auto &ValuePair : DefaultResults) {
+      if (PHI == ValuePair.first)
+        DefaultResult = ValuePair.second;
+    }
+
+    assert(PHI != nullptr && "PHI for value select not found");
+    assert(DefaultResult != nullptr && "Default value for switch not found");
+
+    Value *SelectValue = foldSwitchToSelect2(
+        ResultVector, DefaultResult, SI->getCondition(), PHI, SI, Builder, DTU);
+
+    if (!SelectValue)
+      return false;
+
+    int Index = PHI->getBasicBlockIndex(SI->getParent());
+    if (Index != -1) {
+      PHI->setIncomingValue(Index, SelectValue);
+    }
+
+    for (auto Case = SI->case_begin(); Case != SI->case_end(); ++Case) {
+      int Index = PHI->getBasicBlockIndex(Case->getCaseSuccessor());
+      if (Index != -1)
+        PHI->setIncomingValue(Index, SelectValue);
+    }
+  }
+
+  for (auto Case = SI->case_begin(); Case != SI->case_end(); Case++)
+    SI->removeCase(Case);
+
+  if (SI->getNumCases() == 0)
+    SI->removeFromParent();
+
+  return true;
+}
+
 namespace {
 
 /// This class represents a lookup table that can be used to replace a switch.
@@ -7146,6 +7408,7 @@ bool SimplifyCFGOpt::simplifySwitch(SwitchInst *SI, IRBuilder<> &Builder) {
   // switch expression itself can still be restricted as a result of inlining or
   // CVP. Therefore, only apply this transformation during late stages of the
   // optimisation pipeline.
+
   if (Options.ConvertSwitchToLookupTable &&
       SwitchToLookupTable(SI, Builder, DTU, DL, TTI))
     return requestResimplify();
@@ -7156,6 +7419,10 @@ bool SimplifyCFGOpt::simplifySwitch(SwitchInst *SI, IRBuilder<> &Builder) {
   if (ReduceSwitchRange(SI, Builder, DL, TTI))
     return requestResimplify();
 
+  if (Options.ConvertSwitchToSelect &&
+      convertSwitchToCmpAndSelect(SI, Builder, DTU, DL, TTI))
+    return requestResimplify();
+
   if (HoistCommon &&
       hoistCommonCodeFromSuccessors(SI->getParent(), !Options.HoistCommonInsts))
     return requestResimplify();
diff --git a/llvm/test/Transforms/SimplifyCFG/switch-to-select.ll b/llvm/test/Transforms/SimplifyCFG/switch-to-select.ll
index c431d18b072f9..3ef43d2754bf9 100644
--- a/llvm/test/Transforms/SimplifyCFG/switch-to-select.ll
+++ b/llvm/test/Transforms/SimplifyCFG/switch-to-select.ll
@@ -1,5 +1,5 @@
 ; NOTE: Assertions have been autogenerated by utils/update_test_checks.py
-; RUN: opt -S -passes=simplifycfg < %s | FileCheck -check-prefix=ALL %s
+; RUN: opt -S -passes=simplifycfg -switch-to-select < %s | FileCheck -check-prefix=ALL %s
 
 define float @constant_single_PHInode(i32 %a, i32 %b, float %c, float %d) {
 ; ALL-LABEL: @constant_single_PHInode(
@@ -10,23 +10,18 @@ define float @constant_single_PHInode(i32 %a, i32 %b, float %c, float %d) {
 ; ALL-NEXT:    [[SCALE_I0:%.*]] = fmul reassoc nnan nsz arcp contract afn float [[C:%.*]], 2.000000e+00
 ; ALL-NEXT:    [[DOTI0:%.*]] = fadd reassoc nnan nsz arcp contract afn float [[SCALE_I0]], -1.000000e+00
 ; ALL-NEXT:    [[DOTI1:%.*]] = fadd reassoc nnan nsz arcp contract afn float [[D:%.*]], -3.000000e+00
-; ALL-NEXT:    switch i32 [[B:%.*]], label [[RETURN]] [
-; ALL-NEXT:      i32 0, label [[SW_BB1:%.*]]
-; ALL-NEXT:      i32 1, label [[SW_BB2:%.*]]
-; ALL-NEXT:      i32 2, label [[SW_BB3:%.*]]
-; ALL-NEXT:      i32 3, label [[SW_BB4:%.*]]
-; ALL-NEXT:    ]
-; ALL:       sw.bb1:
-; ALL-NEXT:    br label [[RETURN]]
-; ALL:       sw.bb2:
-; ALL-NEXT:    br label [[RETURN]]
-; ALL:       sw.bb3:
 ; ALL-NEXT:    [[TMP1:%.*]] = fneg reassoc nnan nsz arcp contract afn float [[DOTI0]]
-; ALL-NEXT:    br label [[RETURN]]
-; ALL:       sw.bb4:
+; ALL-NEXT:    [[SWITCH_SELECTCMP:%.*]] = icmp eq i32 [[B:%.*]], 0
+; ALL-NEXT:    [[SWITCH_SELECTCMP1:%.*]] = icmp eq i32 [[B]], 1
+; ALL-NEXT:    [[SWITCH_SELECTCMP2:%.*]] = icmp eq i32 [[B]], 2
+; ALL-NEXT:    [[SWITCH_SELECTCMP3:%.*]] = icmp eq i32 [[B]], 3
+; ALL-NEXT:    [[SWITCH_SELECT:%.*]] = select i1 [[SWITCH_SELECTCMP3]], float -5.000000e+00, float 4.000000e+00
+; ALL-NEXT:    [[SWITCH_SELECT4:%.*]] = select i1 [[SWITCH_SELECTCMP2]], float -1.000000e+00, float [[SWITCH_SELECT]]
+; ALL-NEXT:    [[SWITCH_SELECT5:%.*]] = select i1 [[SWITCH_SELECTCMP1]], float 7.000000e+00, float [[SWITCH_SELECT4]]
+; ALL-NEXT:    [[SWITCH_SELECT6:%.*]] = select i1 [[SWITCH_SELECTCMP]], float 1.000000e+00, float [[SWITCH_SELECT5]]
 ; ALL-NEXT:    br label [[RETURN]]
 ; ALL:       return:
-; ALL-NEXT:    [[SAMPLEPOS_1_I0:%.*]] = phi float [ 0.000000e+00, [[DOTENTRY:%.*]] ], [ -5.000000e+00, [[SW_BB4]] ], [ -1.000000e+00, [[SW_BB3]] ], [ 7.000000e+00, [[SW_BB2]] ], [ 1.000000e+00, [[SW_BB1]] ], [ 4.000000e+00, [[SW]] ]
+; ALL-NEXT:    [[SAMPLEPOS_1_I0:%.*]] = phi float [ 0.000000e+00, [[DOTENTRY:%.*]] ], [ [[SWITCH_SELECT6]], [[SW]] ]
 ; ALL-NEXT:    ret float [[SAMPLEPOS_1_I0]]
 ;
 .entry:
@@ -71,21 +66,35 @@ define float @constant_multiple_PHInode(i32 %a, i32 %b, float %c, float %d) {
 ; ALL-NEXT:    [[SCALE_I0:%.*]] = fmul reassoc nnan nsz arcp contract afn float [[C:%.*]], 2.000000e+00
 ; ALL-NEXT:    [[DOTI0:%.*]] = fadd reassoc nnan nsz arcp contract afn float [[SCALE_I0]], -1.000000e+00
 ; ALL-NEXT:    [[DOTI1:%.*]] = fadd reassoc nnan nsz arcp contract afn float [[D:%.*]], -3.000000e+00
-; ALL-NEXT:    switch i32 [[B:%.*]], label [[RETURN]] [
-; ALL-NEXT:      i32 0, label [[SW_BB1:%.*]]
-; ALL-NEXT:      i32 1, label [[SW_BB2:%.*]]
-; ALL-NEXT:      i32 2, label [[SW_BB3:%.*]]
-; ALL-NEXT:    ]
-; ALL:       sw.bb1:
-; ALL-NEXT:    br label [[RETURN]]
-; ALL:       sw.bb2:
-; ALL-NEXT:    br label [[RETURN]]
-; ALL:       sw.bb3:
+; ALL-NEXT:    [[SWITCH_SELECTCMP:%.*]] = icmp eq i32 [[B:%.*]], 0
+; ALL-NEXT:    [[SWITCH_SELECTCMP1:%.*]] = icmp eq i32 [[B]], 1
+; ALL-NEXT:    [[SWITCH_SELECTCMP2:%.*]] = icmp eq i32 [[B]], 2
+; ALL-NEXT:    [[SWITCH_SELECTCMP3:%.*]] = icmp eq i32 [[B]], 3
+; ALL-NEXT:    [[SWITCH_SELECT:%.*]] = select i1 [[SWITCH_SELECTCMP3]], float 4.000000e+00, float 4.000000e+00
+; ALL-NEXT:    [[SWITCH_SELECT4:%.*]] = select i1 [[SWITCH_SELECTCMP2]], float -3.000000e+00, float [[SWITCH_SELECT]]
+; ALL-NEXT:    [[SWITCH_SELECT5:%.*]] = select i1 [[SWITCH_SELECTCMP1]], float 2.000000e+00, float [[SWITCH_SELECT4]]
+; ALL-NEXT:    [[SWITCH_SELECT6:%.*]] = select i1 [[SWITCH_SELECTCMP]], float -1.000000e+00, float [[SWITCH_SELECT5]]
+; ALL-NEXT:    [[SWITCH_SELECTCMP7:%.*]] = icmp eq i32 [[B]], 0
+; ALL-NEXT:    [[SWITCH_SELECTCMP8:%.*]] = icmp eq i32 [[B]], 1
+; ALL-NEXT:    [[SWITCH_SELECTCMP9:%.*]] = icmp eq i32 [[B]], 2
+; ALL-NEXT:    [[SWITCH_SELECTCMP10:%.*]] = icmp eq i32 [[B]], 3
+; ALL-NEXT:    [[SWITCH_SELECT11:%.*]] = select i1 [[SWITCH_SELECTCMP10]], float 4.000000e+00, float 4.000000e+00
+; ALL-NEXT:    [[SWITCH_SELECT12:%.*]] = select i1 [[SWITCH_SELECTCMP9]], float 3.000000e+00, float [[SWITCH_SELECT11]]
+; ALL-NEXT:    [[SWITCH_SELECT13:%.*]] = select i1 [[SWITCH_SELECTCMP8]], float 2.000000e+00, float [[SWITCH_SELECT12]]
+; ALL-NEXT:    [[SWITCH_SELECT14:%.*]] = select i1 [[SWITCH_SELECTCMP7]], float 1.000000e+00, float [[SWITCH_SELECT13]]
+; ALL-NEXT:    [[SWITCH_SELECTCMP15:%.*]] = icmp eq i32 [[B]], 0
+; ALL-NEXT:    [[SWITCH_SELECTCMP16:%.*]] = icmp eq i32 [[B]], 1
+; ALL-NEXT:    [[SWITCH_SELECTCMP17:%.*]] = icmp eq i32 [[B]], 2
+; ALL-NEXT:    [[SWITCH_SELECTCMP18:%.*]] = icmp eq i32 [[B]], 3
+; ALL-NEXT:    [[SWITCH_SELECT19:%.*]] = select i1 [[SWITCH_SELECTCMP18]], float -4.000000e+00, float -4.000000e+00
+; ALL-NEXT:    [[SWITCH_SELECT20:%.*]] = select i1 [[SWITCH_SELECTCMP17]], float -3.000000e+00, float [[SWITCH_SELECT19]]
+; ALL-NEXT:    [[SWITCH_SELECT21:%.*]] = select i1 [[SWITCH_SELECTCMP16]], float -2.000000e+00, float [[SWITCH_SELECT20]]
+; ALL-NEXT:    [[SWITCH_SELECT22:%.*]] = select i1 [[SWITCH_SELECTCMP15]], float -1.000000e+00, float [[SWITCH_SELECT21]]
 ; ALL-NEXT:    br label [[RETURN]]
 ; ALL:       return:
-; ALL-NEXT:    [[SAMPLEPOS_1_I0:%.*]] = phi float [ 0.000000e+00, [[DOTENTRY:%.*]] ], [ 3.000000e+00, [[SW_BB3]] ], [ 2.000000e+00, [[SW_BB2]] ], [ 1.000000e+00, [[SW_BB1]] ], [ 4.000000e+00, [[SW]] ]
-; ALL-NEXT:    [[SAMPLEPOS_1_I1:%.*]] = phi float [ 0.000000e+00, [[DOTENTRY]] ], [ -3.000000e+00, [[SW_BB3]] ], [ -2.000000e+00, [[SW_BB2]] ], [ -1.000000e+00, [[SW_BB1]] ], [ -4.000000e+00, [[SW]] ]
-; ALL-NEXT:    [[SAMPLEPOS_1_I2:%.*]] = phi float [ 0.000000e+00, [[DOTENTRY]] ], [ -3.000000e+00, [[SW_BB3]] ], [ 2.000000e+00, [[SW_BB2]] ], [ -1.000000e+00, [[SW_BB1]] ], [ 4.000000e+00, [[SW]] ]
+; ALL-NEXT:    [[SAMPLEPOS_1_I0:%.*]] = phi float [ 0.000000e+00, [[DOTENTRY:%.*]] ], [ [[SWITCH_SELECT14]], [[SW]] ]
+; ALL-NEXT:    [[SAMPLEPOS_1_I1:%.*]] = phi float [ 0.000000e+00, [[DOTENTRY]] ], [ [[SWITCH_SELECT22]], [[SW]] ]
+; ALL-NEXT:    [[SAMPLEPOS_1_I2:%.*]] = phi float [ 0.000000e+00, [[DOTENTRY]] ], [ [[SWITCH_SELECT6]], [[SW]] ]
 ; ALL-NEXT:    [[RETVAL1:%.*]] = fadd float [[SAMPLEPOS_1_I0]], [[SAMPLEPOS_1_I1]]
 ; ALL-NEXT:    [[RETVAL:%.*]] = fadd float [[RETVAL1]], [[SAMPLEPOS_1_I2]]
 ; ALL-NEXT:    ret float [[RETVAL]]
@@ -134,24 +143,19 @@ define float @partial_constant_single_PHInode(i32 %a, i32 %b, float %c, float %d
 ; ALL-NEXT:    [[SCALE_I0:%.*]] = fmul reassoc nnan nsz arcp contract afn float [[C:%.*]], 2.000000e+00
 ; ALL-NEXT:    [[DOTI0:%.*]] = fadd reassoc nnan nsz arcp contract afn float [[SCALE_I0]], -1.000000e+00
 ; ALL-NEXT:    [[DOTI1:%.*]] = fadd reassoc nnan nsz arcp contract afn float [[D:%.*]], -3.000000e+00
-; ALL-NEXT:    switch i32 [[B:%.*]], label [[RETURN]] [
-; ALL-NEXT:      i32 0, label [[SW_BB1:%.*]]
-; ALL-NEXT:      i32 1, label [[SW_BB2:%.*]]
-; ALL-NEXT:      i32 2, label [[SW_BB3:%.*]]
-; ALL-NEXT:      i32 3, label [[SW_BB4:%.*]]
-; ALL-NEXT:    ]
-; ALL:       sw.bb1:
-; ALL-NEXT:    br label [[RETURN]]
-; ALL:       sw.bb2:
-; ALL-NEXT:    br label [[RETURN]]
-; ALL:       sw.bb3:
 ; ALL-NEXT:    [[TMP1:%.*]] = fneg reassoc nnan nsz arcp contract afn float [[DOTI0]]
-; ALL-NEXT:    br label [[RETURN]]
-; ALL:       sw.bb4:
 ; ALL-NEXT:    [[TMP2:%.*]] = fneg reassoc nnan nsz arcp contract afn float [[DOTI0]]
+; ALL-NEXT:    [[SWITCH_SELECTCMP:%.*]] = icmp eq i32 [[B:%.*]], 0
+; ALL-NEXT:    [[SWITCH_SELECTCMP1:%.*]] = icmp eq i32 [[B]], 1
+; ALL-NEXT:    [[SWITCH_SELECTCMP2:%.*]] = icmp eq i32 [[B]], 2
+; ALL-NEXT:    [[SWITCH_SELECTCMP3:%.*]] = icmp eq i32 [[B]], 3
+; ALL-NEXT:    [[SWITCH_SELECT:%.*]] = select i1 [[SWITCH_SELECTCMP3]], float [[TMP2]], float 4.000000e+00
+; ALL-NEXT:    [[SWITCH_SELECT4:%.*]] = select i1 [[SWITCH_SELECTCMP2]], float -1.000000e+00, float [[SWITCH_SELECT]]
+; ALL-NEXT:    [[SWITCH_SELECT5:%.*]] = select i1 [[SWITCH_SELECTCMP1]], float [[DOTI0]], float [[SWITCH_SELECT4]]
+; ALL-NEXT:    [[SWITCH_SELECT6:%.*]] = select i1 [[SWITCH_SELECTCMP]], float 1.000000e+00, float [[SWITCH_SELECT5]]
 ; ALL-NEXT:    br label [[RETURN]]
 ; ALL:       return:
-; ALL-NEXT:    [[SAMPLEPOS_1_I0:%.*]] = phi float [ 0.000000e+00, [[DOTENTRY:%.*]] ], [ [[TMP2]], [[SW_BB4]] ], [ -1.000000e+00, [[SW_BB3]] ], [ [[DOTI0]], [[SW_BB2]] ], [ 1.000000e+00, [[SW_BB1]] ], [ 4.000000e+00, [[SW]] ]
+; ALL-NEXT:    [[SAMPLEPOS_1_I0:%.*]] = phi float [ 0.000000e+00, [[DOTENTRY:%.*]] ], [ [[SWITCH_SELECT6]], [[SW]] ]
 ; ALL-NEXT:    ret float [[SAMPLEPOS_1_I0]]
 ;
 .entry:
@@ -195,26 +199,37 @@ define float @partial_constant_multiple_PHInode(i32 %a, i32 %b, float %c, float
 ; ALL-NEXT:    [[SCALE_I0:%.*]] = fmul reassoc nnan nsz arcp contract afn float [[C:%.*]], 2.000000e+00
 ; ALL-NEXT:    [[DOTI0:%.*]] = fadd reassoc nnan nsz arcp contract afn float [[SCALE_I0]], -1.000000e+00
 ; ALL-NEXT:    [[DOTI1:%.*]] = fadd reassoc nnan nsz arcp contract afn float [[D:%.*]], -3.000000e+00
-; ALL-NEXT:    switch i32 [[B:%.*]], label [[RETURN]] [
-; ALL-NEXT:      i32 0, label [[SW_BB1:%.*]]
-; ALL-NEXT:      i32 1, label [[SW_BB2:%.*]]
-; ALL-NEXT:      i32 2, label [[SW_BB3:%.*]]
-; ALL-NEXT:      i32 3, label [[SW_BB4:%.*]]
-; ALL-NEXT:    ]
-; ALL:       sw.bb1:
-; ALL-NEXT:    br label [[RETURN]]
-; ALL:       sw.bb2:
-; ALL-NEXT:    br label [[RETURN]]
-; ALL:       sw.bb3:
 ; ALL-NEXT:    [[TMP1:%.*]] = fneg reassoc nnan nsz arcp contract afn float [[DOTI0]]
-; ALL-NEXT:    br label [[RETURN]]
-; ALL:       sw.bb4:
 ; ALL-NEXT:    [[TMP2:%.*]] = fneg reassoc nnan nsz arcp contract afn float [[DOTI0]]
+; ALL-NEXT:    [[SWITCH_SELECTCMP:%.*]] = icmp eq i32 [[B:%.*]], 0
+; ALL-NEXT:    [[SWITCH_SELECTCMP1:%.*]] = icmp eq i32 [[B]], 1
+; ALL-NEXT:    [[SWITCH_SELECTCMP2:%.*]] = icmp eq i32 [[B]], 2
+; ALL-NEXT:    [[SWITCH_SELECTCMP3:%.*]] = icmp eq i32 [[B]], 3
+; ALL-NEXT:    [[SWITCH_SELECT:%.*]] = select i1 [[SWITCH_SELECTCMP3]], float -1.000000e+00, float 4.000000e+00
+; ALL-NEXT:    [[SWITCH_SELECT4:%.*]] = select i1 [[SWITCH_SELECTCMP2]], float [[TMP1]], float [[SWITCH_SELECT]]
+; ALL-NEXT:    [[SWITCH_SELECT5:%.*]] = select i1 [[SWITCH_SELECTCMP1]], float 1.000000e+00, float [[SWITCH_SELECT4]]
+; ALL-NEXT:    [[SWITCH_SELECT6:%.*]] = select i1 [[SWITCH_SELECTCMP]], float 3.000000e+00, float [[SWITCH_SELECT5]]
+; ALL-NEXT:    [[SWITCH_SELECTCMP7:%.*]] = icmp eq i32 [[B]], 0
+; ALL-NEXT:    [[SWITCH_SELECTCMP8:%.*]] = icmp eq i32 [[B]], 1
+; ALL-NEXT:    [[SWITCH_SELECTCMP9:%.*]] = icmp eq i32 [[B]], 2
+; ALL-NEXT:    [[SWITCH_SELECTCMP10:%.*]] = icmp eq i32 [[B]], 3
+; ALL-NEXT:    [[SWITCH_SELECT11:%.*]] = select i1 [[SWITCH_SELECTCMP10]], float [[TMP2]], float 4.000000e+00
+; ALL-NEXT:    [[SWITCH_SELECT12:%.*]] = select i1 [[SWITCH_SELECTCMP9]], float -1.000000e+00, float [[SWITCH_SELECT11]]
+; ALL-NEXT:    [[SWITCH_SELECT13:%.*]] = select i1 [[SWITCH_SELECTCMP8]], float [[DOTI0]], float [[SWITCH_SELECT12]]
+; ALL-NEXT:    [[SWITCH_SELECT14:%.*]] = select i1 [[SWITCH_SELECTCMP7]], float 1.000000e+00, float [[SWITCH_SELECT13]]
+; ALL-NEXT:    [[SWITCH_SELECTCMP15:%.*]] = icmp eq i32 [[B]], 0
+; ALL-NEXT:    [[SWITCH_SELECTCMP16:%.*]] = icmp eq i32 [[B]], 1
+; ALL-NEXT:    [[SWITCH_SELECTCMP17:%.*]] = icmp eq i32 [[B]], 2
+; ALL-NEXT:    [[SWITCH_SELECTCMP18:%.*]] = icmp eq i32 [[B]], 3
+; ALL-NEXT:    [[SWITCH_SELECT19:%.*]] = select i1 [[SWITCH_SELECTCMP18]], float [[DOTI1]], float 4.000000e+00
+; ALL-NEXT:    [[SWITCH_SELECT20:%.*]] = select i1 [[SWITCH_SELECTCMP17]], float [[DOTI1]], float [[SWITCH_SELECT19]]
+; ALL-NEXT:    [[SWITCH_SELECT21:%.*]] = select i1 [[SWITCH_SELECTCMP16]], float [[DOTI1]], float [[SWITCH_SELECT20]]
+; ALL-NEXT:    [[SWITCH_SELECT22:%.*]] = select i1 [[SWITCH_SELECTCMP15]], float 2.000000e+00, float [[SWITCH_SELECT21]]
 ; ALL-NEXT:    br label [[RETURN]]
 ; ALL:       return:
-; ALL-NEXT:    [[SAMPLEPOS_1_I0:%.*]] = phi float [ 0.000000e+00, [[DOTENTRY:%.*]] ], [ [[TMP2]], [[SW_BB4]] ], [ -1.000000e+00, [[SW_BB3]] ], [ [[DOTI0]], [[SW_BB2]] ], [ 1.000000e+00, [[SW_BB1]] ], [ 4.000000e+00, [[SW]] ]
-; ALL-NEXT:    [[SAMPLEPOS_1_I1:%.*]] = phi float [ 0.000000e+00, [[DOTENTRY]] ], [ [[DOTI1]], [[SW_BB4]] ], [ [[DOTI1]], [[SW_BB3]] ], [ [[DOTI1]], [[SW_BB2]] ], [ 2.000000e+00, [[SW_BB1]] ], [ 4.000000e+00, [[SW]] ]
-; ALL-NEXT:    [[SAMPLEPOS_1_I2:%.*]] = phi float [ 0.000000e+00, [[DOTENTRY]] ], [ -1.000000e+00, [[SW_BB4]] ], [ [[TMP1]], [[SW_BB3]] ], [ 1.000000e+00, [[SW_BB2]] ], [ 3.000000e+00, [[SW_BB1]] ], [ 4.000000e+00, [[SW]] ]
+; ALL-NEXT:    [[SAMPLEPOS_1_I0:%.*]] = phi float [ 0.000000e+00, [[DOTENTRY:%.*]] ], [ [[SWITCH_SELECT14]], [[SW]] ]
+; ALL-NEXT:    [[SAMPLEPOS_1_I1:%.*]] = phi float [ 0.000000e+00, [[DOTENTRY]] ], [ [[SWITCH_SELECT22]], [[SW]] ]
+; ALL-NEXT:    [[SAMPLEPOS_1_I2:%.*]] = phi float [ 0.000000e+00, [[DOTENTRY]] ], [ [[SWITCH_SELECT6]], [[SW]] ]
 ; ALL-NEXT:    [[RETVAL1:%.*]] = fadd float [[SAMPLEPOS_1_I0]], [[SAMPLEPOS_1_I1]]
 ; ALL-NEXT:    [[RETVAL:%.*]] = fadd float [[RETVAL1]], [[SAMPLEPOS_1_I2]]
 ; ALL-NEXT:    ret float [[RETVAL]]
@@ -264,25 +279,20 @@ define float @two_instructions_in_bb(i32 %a, i32 %b, float %c, float %d) {
 ; ALL-NEXT:    [[SCALE_I0:%.*]] = fmul reassoc nnan nsz arcp contract afn float [[C:%.*]], 2.000000e+00
 ; ALL-NEXT:    [[DOTI0:%.*]] = fadd reassoc nnan nsz arcp contract afn float [[SCALE_I0]], -1.000000e+00
 ; ALL-NEXT:    [[DOTI1:%.*]] = fadd reassoc nnan nsz arcp contract afn float [[D:%.*]], -3.000000e+00
-; ALL-NEXT:    switch i32 [[B:%.*]], label [[RETURN]] [
-; ALL-NEXT:      i32 0, label [[SW_BB1:%.*]]
-; ALL-NEXT:      i32 1, label [[SW_BB2:%.*]]
-; ALL-NEXT:      i32 2, label [[SW_BB3:%.*]]
-; ALL-NEXT:      i32 3, label [[SW_BB4:%.*]]
-; ALL-NEXT:    ]
-; ALL:       sw.bb1:
-; ALL-NEXT:    br label [[RETURN]]
-; ALL:       sw.bb2:
-; ALL-NEXT:    br label [[RETURN]]
-; ALL:       sw.bb3:
 ; ALL-NEXT:    [[TMP1:%.*]] = fneg reassoc nnan nsz arcp contract afn float [[DOTI0]]
-; ALL-NEXT:    br label [[RETURN]]
-; ALL:       sw.bb4:
 ; ALL-NEXT:    [[TMP2:%.*]] = fneg reassoc nnan nsz arcp contract afn float [[DOTI0]]
 ; ALL-NEXT:    [[TMP3:%.*]] = fneg reassoc nnan nsz arcp contract afn float [[DOTI1]]
+; ALL-NEXT:    [[SWITCH_SELECTCMP:%.*]] = icmp eq i32 [[B:%.*]], 0
+; ALL-NEXT:    [[SWITCH_SELECTCMP1:%.*]] = icmp eq i32 [[B]], 1
+; ALL-NEXT:    [[SWITCH_SELECTCMP2:%.*]] = icmp eq i32 [[B]], 2
+; ALL-NEXT:    [[SWITCH_SELECTCMP3:%.*]] = icmp eq i32 [[B]], 3
+; ALL-NEXT:    [[SWITCH_SELECT:%.*]] = select i1 [[SWITCH_SELECTCMP3]], float [[TMP2]], float 4.000000e+00
+; ALL-NEXT:    [[SWITCH_SELECT4:%.*]] = select i1 [[SWITCH_SELECTCMP2]], float -1.000000e+00, float [[SWITCH_SELECT]]
+; ALL-NEXT:    [[SWITCH_SELECT5:%.*]] = select i1 [[SWITCH_SELECTCMP1]], float [[DOTI0]], float [[SWITCH_SELECT4]]
+; ALL-NEXT:    [[SWITCH_SELECT6:%.*]] = select i1 [[SWITCH_SELECTCMP]], float 1.000000e+00, float [[SWITCH_SELECT5]]
 ; ALL-NEXT:    br label [[RETURN]]
 ; ALL:       return:
-; ALL-NEXT:    [[SAMPLEPOS_1_I0:%.*]] = phi float [ 0.000000e+00, [[DOTENTRY:%.*]] ], [ [[TMP2]], [[SW_BB4]] ], [ -1.000000e+00, [[SW_BB3]] ], [ [[DOTI0]], [[SW_BB2]] ], [ 1.000000e+00, [[SW_BB1]] ], [ 4.000000e+00, [[SW]] ]
+; ALL-NEXT:    [[SAMPLEPOS_1_I0:%.*]] = phi float [ 0.000000e+00, [[DOTENTRY:%.*]] ], [ [[SWITCH_SELECT6]], [[SW]] ]
 ; ALL-NEXT:    ret float [[SAMPLEPOS_1_I0]]
 ;
 .entry:
@@ -317,3 +327,76 @@ return:                                               ; preds = %sw.bb1, %sw.bb2
   %samplePos.1.i0 = phi float [ 0.000000e+00, %.entry ], [ %20, %sw.bb4 ], [ -1.000000e+00, %sw.bb3 ], [ %.i0, %sw.bb2 ], [ 1.000000e+00, %sw.bb1 ], [ 4.000000e+00, %sw ]
   ret float %samplePos.1.i0
 }
+
+define float @no_common_dest_for_cases(i32 %a, i32 %b, float %c, float %d) {
+; ALL-LABEL: @no_common_dest_for_cases(
+; ALL-NEXT:  .entry:
+; ALL-NEXT:    [[TMP0:%.*]] = icmp eq i32 [[A:%.*]], 1
+; ALL-NEXT:    br i1 [[TMP0]], label [[SW:%.*]], label [[COMMON_RET:%.*]]
+; ALL:       sw:
+; ALL-NEXT:    [[SCALE_I0:%.*]] = fmul reassoc nnan nsz arcp contract afn float [[C:%.*]], 2.000000e+00
+; ALL-NEXT:    [[DOTI0:%.*]] = fadd reassoc nnan nsz arcp contract afn float [[SCALE_I0]], -1.000000e+00
+; ALL-NEXT:    [[DOTI1:%.*]] = fadd reassoc nnan nsz arcp contract afn float [[D:%.*]], -3.000000e+00
+; ALL-NEXT:    [[TMP1:%.*]] = fneg reassoc nnan nsz arcp contract afn float [[DOTI0]]
+; ALL-NEXT:    [[TMP2:%.*]] = fneg reassoc nnan nsz arcp contract afn float [[DOTI0]]
+; ALL-NEXT:    [[TMP3:%.*]] = fneg reassoc nnan nsz arcp contract afn float [[DOTI0]]
+; ALL-NEXT:    [[TMP4:%.*]] = fneg reassoc nnan nsz arcp contract afn float [[DOTI0]]
+; ALL-NEXT:    [[SWITCH_SELECTCMP:%.*]] = icmp eq i32 [[B:%.*]], 0
+; ALL-NEXT:    [[SWITCH_SELECTCMP1:%.*]] = icmp eq i32 [[B]], 1
+; ALL-NEXT:    [[SWITCH_SELECTCMP2:%.*]] = icmp eq i32 [[B]], 2
+; ALL-NEXT:    [[SWITCH_SELECTCMP3:%.*]] = icmp eq i32 [[B]], 3
+; ALL-NEXT:    [[SWITCH_SELECT:%.*]] = select i1 [[SWITCH_SELECTCMP3]], float [[TMP4]], float 0.000000e+00
+; ALL-NEXT:    [[SWITCH_SELECT4:%.*]] = select i1 [[SWITCH_SELECTCMP2]], float [[TMP3]], float [[SWITCH_SELECT]]
+; ALL-NEXT:    [[SWITCH_SELECT5:%.*]] = select i1 [[SWITCH_SELECTCMP1]], float [[TMP2]], float [[SWITCH_SELECT4]]
+; ALL-NEXT:    [[SWITCH_SELECT6:%.*]] = select i1 [[SWITCH_SELECTCMP]], float [[TMP1]], float [[SWITCH_SELECT5]]
+; ALL-NEXT:    br label [[COMMON_RET]]
+; ALL:       common.ret:
+; ALL-NEXT:    [[COMMON_RET_OP:%.*]] = phi float [ 0.000000e+00, [[DOTENTRY:%.*]] ], [ [[SWITCH_SELECT6]], [[SW]] ]
+; ALL-NEXT:    ret float [[COMMON_RET_OP]]
+;
+.entry:
+  %5 = icmp eq i32 %a, 1
+  br i1 %5, label %sw, label %return
+
+sw:
+  %scale.i0 = fmul reassoc nnan nsz arcp contract afn float %c, 2.000000e+00
+  %.i0 = fadd reassoc nnan nsz arcp contract afn float %scale.i0, -1.000000e+00
+  %.i1 = fadd reassoc nnan nsz arcp contract afn float %d, -3.000000e+00
+  switch i32 %b, label %return [
+  i32 0, label %sw.bb1
+  i32 1, label %sw.bb2
+  i32 2, label %sw.bb3
+  i32 3, label %sw.bb4
+  ]
+
+sw.bb1:                                               ; preds = %sw
+  %18 = fneg reassoc nnan nsz arcp contract afn float %.i0
+  br label %return1
+
+sw.bb2:                                               ; preds = %sw
+  %19 = fneg reassoc nnan nsz arcp contract afn float %.i0
+  br label %return2
+
+sw.bb3:                                               ; preds = %sw
+  %20 = fneg reassoc nnan nsz arcp contract afn float %.i0
+  br label %return3
+
+sw.bb4:                                               ; preds = %sw
+  %21 = fneg reassoc nnan nsz arcp contract afn float %.i0
+  br label %return4
+
+return1:                                              ; preds = %sw.bb1
+  ret float %18
+
+return2:                                              ; preds = %sw.bb2
+  ret float %19
+
+return3:                                              ; preds = %sw.bb3
+  ret float %20
+
+return4:                                              ; preds = %sw.bb4
+  ret float %21
+
+return:                                               ; preds = %.entry
+  ret float 0.0
+}



More information about the llvm-commits mailing list