[llvm] goldsteinn/helper for icmp eq ne (PR #86346)

via llvm-commits llvm-commits at lists.llvm.org
Fri Mar 22 14:47:49 PDT 2024


https://github.com/goldsteinn created https://github.com/llvm/llvm-project/pull/86346

- **Pre-commit: add test**
- **Fold 'switch(rol(x, C1))'**
- **[InstCombine] Add tests for simplifying Instruction w/ constants with eq/ne Constants; NFC**
- **[InstCombine] Add helper simplifying Instruction w/ constants with eq/ne Constants; NFC**
- **[InstCombine] Use `simplifyOpWithConstantEqConsts` in `foldICmpEquality`**
- **[InstCombine] Use `simplifyOpWithConstantEqConsts` in `visitSwitchInst`**


>From 1064f1fffab1dbd82c78108186b283aa43e954f0 Mon Sep 17 00:00:00 2001
From: YanWQ-monad <YanWQmonad at gmail.com>
Date: Sat, 23 Mar 2024 00:47:03 +0800
Subject: [PATCH 1/6] Pre-commit: add test

---
 .../test/Transforms/InstCombine/switch-rol.ll | 66 +++++++++++++++++++
 1 file changed, 66 insertions(+)
 create mode 100644 llvm/test/Transforms/InstCombine/switch-rol.ll

diff --git a/llvm/test/Transforms/InstCombine/switch-rol.ll b/llvm/test/Transforms/InstCombine/switch-rol.ll
new file mode 100644
index 00000000000000..cd0d066e3e0ce3
--- /dev/null
+++ b/llvm/test/Transforms/InstCombine/switch-rol.ll
@@ -0,0 +1,66 @@
+; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --version 4
+; RUN: opt < %s -passes=instcombine -S | FileCheck %s
+
+declare void @dummy()
+
+define i32 @switch_rol(i32 %a) #0 {
+; CHECK-LABEL: define i32 @switch_rol(
+; CHECK-SAME: i32 [[A:%.*]]) {
+; CHECK-NEXT:  entry:
+; CHECK-NEXT:    [[ROL:%.*]] = call i32 @llvm.fshl.i32(i32 [[A]], i32 [[A]], i32 30)
+; CHECK-NEXT:    switch i32 [[ROL]], label [[DEFAULT:%.*]] [
+; CHECK-NEXT:      i32 0, label [[TRAP_EXIT:%.*]]
+; CHECK-NEXT:      i32 5, label [[TRAP_EXIT]]
+; CHECK-NEXT:    ]
+; CHECK:       default:
+; CHECK-NEXT:    call void @dummy()
+; CHECK-NEXT:    br label [[TRAP_EXIT]]
+; CHECK:       trap.exit:
+; CHECK-NEXT:    ret i32 0
+;
+entry:
+  %rol = call i32 @llvm.fshl.i32(i32 %a, i32 %a, i32 30)
+  switch i32 %rol, label %default [
+  i32 0, label %trap.exit
+  i32 5, label %trap.exit
+  ]
+
+default:
+  call void @dummy()
+  br label %trap.exit
+
+trap.exit:
+  ret i32 0
+}
+
+define i32 @switch_rol_2(i32 %a) #0 {
+; CHECK-LABEL: define i32 @switch_rol_2(
+; CHECK-SAME: i32 [[A:%.*]]) {
+; CHECK-NEXT:  entry:
+; CHECK-NEXT:    [[TMP0:%.*]] = add i32 [[A]], -7
+; CHECK-NEXT:    [[ROL:%.*]] = call i32 @llvm.fshl.i32(i32 [[TMP0]], i32 [[TMP0]], i32 30)
+; CHECK-NEXT:    switch i32 [[ROL]], label [[DEFAULT:%.*]] [
+; CHECK-NEXT:      i32 0, label [[TRAP_EXIT:%.*]]
+; CHECK-NEXT:      i32 5, label [[TRAP_EXIT]]
+; CHECK-NEXT:    ]
+; CHECK:       default:
+; CHECK-NEXT:    call void @dummy()
+; CHECK-NEXT:    br label [[TRAP_EXIT]]
+; CHECK:       trap.exit:
+; CHECK-NEXT:    ret i32 0
+;
+entry:
+  %1 = sub i32 %a, 7
+  %rol = call i32 @llvm.fshl.i32(i32 %1, i32 %1, i32 30)
+  switch i32 %rol, label %default [
+  i32 0, label %trap.exit
+  i32 5, label %trap.exit
+  ]
+
+default:
+  call void @dummy()
+  br label %trap.exit
+
+trap.exit:
+  ret i32 0
+}

>From 450520b6d888181449e50f29fbaa5acdcebca4e4 Mon Sep 17 00:00:00 2001
From: YanWQ-monad <YanWQmonad at gmail.com>
Date: Sat, 23 Mar 2024 00:47:45 +0800
Subject: [PATCH 2/6] Fold 'switch(rol(x, C1))'

---
 .../Transforms/InstCombine/InstructionCombining.cpp | 10 ++++++++++
 llvm/test/Transforms/InstCombine/switch-rol.ll      | 13 +++++--------
 2 files changed, 15 insertions(+), 8 deletions(-)

diff --git a/llvm/lib/Transforms/InstCombine/InstructionCombining.cpp b/llvm/lib/Transforms/InstCombine/InstructionCombining.cpp
index 7c40fb4fc86082..b6611cfbbfc1f4 100644
--- a/llvm/lib/Transforms/InstCombine/InstructionCombining.cpp
+++ b/llvm/lib/Transforms/InstCombine/InstructionCombining.cpp
@@ -3645,6 +3645,16 @@ Instruction *InstCombinerImpl::visitSwitchInst(SwitchInst &SI) {
     }
   }
 
+  // Fold 'switch(rol(x, C1)) case C2:' to 'switch(x) case rol(C2, -C1):'
+  if (match(Cond,
+            m_FShl(m_Value(Op0), m_Deferred(Op0), m_ConstantInt(ShiftAmt)))) {
+    for (auto &Case : SI.cases()) {
+      const APInt NewCase = Case.getCaseValue()->getValue().rotr(ShiftAmt);
+      Case.setValue(ConstantInt::get(SI.getContext(), NewCase));
+    }
+    return replaceOperand(SI, 0, Op0);
+  }
+
   KnownBits Known = computeKnownBits(Cond, 0, &SI);
   unsigned LeadingKnownZeros = Known.countMinLeadingZeros();
   unsigned LeadingKnownOnes = Known.countMinLeadingOnes();
diff --git a/llvm/test/Transforms/InstCombine/switch-rol.ll b/llvm/test/Transforms/InstCombine/switch-rol.ll
index cd0d066e3e0ce3..7557ad5dfe276e 100644
--- a/llvm/test/Transforms/InstCombine/switch-rol.ll
+++ b/llvm/test/Transforms/InstCombine/switch-rol.ll
@@ -7,10 +7,9 @@ define i32 @switch_rol(i32 %a) #0 {
 ; CHECK-LABEL: define i32 @switch_rol(
 ; CHECK-SAME: i32 [[A:%.*]]) {
 ; CHECK-NEXT:  entry:
-; CHECK-NEXT:    [[ROL:%.*]] = call i32 @llvm.fshl.i32(i32 [[A]], i32 [[A]], i32 30)
-; CHECK-NEXT:    switch i32 [[ROL]], label [[DEFAULT:%.*]] [
+; CHECK-NEXT:    switch i32 [[A]], label [[DEFAULT:%.*]] [
 ; CHECK-NEXT:      i32 0, label [[TRAP_EXIT:%.*]]
-; CHECK-NEXT:      i32 5, label [[TRAP_EXIT]]
+; CHECK-NEXT:      i32 20, label [[TRAP_EXIT]]
 ; CHECK-NEXT:    ]
 ; CHECK:       default:
 ; CHECK-NEXT:    call void @dummy()
@@ -37,11 +36,9 @@ define i32 @switch_rol_2(i32 %a) #0 {
 ; CHECK-LABEL: define i32 @switch_rol_2(
 ; CHECK-SAME: i32 [[A:%.*]]) {
 ; CHECK-NEXT:  entry:
-; CHECK-NEXT:    [[TMP0:%.*]] = add i32 [[A]], -7
-; CHECK-NEXT:    [[ROL:%.*]] = call i32 @llvm.fshl.i32(i32 [[TMP0]], i32 [[TMP0]], i32 30)
-; CHECK-NEXT:    switch i32 [[ROL]], label [[DEFAULT:%.*]] [
-; CHECK-NEXT:      i32 0, label [[TRAP_EXIT:%.*]]
-; CHECK-NEXT:      i32 5, label [[TRAP_EXIT]]
+; CHECK-NEXT:    switch i32 [[A]], label [[DEFAULT:%.*]] [
+; CHECK-NEXT:      i32 7, label [[TRAP_EXIT:%.*]]
+; CHECK-NEXT:      i32 27, label [[TRAP_EXIT]]
 ; CHECK-NEXT:    ]
 ; CHECK:       default:
 ; CHECK-NEXT:    call void @dummy()

>From 1e2e2b5ae4623fcefa844aef81ac2fb92c752198 Mon Sep 17 00:00:00 2001
From: Noah Goldstein <goldstein.w.n at gmail.com>
Date: Fri, 22 Mar 2024 16:11:23 -0500
Subject: [PATCH 3/6] [InstCombine] Add tests for simplifying Instruction w/
 constants with eq/ne Constants; NFC

---
 .../Transforms/InstCombine/simplify-cmp-eq.ll | 1611 +++++++++++++++++
 1 file changed, 1611 insertions(+)
 create mode 100644 llvm/test/Transforms/InstCombine/simplify-cmp-eq.ll

diff --git a/llvm/test/Transforms/InstCombine/simplify-cmp-eq.ll b/llvm/test/Transforms/InstCombine/simplify-cmp-eq.ll
new file mode 100644
index 00000000000000..d5cd9061763945
--- /dev/null
+++ b/llvm/test/Transforms/InstCombine/simplify-cmp-eq.ll
@@ -0,0 +1,1611 @@
+; NOTE: Assertions have been autogenerated by utils/update_test_checks.py
+; RUN: opt < %s -passes=instcombine -S | FileCheck %s
+
+declare void @use.i8(i8)
+define <2 x i1> @simplify_cmp_or_disjoint(<2 x i8> %x) {
+; CHECK-LABEL: @simplify_cmp_or_disjoint(
+; CHECK-NEXT:    [[V:%.*]] = or disjoint <2 x i8> [[X:%.*]], <i8 12, i8 13>
+; CHECK-NEXT:    [[R:%.*]] = icmp ne <2 x i8> [[V]], <i8 0, i8 45>
+; CHECK-NEXT:    ret <2 x i1> [[R]]
+;
+  %v = or disjoint <2 x i8> %x, <i8 12, i8 13>
+  %r = icmp ne <2 x i8> %v, <i8 0, i8 45>
+  ret <2 x i1> %r
+}
+
+define <2 x i1> @simplify_cmp_or_fail_missing_disjoint(<2 x i8> %x) {
+; CHECK-LABEL: @simplify_cmp_or_fail_missing_disjoint(
+; CHECK-NEXT:    [[V:%.*]] = or <2 x i8> [[X:%.*]], <i8 12, i8 13>
+; CHECK-NEXT:    [[R:%.*]] = icmp ne <2 x i8> [[V]], <i8 0, i8 45>
+; CHECK-NEXT:    ret <2 x i1> [[R]]
+;
+  %v = or <2 x i8> %x, <i8 12, i8 13>
+  %r = icmp ne <2 x i8> %v, <i8 0, i8 45>
+  ret <2 x i1> %r
+}
+
+define i1 @simplify_cmp_add(i8 %x) {
+; CHECK-LABEL: @simplify_cmp_add(
+; CHECK-NEXT:    [[R:%.*]] = icmp ne i8 [[X:%.*]], 43
+; CHECK-NEXT:    ret i1 [[R]]
+;
+  %v = add i8 %x, 12
+  %r = icmp ne i8 %v, 55
+  ret i1 %r
+}
+
+define i1 @simplify_cmp_add_fail_multiuse(i8 %x) {
+; CHECK-LABEL: @simplify_cmp_add_fail_multiuse(
+; CHECK-NEXT:    [[V:%.*]] = add i8 [[X:%.*]], 12
+; CHECK-NEXT:    call void @use.i8(i8 [[V]])
+; CHECK-NEXT:    [[R:%.*]] = icmp ne i8 [[V]], 55
+; CHECK-NEXT:    ret i1 [[R]]
+;
+  %v = add i8 %x, 12
+  call void @use.i8(i8 %v)
+  %r = icmp ne i8 %v, 55
+  ret i1 %r
+}
+
+define <2 x i1> @simplify_cmp_sub(<2 x i8> %x) {
+; CHECK-LABEL: @simplify_cmp_sub(
+; CHECK-NEXT:    [[V:%.*]] = sub <2 x i8> <i8 12, i8 13>, [[X:%.*]]
+; CHECK-NEXT:    [[R:%.*]] = icmp eq <2 x i8> [[V]], <i8 0, i8 55>
+; CHECK-NEXT:    ret <2 x i1> [[R]]
+;
+  %v = sub <2 x i8> <i8 12, i8 13>, %x
+  %r = icmp eq <2 x i8> %v, <i8 0, i8 55>
+  ret <2 x i1> %r
+}
+
+define i1 @simplify_cmp_xor(i8 %x) {
+; CHECK-LABEL: @simplify_cmp_xor(
+; CHECK-NEXT:    [[R:%.*]] = icmp eq i8 [[X:%.*]], 59
+; CHECK-NEXT:    ret i1 [[R]]
+;
+  %v = xor i8 %x, 12
+  %r = icmp eq i8 %v, 55
+  ret i1 %r
+}
+
+define <2 x i1> @simplify_cmp_mul_udiv(<2 x i8> %x) {
+; CHECK-LABEL: @simplify_cmp_mul_udiv(
+; CHECK-NEXT:    [[R:%.*]] = icmp eq <2 x i8> [[X:%.*]], <i8 4, i8 4>
+; CHECK-NEXT:    ret <2 x i1> [[R]]
+;
+  %v = mul nuw <2 x i8> %x, <i8 12, i8 12>
+  %r = icmp eq <2 x i8> %v, <i8 48, i8 48>
+  ret <2 x i1> %r
+}
+
+define <2 x i1> @simplify_cmp_mul_udiv_todo(<2 x i8> %x) {
+; CHECK-LABEL: @simplify_cmp_mul_udiv_todo(
+; CHECK-NEXT:    [[V:%.*]] = mul nuw <2 x i8> [[X:%.*]], <i8 12, i8 12>
+; CHECK-NEXT:    [[R:%.*]] = icmp eq <2 x i8> [[V]], <i8 48, i8 60>
+; CHECK-NEXT:    ret <2 x i1> [[R]]
+;
+  %v = mul nuw <2 x i8> %x, <i8 12, i8 12>
+  %r = icmp eq <2 x i8> %v, <i8 48, i8 60>
+  ret <2 x i1> %r
+}
+
+define <2 x i1> @simplify_cmp_mul_udiv_fail_missing_nuw(<2 x i8> %x) {
+; CHECK-LABEL: @simplify_cmp_mul_udiv_fail_missing_nuw(
+; CHECK-NEXT:    [[R:%.*]] = icmp eq <2 x i8> [[X:%.*]], <i8 4, i8 4>
+; CHECK-NEXT:    ret <2 x i1> [[R]]
+;
+  %v = mul nsw <2 x i8> %x, <i8 12, i8 12>
+  %r = icmp eq <2 x i8> %v, <i8 48, i8 48>
+  ret <2 x i1> %r
+}
+
+define <2 x i1> @simplify_cmp_mul_udiv_fail_bad_rem(<2 x i8> %x) {
+; CHECK-LABEL: @simplify_cmp_mul_udiv_fail_bad_rem(
+; CHECK-NEXT:    ret <2 x i1> zeroinitializer
+;
+  %v = mul nuw <2 x i8> %x, <i8 12, i8 12>
+  %r = icmp eq <2 x i8> %v, <i8 47, i8 47>
+  ret <2 x i1> %r
+}
+
+define <2 x i1> @simplify_cmp_mul_sdiv(<2 x i8> %x) {
+; CHECK-LABEL: @simplify_cmp_mul_sdiv(
+; CHECK-NEXT:    ret <2 x i1> zeroinitializer
+;
+  %v = mul nuw <2 x i8> %x, <i8 12, i8 12>
+  %r = icmp eq <2 x i8> %v, <i8 -48, i8 -48>
+  ret <2 x i1> %r
+}
+
+define <2 x i1> @simplify_cmp_mul_sdiv_fail_bad_rem(<2 x i8> %x) {
+; CHECK-LABEL: @simplify_cmp_mul_sdiv_fail_bad_rem(
+; CHECK-NEXT:    ret <2 x i1> zeroinitializer
+;
+  %v = mul nuw <2 x i8> %x, <i8 7, i8 7>
+  %r = icmp eq <2 x i8> %v, <i8 -48, i8 -48>
+  ret <2 x i1> %r
+}
+
+define i1 @simplify_cmp_udiv(i8 %x) {
+; CHECK-LABEL: @simplify_cmp_udiv(
+; CHECK-NEXT:    [[R:%.*]] = icmp eq i8 [[X:%.*]], -112
+; CHECK-NEXT:    ret i1 [[R]]
+;
+  %v = udiv exact i8 %x, 12
+  %r = icmp eq i8 %v, 12
+  ret i1 %r
+}
+
+define i1 @simplify_cmp_udiv_fail_missing_exact(i8 %x) {
+; CHECK-LABEL: @simplify_cmp_udiv_fail_missing_exact(
+; CHECK-NEXT:    [[X_OFF:%.*]] = add i8 [[X:%.*]], 112
+; CHECK-NEXT:    [[R:%.*]] = icmp ult i8 [[X_OFF]], 12
+; CHECK-NEXT:    ret i1 [[R]]
+;
+  %v = udiv i8 %x, 12
+  %r = icmp eq i8 %v, 12
+  ret i1 %r
+}
+
+define i1 @simplify_cmp_udiv_fail_overflow(i8 %x) {
+; CHECK-LABEL: @simplify_cmp_udiv_fail_overflow(
+; CHECK-NEXT:    ret i1 false
+;
+  %v = udiv exact i8 %x, 12
+  %r = icmp eq i8 %v, 50
+  ret i1 %r
+}
+
+define i1 @simplify_cmp_sdiv(i8 %x) {
+; CHECK-LABEL: @simplify_cmp_sdiv(
+; CHECK-NEXT:    [[R:%.*]] = icmp eq i8 [[X:%.*]], 72
+; CHECK-NEXT:    ret i1 [[R]]
+;
+  %v = sdiv exact i8 %x, 12
+  %r = icmp eq i8 %v, 6
+  ret i1 %r
+}
+
+define i1 @simplify_cmp_sdiv_fail_missing_exact(i8 %x) {
+; CHECK-LABEL: @simplify_cmp_sdiv_fail_missing_exact(
+; CHECK-NEXT:    [[X_OFF:%.*]] = add i8 [[X:%.*]], -72
+; CHECK-NEXT:    [[R:%.*]] = icmp ult i8 [[X_OFF]], 12
+; CHECK-NEXT:    ret i1 [[R]]
+;
+  %v = sdiv i8 %x, 12
+  %r = icmp eq i8 %v, 6
+  ret i1 %r
+}
+
+define i1 @simplify_cmp_sdiv_fail_overflow(i8 %x) {
+; CHECK-LABEL: @simplify_cmp_sdiv_fail_overflow(
+; CHECK-NEXT:    ret i1 false
+;
+  %v = sdiv exact i8 %x, 12
+  %r = icmp eq i8 %v, 12
+  ret i1 %r
+}
+
+define i1 @simplify_cmp_zext(i4 %x) {
+; CHECK-LABEL: @simplify_cmp_zext(
+; CHECK-NEXT:    [[R:%.*]] = icmp eq i4 [[X:%.*]], -8
+; CHECK-NEXT:    ret i1 [[R]]
+;
+  %v = zext i4 %x to i8
+  %r = icmp eq i8 %v, 8
+  ret i1 %r
+}
+
+define i1 @simplify_cmp_zext_fail_out_of_bounds(i4 %x) {
+; CHECK-LABEL: @simplify_cmp_zext_fail_out_of_bounds(
+; CHECK-NEXT:    ret i1 false
+;
+  %v = zext i4 %x to i8
+  %r = icmp eq i8 %v, 16
+  ret i1 %r
+}
+
+define i1 @simplify_cmp_sext(i4 %x) {
+; CHECK-LABEL: @simplify_cmp_sext(
+; CHECK-NEXT:    ret i1 false
+;
+  %v = sext i4 %x to i8
+  %r = icmp eq i8 %v, 8
+  ret i1 %r
+}
+
+define i1 @simplify_cmp_sext2(i4 %x) {
+; CHECK-LABEL: @simplify_cmp_sext2(
+; CHECK-NEXT:    [[R:%.*]] = icmp eq i4 [[X:%.*]], -8
+; CHECK-NEXT:    ret i1 [[R]]
+;
+  %v = sext i4 %x to i8
+  %r = icmp eq i8 %v, -8
+  ret i1 %r
+}
+
+define i1 @simplify_cmp_sext_fail_out_of_bounds(i4 %x) {
+; CHECK-LABEL: @simplify_cmp_sext_fail_out_of_bounds(
+; CHECK-NEXT:    ret i1 false
+;
+  %v = sext i4 %x to i8
+  %r = icmp eq i8 %v, -16
+  ret i1 %r
+}
+
+define i1 @simplify_cmp_shl(i8 %x) {
+; CHECK-LABEL: @simplify_cmp_shl(
+; CHECK-NEXT:    [[V_MASK:%.*]] = and i8 [[X:%.*]], 31
+; CHECK-NEXT:    [[R:%.*]] = icmp eq i8 [[V_MASK]], 7
+; CHECK-NEXT:    ret i1 [[R]]
+;
+  %v = shl i8 %x, 3
+  %r = icmp eq i8 %v, 56
+  ret i1 %r
+}
+
+define i1 @simplify_cmp_shl_fail_shiftout(i8 %x) {
+; CHECK-LABEL: @simplify_cmp_shl_fail_shiftout(
+; CHECK-NEXT:    ret i1 false
+;
+  %v = shl i8 %x, 3
+  %r = icmp eq i8 %v, 57
+  ret i1 %r
+}
+
+define i1 @simplify_cmp_shl_fail_multiuse(i8 %x) {
+; CHECK-LABEL: @simplify_cmp_shl_fail_multiuse(
+; CHECK-NEXT:    [[V:%.*]] = shl i8 [[X:%.*]], 3
+; CHECK-NEXT:    [[R:%.*]] = icmp eq i8 [[V]], 56
+; CHECK-NEXT:    call void @use.i8(i8 [[V]])
+; CHECK-NEXT:    ret i1 [[R]]
+;
+  %v = shl i8 %x, 3
+  %r = icmp eq i8 %v, 56
+  call void @use.i8(i8 %v)
+  ret i1 %r
+}
+
+define i1 @simplify_cmp_shl_okay_multiuse(i8 %x) {
+; CHECK-LABEL: @simplify_cmp_shl_okay_multiuse(
+; CHECK-NEXT:    [[V:%.*]] = shl nuw i8 [[X:%.*]], 3
+; CHECK-NEXT:    [[R:%.*]] = icmp eq i8 [[X]], 7
+; CHECK-NEXT:    call void @use.i8(i8 [[V]])
+; CHECK-NEXT:    ret i1 [[R]]
+;
+  %v = shl nuw i8 %x, 3
+  %r = icmp eq i8 %v, 56
+  call void @use.i8(i8 %v)
+  ret i1 %r
+}
+
+define i1 @simplify_cmp_shl_okay_multiuse2(i8 %x) {
+; CHECK-LABEL: @simplify_cmp_shl_okay_multiuse2(
+; CHECK-NEXT:    [[V:%.*]] = shl nsw i8 [[X:%.*]], 3
+; CHECK-NEXT:    [[R:%.*]] = icmp eq i8 [[X]], 7
+; CHECK-NEXT:    call void @use.i8(i8 [[V]])
+; CHECK-NEXT:    ret i1 [[R]]
+;
+  %v = shl nsw i8 %x, 3
+  %r = icmp eq i8 %v, 56
+  call void @use.i8(i8 %v)
+  ret i1 %r
+}
+
+define i1 @simplify_cmp_lshr(i8 %x) {
+; CHECK-LABEL: @simplify_cmp_lshr(
+; CHECK-NEXT:    [[V_MASK:%.*]] = and i8 [[X:%.*]], -8
+; CHECK-NEXT:    [[R:%.*]] = icmp eq i8 [[V_MASK]], -64
+; CHECK-NEXT:    ret i1 [[R]]
+;
+  %v = lshr i8 %x, 3
+  %r = icmp eq i8 %v, 24
+  ret i1 %r
+}
+
+define i1 @simplify_cmp_lshr_fail_shiftout(i8 %x) {
+; CHECK-LABEL: @simplify_cmp_lshr_fail_shiftout(
+; CHECK-NEXT:    ret i1 false
+;
+  %v = lshr i8 %x, 3
+  %r = icmp eq i8 %v, 56
+  ret i1 %r
+}
+
+define i1 @simplify_cmp_lshr_fail_multiuse(i8 %x) {
+; CHECK-LABEL: @simplify_cmp_lshr_fail_multiuse(
+; CHECK-NEXT:    [[V:%.*]] = lshr i8 [[X:%.*]], 3
+; CHECK-NEXT:    [[R:%.*]] = icmp eq i8 [[V]], 24
+; CHECK-NEXT:    call void @use.i8(i8 [[V]])
+; CHECK-NEXT:    ret i1 [[R]]
+;
+  %v = lshr i8 %x, 3
+  %r = icmp eq i8 %v, 24
+  call void @use.i8(i8 %v)
+  ret i1 %r
+}
+
+define i1 @simplify_cmp_lshr_okay_multiuse(i8 %x) {
+; CHECK-LABEL: @simplify_cmp_lshr_okay_multiuse(
+; CHECK-NEXT:    [[V:%.*]] = lshr exact i8 [[X:%.*]], 3
+; CHECK-NEXT:    [[R:%.*]] = icmp eq i8 [[X]], -64
+; CHECK-NEXT:    call void @use.i8(i8 [[V]])
+; CHECK-NEXT:    ret i1 [[R]]
+;
+  %v = lshr exact i8 %x, 3
+  %r = icmp eq i8 %v, 24
+  call void @use.i8(i8 %v)
+  ret i1 %r
+}
+
+define i1 @simplify_cmp_ashr(i8 %x) {
+; CHECK-LABEL: @simplify_cmp_ashr(
+; CHECK-NEXT:    [[V_MASK:%.*]] = and i8 [[X:%.*]], -8
+; CHECK-NEXT:    [[R:%.*]] = icmp eq i8 [[V_MASK]], 96
+; CHECK-NEXT:    ret i1 [[R]]
+;
+  %v = ashr i8 %x, 3
+  %r = icmp eq i8 %v, 12
+  ret i1 %r
+}
+
+define i1 @simplify_cmp_ashr_fail_shiftout(i8 %x) {
+; CHECK-LABEL: @simplify_cmp_ashr_fail_shiftout(
+; CHECK-NEXT:    ret i1 false
+;
+  %v = ashr i8 %x, 3
+  %r = icmp eq i8 %v, 56
+  ret i1 %r
+}
+
+define i1 @simplify_cmp_ashr_fail_multiuse(i8 %x) {
+; CHECK-LABEL: @simplify_cmp_ashr_fail_multiuse(
+; CHECK-NEXT:    [[V:%.*]] = ashr i8 [[X:%.*]], 3
+; CHECK-NEXT:    [[R:%.*]] = icmp eq i8 [[V]], 12
+; CHECK-NEXT:    call void @use.i8(i8 [[V]])
+; CHECK-NEXT:    ret i1 [[R]]
+;
+  %v = ashr i8 %x, 3
+  %r = icmp eq i8 %v, 12
+  call void @use.i8(i8 %v)
+  ret i1 %r
+}
+
+define i1 @simplify_cmp_ashr_okay_multiuse(i8 %x) {
+; CHECK-LABEL: @simplify_cmp_ashr_okay_multiuse(
+; CHECK-NEXT:    [[V:%.*]] = ashr exact i8 [[X:%.*]], 3
+; CHECK-NEXT:    [[R:%.*]] = icmp eq i8 [[X]], -96
+; CHECK-NEXT:    call void @use.i8(i8 [[V]])
+; CHECK-NEXT:    ret i1 [[R]]
+;
+  %v = ashr exact i8 %x, 3
+  %r = icmp eq i8 %v, -12
+  call void @use.i8(i8 %v)
+  ret i1 %r
+}
+
+define i1 @simplify_cmp_bitreverse(i8 %x) {
+; CHECK-LABEL: @simplify_cmp_bitreverse(
+; CHECK-NEXT:    [[R:%.*]] = icmp eq i8 [[X:%.*]], -34
+; CHECK-NEXT:    ret i1 [[R]]
+;
+  %v = call i8 @llvm.bitreverse.i8(i8 %x)
+  %r = icmp eq i8 %v, 123
+  ret i1 %r
+}
+
+define i1 @simplify_cmp_bswap(i16 %x) {
+; CHECK-LABEL: @simplify_cmp_bswap(
+; CHECK-NEXT:    [[R:%.*]] = icmp eq i16 [[X:%.*]], 14640
+; CHECK-NEXT:    ret i1 [[R]]
+;
+  %v = call i16 @llvm.bswap.i16(i16 %x)
+  %r = icmp eq i16 %v, 12345
+  ret i1 %r
+}
+
+define i1 @simplify_cmp_fshr(i8 %x) {
+; CHECK-LABEL: @simplify_cmp_fshr(
+; CHECK-NEXT:    [[R:%.*]] = icmp eq i8 [[X:%.*]], -37
+; CHECK-NEXT:    ret i1 [[R]]
+;
+  %v = call i8 @llvm.fshr.i8(i8 %x, i8 %x, i8 3)
+  %r = icmp eq i8 %v, 123
+  ret i1 %r
+}
+
+define i1 @simplify_cmp_fshr_fail_not_rotate(i8 %x, i8 %y) {
+; CHECK-LABEL: @simplify_cmp_fshr_fail_not_rotate(
+; CHECK-NEXT:    [[V:%.*]] = call i8 @llvm.fshl.i8(i8 [[X:%.*]], i8 [[Y:%.*]], i8 5)
+; CHECK-NEXT:    [[R:%.*]] = icmp eq i8 [[V]], 123
+; CHECK-NEXT:    ret i1 [[R]]
+;
+  %v = call i8 @llvm.fshr.i8(i8 %x, i8 %y, i8 3)
+  %r = icmp eq i8 %v, 123
+  ret i1 %r
+}
+
+define i1 @simplify_cmp_fshl(i8 %x) {
+; CHECK-LABEL: @simplify_cmp_fshl(
+; CHECK-NEXT:    [[R:%.*]] = icmp eq i8 [[X:%.*]], 66
+; CHECK-NEXT:    ret i1 [[R]]
+;
+  %v = call i8 @llvm.fshl.i8(i8 %x, i8 %x, i8 7)
+  %r = icmp eq i8 %v, 33
+  ret i1 %r
+}
+
+define i1 @simplify_cmp_fshl_fail_not_rotate(i8 %x, i8 %y) {
+; CHECK-LABEL: @simplify_cmp_fshl_fail_not_rotate(
+; CHECK-NEXT:    [[V:%.*]] = call i8 @llvm.fshl.i8(i8 [[X:%.*]], i8 [[Y:%.*]], i8 7)
+; CHECK-NEXT:    [[R:%.*]] = icmp eq i8 [[V]], 33
+; CHECK-NEXT:    ret i1 [[R]]
+;
+  %v = call i8 @llvm.fshl.i8(i8 %x, i8 %y, i8 7)
+  %r = icmp eq i8 %v, 33
+  ret i1 %r
+}
+
+define i8 @simplify_switch_or_disjoint(i8 %x) {
+; CHECK-LABEL: @simplify_switch_or_disjoint(
+; CHECK-NEXT:    [[V:%.*]] = or disjoint i8 [[X:%.*]], 12
+; CHECK-NEXT:    switch i8 [[V]], label [[DEFAULT:%.*]] [
+; CHECK-NEXT:      i8 12, label [[L12:%.*]]
+; CHECK-NEXT:      i8 44, label [[L44:%.*]]
+; CHECK-NEXT:      i8 45, label [[L45:%.*]]
+; CHECK-NEXT:    ]
+; CHECK:       l12:
+; CHECK-NEXT:    ret i8 12
+; CHECK:       l44:
+; CHECK-NEXT:    ret i8 44
+; CHECK:       l45:
+; CHECK-NEXT:    ret i8 40
+; CHECK:       default:
+; CHECK-NEXT:    ret i8 -1
+;
+  %v = or disjoint i8 %x, 12
+  switch i8 %v, label %default[
+  i8 12, label %l12
+  i8 44, label %l44
+  i8 45, label %l45
+  ]
+
+l12:
+  ret i8 12
+l44:
+  ret i8 44
+l45:
+  ret i8 40
+default:
+  ret i8 -1
+}
+
+define i8 @simplify_switch_add(i8 %x) {
+; CHECK-LABEL: @simplify_switch_add(
+; CHECK-NEXT:    [[V:%.*]] = add i8 [[X:%.*]], 12
+; CHECK-NEXT:    call void @use.i8(i8 [[V]])
+; CHECK-NEXT:    switch i8 [[X]], label [[DEFAULT:%.*]] [
+; CHECK-NEXT:      i8 0, label [[L12:%.*]]
+; CHECK-NEXT:      i8 32, label [[L44:%.*]]
+; CHECK-NEXT:      i8 33, label [[L45:%.*]]
+; CHECK-NEXT:    ]
+; CHECK:       l12:
+; CHECK-NEXT:    ret i8 12
+; CHECK:       l44:
+; CHECK-NEXT:    ret i8 44
+; CHECK:       l45:
+; CHECK-NEXT:    ret i8 40
+; CHECK:       default:
+; CHECK-NEXT:    ret i8 -1
+;
+  %v = add i8 %x, 12
+  call void @use.i8(i8 %v)
+  switch i8 %v, label %default[
+  i8 12, label %l12
+  i8 44, label %l44
+  i8 45, label %l45
+  ]
+
+l12:
+  ret i8 12
+l44:
+  ret i8 44
+l45:
+  ret i8 40
+default:
+  ret i8 -1
+}
+
+define i8 @simplify_switch_sub(i8 %x) {
+; CHECK-LABEL: @simplify_switch_sub(
+; CHECK-NEXT:    [[V:%.*]] = sub i8 12, [[X:%.*]]
+; CHECK-NEXT:    call void @use.i8(i8 [[V]])
+; CHECK-NEXT:    switch i8 [[X]], label [[DEFAULT:%.*]] [
+; CHECK-NEXT:      i8 0, label [[L12:%.*]]
+; CHECK-NEXT:      i8 -32, label [[L44:%.*]]
+; CHECK-NEXT:      i8 -33, label [[L45:%.*]]
+; CHECK-NEXT:    ]
+; CHECK:       l12:
+; CHECK-NEXT:    ret i8 12
+; CHECK:       l44:
+; CHECK-NEXT:    ret i8 44
+; CHECK:       l45:
+; CHECK-NEXT:    ret i8 40
+; CHECK:       default:
+; CHECK-NEXT:    ret i8 -1
+;
+  %v = sub i8 12, %x
+  call void @use.i8(i8 %v)
+  switch i8 %v, label %default[
+  i8 12, label %l12
+  i8 44, label %l44
+  i8 45, label %l45
+  ]
+
+l12:
+  ret i8 12
+l44:
+  ret i8 44
+l45:
+  ret i8 40
+default:
+  ret i8 -1
+}
+
+define i8 @simplify_switch_xor(i8 %x) {
+; CHECK-LABEL: @simplify_switch_xor(
+; CHECK-NEXT:    [[V:%.*]] = xor i8 [[X:%.*]], 12
+; CHECK-NEXT:    call void @use.i8(i8 [[V]])
+; CHECK-NEXT:    switch i8 [[V]], label [[DEFAULT:%.*]] [
+; CHECK-NEXT:      i8 12, label [[L12:%.*]]
+; CHECK-NEXT:      i8 44, label [[L44:%.*]]
+; CHECK-NEXT:      i8 45, label [[L45:%.*]]
+; CHECK-NEXT:    ]
+; CHECK:       l12:
+; CHECK-NEXT:    ret i8 12
+; CHECK:       l44:
+; CHECK-NEXT:    ret i8 44
+; CHECK:       l45:
+; CHECK-NEXT:    ret i8 40
+; CHECK:       default:
+; CHECK-NEXT:    ret i8 -1
+;
+  %v = xor i8 %x, 12
+  call void @use.i8(i8 %v)
+  switch i8 %v, label %default[
+  i8 12, label %l12
+  i8 44, label %l44
+  i8 45, label %l45
+  ]
+
+l12:
+  ret i8 12
+l44:
+  ret i8 44
+l45:
+  ret i8 40
+default:
+  ret i8 -1
+
+}
+
+define i8 @simplify_switch_mul_udiv(i8 %x) {
+; CHECK-LABEL: @simplify_switch_mul_udiv(
+; CHECK-NEXT:    [[V:%.*]] = mul nuw i8 [[X:%.*]], 12
+; CHECK-NEXT:    call void @use.i8(i8 [[V]])
+; CHECK-NEXT:    switch i8 [[V]], label [[DEFAULT:%.*]] [
+; CHECK-NEXT:      i8 12, label [[L12:%.*]]
+; CHECK-NEXT:      i8 48, label [[L48:%.*]]
+; CHECK-NEXT:      i8 60, label [[L60:%.*]]
+; CHECK-NEXT:      i8 0, label [[L0:%.*]]
+; CHECK-NEXT:    ]
+; CHECK:       l12:
+; CHECK-NEXT:    ret i8 12
+; CHECK:       l48:
+; CHECK-NEXT:    ret i8 44
+; CHECK:       l60:
+; CHECK-NEXT:    ret i8 3
+; CHECK:       l0:
+; CHECK-NEXT:    ret i8 9
+; CHECK:       default:
+; CHECK-NEXT:    ret i8 -1
+;
+  %v = mul nuw i8 %x, 12
+  call void @use.i8(i8 %v)
+  switch i8 %v, label %default[
+  i8 12, label %l12
+  i8 48, label %l48
+  i8 60, label %l60
+  i8 0, label %l0
+  ]
+
+l12:
+  ret i8 12
+l48:
+  ret i8 44
+l60:
+  ret i8 3
+l0:
+  ret i8 9
+default:
+  ret i8 -1
+}
+
+define i8 @simplify_switch_mul_udiv_fail_bad_rem(i8 %x) {
+; CHECK-LABEL: @simplify_switch_mul_udiv_fail_bad_rem(
+; CHECK-NEXT:    [[V:%.*]] = mul nuw i8 [[X:%.*]], 12
+; CHECK-NEXT:    call void @use.i8(i8 [[V]])
+; CHECK-NEXT:    switch i8 [[V]], label [[DEFAULT:%.*]] [
+; CHECK-NEXT:      i8 12, label [[L12:%.*]]
+; CHECK-NEXT:      i8 47, label [[L48:%.*]]
+; CHECK-NEXT:      i8 60, label [[L60:%.*]]
+; CHECK-NEXT:      i8 0, label [[L0:%.*]]
+; CHECK-NEXT:    ]
+; CHECK:       l12:
+; CHECK-NEXT:    ret i8 12
+; CHECK:       l48:
+; CHECK-NEXT:    ret i8 44
+; CHECK:       l60:
+; CHECK-NEXT:    ret i8 3
+; CHECK:       l0:
+; CHECK-NEXT:    ret i8 9
+; CHECK:       default:
+; CHECK-NEXT:    ret i8 -1
+;
+  %v = mul nuw i8 %x, 12
+  call void @use.i8(i8 %v)
+  switch i8 %v, label %default[
+  i8 12, label %l12
+  i8 47, label %l48
+  i8 60, label %l60
+  i8 0, label %l0
+  ]
+
+l12:
+  ret i8 12
+l48:
+  ret i8 44
+l60:
+  ret i8 3
+l0:
+  ret i8 9
+default:
+  ret i8 -1
+}
+
+define i8 @simplify_switch_mul_sdiv(i8 %x) {
+; CHECK-LABEL: @simplify_switch_mul_sdiv(
+; CHECK-NEXT:    [[V:%.*]] = mul nuw i8 [[X:%.*]], 12
+; CHECK-NEXT:    call void @use.i8(i8 [[V]])
+; CHECK-NEXT:    switch i8 [[V]], label [[DEFAULT:%.*]] [
+; CHECK-NEXT:      i8 -12, label [[L12:%.*]]
+; CHECK-NEXT:      i8 48, label [[L48:%.*]]
+; CHECK-NEXT:      i8 -60, label [[L60:%.*]]
+; CHECK-NEXT:      i8 0, label [[L0:%.*]]
+; CHECK-NEXT:    ]
+; CHECK:       l12:
+; CHECK-NEXT:    ret i8 12
+; CHECK:       l48:
+; CHECK-NEXT:    ret i8 44
+; CHECK:       l60:
+; CHECK-NEXT:    ret i8 3
+; CHECK:       l0:
+; CHECK-NEXT:    ret i8 9
+; CHECK:       default:
+; CHECK-NEXT:    ret i8 -1
+;
+  %v = mul nuw i8 %x, 12
+  call void @use.i8(i8 %v)
+  switch i8 %v, label %default[
+  i8 -12, label %l12
+  i8 48, label %l48
+  i8 -60, label %l60
+  i8 0, label %l0
+  ]
+
+l12:
+  ret i8 12
+l48:
+  ret i8 44
+l60:
+  ret i8 3
+l0:
+  ret i8 9
+default:
+  ret i8 -1
+}
+
+define i8 @simplify_switch_mul_sdiv_fail_bad_rem(i8 %x) {
+; CHECK-LABEL: @simplify_switch_mul_sdiv_fail_bad_rem(
+; CHECK-NEXT:    [[V:%.*]] = mul nuw i8 [[X:%.*]], 12
+; CHECK-NEXT:    call void @use.i8(i8 [[V]])
+; CHECK-NEXT:    switch i8 [[V]], label [[DEFAULT:%.*]] [
+; CHECK-NEXT:      i8 -12, label [[L12:%.*]]
+; CHECK-NEXT:      i8 -47, label [[L48:%.*]]
+; CHECK-NEXT:      i8 60, label [[L60:%.*]]
+; CHECK-NEXT:      i8 0, label [[L0:%.*]]
+; CHECK-NEXT:    ]
+; CHECK:       l12:
+; CHECK-NEXT:    ret i8 12
+; CHECK:       l48:
+; CHECK-NEXT:    ret i8 44
+; CHECK:       l60:
+; CHECK-NEXT:    ret i8 3
+; CHECK:       l0:
+; CHECK-NEXT:    ret i8 9
+; CHECK:       default:
+; CHECK-NEXT:    ret i8 -1
+;
+  %v = mul nuw i8 %x, 12
+  call void @use.i8(i8 %v)
+  switch i8 %v, label %default[
+  i8 -12, label %l12
+  i8 -47, label %l48
+  i8 60, label %l60
+  i8 0, label %l0
+  ]
+
+l12:
+  ret i8 12
+l48:
+  ret i8 44
+l60:
+  ret i8 3
+l0:
+  ret i8 9
+default:
+  ret i8 -1
+}
+
+define i8 @simplify_switch_udiv(i8 %x) {
+; CHECK-LABEL: @simplify_switch_udiv(
+; CHECK-NEXT:    [[V:%.*]] = udiv exact i8 [[X:%.*]], 12
+; CHECK-NEXT:    call void @use.i8(i8 [[V]])
+; CHECK-NEXT:    switch i8 [[V]], label [[DEFAULT:%.*]] [
+; CHECK-NEXT:      i8 12, label [[L12:%.*]]
+; CHECK-NEXT:      i8 3, label [[L48:%.*]]
+; CHECK-NEXT:      i8 9, label [[L60:%.*]]
+; CHECK-NEXT:      i8 0, label [[L0:%.*]]
+; CHECK-NEXT:    ]
+; CHECK:       l12:
+; CHECK-NEXT:    ret i8 12
+; CHECK:       l48:
+; CHECK-NEXT:    ret i8 44
+; CHECK:       l60:
+; CHECK-NEXT:    ret i8 3
+; CHECK:       l0:
+; CHECK-NEXT:    ret i8 9
+; CHECK:       default:
+; CHECK-NEXT:    ret i8 -1
+;
+  %v = udiv exact i8 %x, 12
+  call void @use.i8(i8 %v)
+  switch i8 %v, label %default[
+  i8 12, label %l12
+  i8 3, label %l48
+  i8 9, label %l60
+  i8 0, label %l0
+  ]
+
+l12:
+  ret i8 12
+l48:
+  ret i8 44
+l60:
+  ret i8 3
+l0:
+  ret i8 9
+default:
+  ret i8 -1
+}
+
+define i8 @simplify_switch_udiv_fail_overflow(i8 %x) {
+; CHECK-LABEL: @simplify_switch_udiv_fail_overflow(
+; CHECK-NEXT:    [[V:%.*]] = udiv exact i8 [[X:%.*]], 12
+; CHECK-NEXT:    call void @use.i8(i8 [[V]])
+; CHECK-NEXT:    switch i8 [[V]], label [[DEFAULT:%.*]] [
+; CHECK-NEXT:      i8 12, label [[L12:%.*]]
+; CHECK-NEXT:      i8 50, label [[L48:%.*]]
+; CHECK-NEXT:      i8 9, label [[L60:%.*]]
+; CHECK-NEXT:      i8 0, label [[L0:%.*]]
+; CHECK-NEXT:    ]
+; CHECK:       l12:
+; CHECK-NEXT:    ret i8 12
+; CHECK:       l48:
+; CHECK-NEXT:    ret i8 44
+; CHECK:       l60:
+; CHECK-NEXT:    ret i8 3
+; CHECK:       l0:
+; CHECK-NEXT:    ret i8 9
+; CHECK:       default:
+; CHECK-NEXT:    ret i8 -1
+;
+  %v = udiv exact i8 %x, 12
+  call void @use.i8(i8 %v)
+  switch i8 %v, label %default[
+  i8 12, label %l12
+  i8 50, label %l48
+  i8 9, label %l60
+  i8 0, label %l0
+  ]
+
+l12:
+  ret i8 12
+l48:
+  ret i8 44
+l60:
+  ret i8 3
+l0:
+  ret i8 9
+default:
+  ret i8 -1
+}
+
+define i8 @simplify_switch_sdiv(i8 %x) {
+; CHECK-LABEL: @simplify_switch_sdiv(
+; CHECK-NEXT:    [[V:%.*]] = sdiv exact i8 [[X:%.*]], 12
+; CHECK-NEXT:    call void @use.i8(i8 [[V]])
+; CHECK-NEXT:    switch i8 [[V]], label [[DEFAULT:%.*]] [
+; CHECK-NEXT:      i8 4, label [[L12:%.*]]
+; CHECK-NEXT:      i8 -3, label [[L48:%.*]]
+; CHECK-NEXT:      i8 7, label [[L60:%.*]]
+; CHECK-NEXT:      i8 0, label [[L0:%.*]]
+; CHECK-NEXT:    ]
+; CHECK:       l12:
+; CHECK-NEXT:    ret i8 12
+; CHECK:       l48:
+; CHECK-NEXT:    ret i8 44
+; CHECK:       l60:
+; CHECK-NEXT:    ret i8 3
+; CHECK:       l0:
+; CHECK-NEXT:    ret i8 9
+; CHECK:       default:
+; CHECK-NEXT:    ret i8 -1
+;
+  %v = sdiv exact i8 %x, 12
+  call void @use.i8(i8 %v)
+  switch i8 %v, label %default[
+  i8 4, label %l12
+  i8 -3, label %l48
+  i8 7, label %l60
+  i8 0, label %l0
+  ]
+
+l12:
+  ret i8 12
+l48:
+  ret i8 44
+l60:
+  ret i8 3
+l0:
+  ret i8 9
+default:
+  ret i8 -1
+}
+
+define i8 @simplify_switch_sdiv_fail_overflow(i8 %x) {
+; CHECK-LABEL: @simplify_switch_sdiv_fail_overflow(
+; CHECK-NEXT:    [[V:%.*]] = udiv exact i8 [[X:%.*]], 12
+; CHECK-NEXT:    switch i8 [[V]], label [[DEFAULT:%.*]] [
+; CHECK-NEXT:      i8 4, label [[L12:%.*]]
+; CHECK-NEXT:      i8 -3, label [[L48:%.*]]
+; CHECK-NEXT:      i8 12, label [[L60:%.*]]
+; CHECK-NEXT:      i8 0, label [[L0:%.*]]
+; CHECK-NEXT:    ]
+; CHECK:       l12:
+; CHECK-NEXT:    ret i8 12
+; CHECK:       l48:
+; CHECK-NEXT:    ret i8 44
+; CHECK:       l60:
+; CHECK-NEXT:    ret i8 3
+; CHECK:       l0:
+; CHECK-NEXT:    ret i8 9
+; CHECK:       default:
+; CHECK-NEXT:    ret i8 -1
+;
+  %v = udiv exact i8 %x, 12
+  switch i8 %v, label %default[
+  i8 4, label %l12
+  i8 -3, label %l48
+  i8 12, label %l60
+  i8 0, label %l0
+  ]
+
+l12:
+  ret i8 12
+l48:
+  ret i8 44
+l60:
+  ret i8 3
+l0:
+  ret i8 9
+default:
+  ret i8 -1
+}
+
+define i8 @simplify_switch_zext(i4 %x) {
+; CHECK-LABEL: @simplify_switch_zext(
+; CHECK-NEXT:    switch i4 [[X:%.*]], label [[DEFAULT:%.*]] [
+; CHECK-NEXT:      i4 4, label [[L12:%.*]]
+; CHECK-NEXT:      i4 3, label [[L48:%.*]]
+; CHECK-NEXT:      i4 -4, label [[L60:%.*]]
+; CHECK-NEXT:      i4 0, label [[L0:%.*]]
+; CHECK-NEXT:    ]
+; CHECK:       l12:
+; CHECK-NEXT:    ret i8 12
+; CHECK:       l48:
+; CHECK-NEXT:    ret i8 44
+; CHECK:       l60:
+; CHECK-NEXT:    ret i8 3
+; CHECK:       l0:
+; CHECK-NEXT:    ret i8 9
+; CHECK:       default:
+; CHECK-NEXT:    ret i8 -1
+;
+  %v = zext i4 %x to i8
+  switch i8 %v, label %default[
+  i8 4, label %l12
+  i8 3, label %l48
+  i8 12, label %l60
+  i8 0, label %l0
+  ]
+
+l12:
+  ret i8 12
+l48:
+  ret i8 44
+l60:
+  ret i8 3
+l0:
+  ret i8 9
+default:
+  ret i8 -1
+}
+
+define i8 @simplify_switch_zext_fail_out_of_bounds(i4 %x) {
+; CHECK-LABEL: @simplify_switch_zext_fail_out_of_bounds(
+; CHECK-NEXT:    [[V:%.*]] = zext i4 [[X:%.*]] to i8
+; CHECK-NEXT:    switch i8 [[V]], label [[DEFAULT:%.*]] [
+; CHECK-NEXT:      i8 16, label [[L12:%.*]]
+; CHECK-NEXT:      i8 3, label [[L48:%.*]]
+; CHECK-NEXT:      i8 12, label [[L60:%.*]]
+; CHECK-NEXT:      i8 0, label [[L0:%.*]]
+; CHECK-NEXT:    ]
+; CHECK:       l12:
+; CHECK-NEXT:    ret i8 12
+; CHECK:       l48:
+; CHECK-NEXT:    ret i8 44
+; CHECK:       l60:
+; CHECK-NEXT:    ret i8 3
+; CHECK:       l0:
+; CHECK-NEXT:    ret i8 9
+; CHECK:       default:
+; CHECK-NEXT:    ret i8 -1
+;
+  %v = zext i4 %x to i8
+  switch i8 %v, label %default[
+  i8 16, label %l12
+  i8 3, label %l48
+  i8 12, label %l60
+  i8 0, label %l0
+  ]
+
+l12:
+  ret i8 12
+l48:
+  ret i8 44
+l60:
+  ret i8 3
+l0:
+  ret i8 9
+default:
+  ret i8 -1
+}
+
+define i8 @simplify_switch_sext(i4 %x) {
+; CHECK-LABEL: @simplify_switch_sext(
+; CHECK-NEXT:    [[V:%.*]] = zext i4 [[X:%.*]] to i8
+; CHECK-NEXT:    switch i8 [[V]], label [[DEFAULT:%.*]] [
+; CHECK-NEXT:      i8 -4, label [[L12:%.*]]
+; CHECK-NEXT:      i8 3, label [[L48:%.*]]
+; CHECK-NEXT:      i8 12, label [[L60:%.*]]
+; CHECK-NEXT:      i8 0, label [[L0:%.*]]
+; CHECK-NEXT:    ]
+; CHECK:       l12:
+; CHECK-NEXT:    ret i8 12
+; CHECK:       l48:
+; CHECK-NEXT:    ret i8 44
+; CHECK:       l60:
+; CHECK-NEXT:    ret i8 3
+; CHECK:       l0:
+; CHECK-NEXT:    ret i8 9
+; CHECK:       default:
+; CHECK-NEXT:    ret i8 -1
+;
+  %v = zext i4 %x to i8
+  switch i8 %v, label %default[
+  i8 -4, label %l12
+  i8 3, label %l48
+  i8 12, label %l60
+  i8 0, label %l0
+  ]
+
+l12:
+  ret i8 12
+l48:
+  ret i8 44
+l60:
+  ret i8 3
+l0:
+  ret i8 9
+default:
+  ret i8 -1
+}
+
+define i8 @simplify_switch_sext_fail_out_of_bounds(i4 %x) {
+; CHECK-LABEL: @simplify_switch_sext_fail_out_of_bounds(
+; CHECK-NEXT:    [[V:%.*]] = zext i4 [[X:%.*]] to i8
+; CHECK-NEXT:    switch i8 [[V]], label [[DEFAULT:%.*]] [
+; CHECK-NEXT:      i8 -4, label [[L12:%.*]]
+; CHECK-NEXT:      i8 16, label [[L48:%.*]]
+; CHECK-NEXT:      i8 12, label [[L60:%.*]]
+; CHECK-NEXT:      i8 0, label [[L0:%.*]]
+; CHECK-NEXT:    ]
+; CHECK:       l12:
+; CHECK-NEXT:    ret i8 12
+; CHECK:       l48:
+; CHECK-NEXT:    ret i8 44
+; CHECK:       l60:
+; CHECK-NEXT:    ret i8 3
+; CHECK:       l0:
+; CHECK-NEXT:    ret i8 9
+; CHECK:       default:
+; CHECK-NEXT:    ret i8 -1
+;
+  %v = zext i4 %x to i8
+  switch i8 %v, label %default[
+  i8 -4, label %l12
+  i8 16, label %l48
+  i8 12, label %l60
+  i8 0, label %l0
+  ]
+
+l12:
+  ret i8 12
+l48:
+  ret i8 44
+l60:
+  ret i8 3
+l0:
+  ret i8 9
+default:
+  ret i8 -1
+}
+
+define i8 @simplify_switch_shl(i8 %x) {
+; CHECK-LABEL: @simplify_switch_shl(
+; CHECK-NEXT:    [[TMP1:%.*]] = and i8 [[X:%.*]], 63
+; CHECK-NEXT:    switch i8 [[TMP1]], label [[DEFAULT:%.*]] [
+; CHECK-NEXT:      i8 61, label [[L12:%.*]]
+; CHECK-NEXT:      i8 4, label [[L48:%.*]]
+; CHECK-NEXT:      i8 15, label [[L60:%.*]]
+; CHECK-NEXT:      i8 0, label [[L0:%.*]]
+; CHECK-NEXT:    ]
+; CHECK:       l12:
+; CHECK-NEXT:    ret i8 12
+; CHECK:       l48:
+; CHECK-NEXT:    ret i8 44
+; CHECK:       l60:
+; CHECK-NEXT:    ret i8 3
+; CHECK:       l0:
+; CHECK-NEXT:    ret i8 9
+; CHECK:       default:
+; CHECK-NEXT:    ret i8 -1
+;
+  %v = shl i8 %x, 2
+  switch i8 %v, label %default[
+  i8 -12, label %l12
+  i8 16, label %l48
+  i8 60, label %l60
+  i8 0, label %l0
+  ]
+
+l12:
+  ret i8 12
+l48:
+  ret i8 44
+l60:
+  ret i8 3
+l0:
+  ret i8 9
+default:
+  ret i8 -1
+}
+
+define i8 @simplify_switch_shl_fail_shiftout(i8 %x) {
+; CHECK-LABEL: @simplify_switch_shl_fail_shiftout(
+; CHECK-NEXT:    [[V:%.*]] = shl i8 [[X:%.*]], 2
+; CHECK-NEXT:    switch i8 [[V]], label [[DEFAULT:%.*]] [
+; CHECK-NEXT:      i8 -12, label [[L12:%.*]]
+; CHECK-NEXT:      i8 16, label [[L48:%.*]]
+; CHECK-NEXT:      i8 2, label [[L60:%.*]]
+; CHECK-NEXT:      i8 0, label [[L0:%.*]]
+; CHECK-NEXT:    ]
+; CHECK:       l12:
+; CHECK-NEXT:    ret i8 12
+; CHECK:       l48:
+; CHECK-NEXT:    ret i8 44
+; CHECK:       l60:
+; CHECK-NEXT:    ret i8 3
+; CHECK:       l0:
+; CHECK-NEXT:    ret i8 9
+; CHECK:       default:
+; CHECK-NEXT:    ret i8 -1
+;
+  %v = shl i8 %x, 2
+  switch i8 %v, label %default[
+  i8 -12, label %l12
+  i8 16, label %l48
+  i8 2, label %l60
+  i8 0, label %l0
+  ]
+
+l12:
+  ret i8 12
+l48:
+  ret i8 44
+l60:
+  ret i8 3
+l0:
+  ret i8 9
+default:
+  ret i8 -1
+}
+
+define i8 @simplify_switch_shl2(i8 %x) {
+; CHECK-LABEL: @simplify_switch_shl2(
+; CHECK-NEXT:    [[V:%.*]] = shl nsw i8 [[X:%.*]], 2
+; CHECK-NEXT:    call void @use.i8(i8 [[V]])
+; CHECK-NEXT:    switch i8 [[X]], label [[DEFAULT:%.*]] [
+; CHECK-NEXT:      i8 -3, label [[L12:%.*]]
+; CHECK-NEXT:      i8 4, label [[L48:%.*]]
+; CHECK-NEXT:      i8 15, label [[L60:%.*]]
+; CHECK-NEXT:      i8 0, label [[L0:%.*]]
+; CHECK-NEXT:    ]
+; CHECK:       l12:
+; CHECK-NEXT:    ret i8 12
+; CHECK:       l48:
+; CHECK-NEXT:    ret i8 44
+; CHECK:       l60:
+; CHECK-NEXT:    ret i8 3
+; CHECK:       l0:
+; CHECK-NEXT:    ret i8 9
+; CHECK:       default:
+; CHECK-NEXT:    ret i8 -1
+;
+  %v = shl nsw i8 %x, 2
+  call void @use.i8(i8 %v)
+  switch i8 %v, label %default[
+  i8 -12, label %l12
+  i8 16, label %l48
+  i8 60, label %l60
+  i8 0, label %l0
+  ]
+
+l12:
+  ret i8 12
+l48:
+  ret i8 44
+l60:
+  ret i8 3
+l0:
+  ret i8 9
+default:
+  ret i8 -1
+}
+
+define i8 @simplify_switch_shl_fail_multiuse(i8 %x) {
+; CHECK-LABEL: @simplify_switch_shl_fail_multiuse(
+; CHECK-NEXT:    [[V:%.*]] = shl i8 [[X:%.*]], 2
+; CHECK-NEXT:    call void @use.i8(i8 [[V]])
+; CHECK-NEXT:    switch i8 [[V]], label [[DEFAULT:%.*]] [
+; CHECK-NEXT:      i8 -12, label [[L12:%.*]]
+; CHECK-NEXT:      i8 16, label [[L48:%.*]]
+; CHECK-NEXT:      i8 60, label [[L60:%.*]]
+; CHECK-NEXT:      i8 0, label [[L0:%.*]]
+; CHECK-NEXT:    ]
+; CHECK:       l12:
+; CHECK-NEXT:    ret i8 12
+; CHECK:       l48:
+; CHECK-NEXT:    ret i8 44
+; CHECK:       l60:
+; CHECK-NEXT:    ret i8 3
+; CHECK:       l0:
+; CHECK-NEXT:    ret i8 9
+; CHECK:       default:
+; CHECK-NEXT:    ret i8 -1
+;
+  %v = shl i8 %x, 2
+  call void @use.i8(i8 %v)
+  switch i8 %v, label %default[
+  i8 -12, label %l12
+  i8 16, label %l48
+  i8 60, label %l60
+  i8 0, label %l0
+  ]
+
+l12:
+  ret i8 12
+l48:
+  ret i8 44
+l60:
+  ret i8 3
+l0:
+  ret i8 9
+default:
+  ret i8 -1
+}
+
+define i8 @simplify_switch_shl3(i8 %x) {
+; CHECK-LABEL: @simplify_switch_shl3(
+; CHECK-NEXT:    [[V:%.*]] = shl nuw i8 [[X:%.*]], 2
+; CHECK-NEXT:    call void @use.i8(i8 [[V]])
+; CHECK-NEXT:    switch i8 [[X]], label [[DEFAULT:%.*]] [
+; CHECK-NEXT:      i8 61, label [[L12:%.*]]
+; CHECK-NEXT:      i8 4, label [[L48:%.*]]
+; CHECK-NEXT:      i8 15, label [[L60:%.*]]
+; CHECK-NEXT:      i8 0, label [[L0:%.*]]
+; CHECK-NEXT:    ]
+; CHECK:       l12:
+; CHECK-NEXT:    ret i8 12
+; CHECK:       l48:
+; CHECK-NEXT:    ret i8 44
+; CHECK:       l60:
+; CHECK-NEXT:    ret i8 3
+; CHECK:       l0:
+; CHECK-NEXT:    ret i8 9
+; CHECK:       default:
+; CHECK-NEXT:    ret i8 -1
+;
+  %v = shl nuw i8 %x, 2
+  call void @use.i8(i8 %v)
+  switch i8 %v, label %default[
+  i8 -12, label %l12
+  i8 16, label %l48
+  i8 60, label %l60
+  i8 0, label %l0
+  ]
+
+l12:
+  ret i8 12
+l48:
+  ret i8 44
+l60:
+  ret i8 3
+l0:
+  ret i8 9
+default:
+  ret i8 -1
+}
+
+define i8 @simplify_switch_lshr(i8 %x) {
+; CHECK-LABEL: @simplify_switch_lshr(
+; CHECK-NEXT:    [[V:%.*]] = lshr exact i8 [[X:%.*]], 2
+; CHECK-NEXT:    call void @use.i8(i8 [[V]])
+; CHECK-NEXT:    switch i8 [[V]], label [[DEFAULT:%.*]] [
+; CHECK-NEXT:      i8 12, label [[L12:%.*]]
+; CHECK-NEXT:      i8 16, label [[L48:%.*]]
+; CHECK-NEXT:      i8 30, label [[L60:%.*]]
+; CHECK-NEXT:      i8 0, label [[L0:%.*]]
+; CHECK-NEXT:    ]
+; CHECK:       l12:
+; CHECK-NEXT:    ret i8 12
+; CHECK:       l48:
+; CHECK-NEXT:    ret i8 44
+; CHECK:       l60:
+; CHECK-NEXT:    ret i8 3
+; CHECK:       l0:
+; CHECK-NEXT:    ret i8 9
+; CHECK:       default:
+; CHECK-NEXT:    ret i8 -1
+;
+  %v = lshr exact i8 %x, 2
+  call void @use.i8(i8 %v)
+  switch i8 %v, label %default[
+  i8 12, label %l12
+  i8 16, label %l48
+  i8 30, label %l60
+  i8 0, label %l0
+  ]
+
+l12:
+  ret i8 12
+l48:
+  ret i8 44
+l60:
+  ret i8 3
+l0:
+  ret i8 9
+default:
+  ret i8 -1
+}
+
+define i8 @simplify_switch_lshr_fail_shiftout(i8 %x) {
+; CHECK-LABEL: @simplify_switch_lshr_fail_shiftout(
+; CHECK-NEXT:    [[V:%.*]] = lshr exact i8 [[X:%.*]], 2
+; CHECK-NEXT:    switch i8 [[V]], label [[DEFAULT:%.*]] [
+; CHECK-NEXT:      i8 12, label [[L12:%.*]]
+; CHECK-NEXT:      i8 16, label [[L48:%.*]]
+; CHECK-NEXT:      i8 30, label [[L60:%.*]]
+; CHECK-NEXT:      i8 -128, label [[L0:%.*]]
+; CHECK-NEXT:    ]
+; CHECK:       l12:
+; CHECK-NEXT:    ret i8 12
+; CHECK:       l48:
+; CHECK-NEXT:    ret i8 44
+; CHECK:       l60:
+; CHECK-NEXT:    ret i8 3
+; CHECK:       l0:
+; CHECK-NEXT:    ret i8 9
+; CHECK:       default:
+; CHECK-NEXT:    ret i8 -1
+;
+  %v = lshr exact i8 %x, 2
+  switch i8 %v, label %default[
+  i8 12, label %l12
+  i8 16, label %l48
+  i8 30, label %l60
+  i8 128, label %l0
+  ]
+
+l12:
+  ret i8 12
+l48:
+  ret i8 44
+l60:
+  ret i8 3
+l0:
+  ret i8 9
+default:
+  ret i8 -1
+}
+
+define i8 @simplify_switch_ashr(i8 %x) {
+; CHECK-LABEL: @simplify_switch_ashr(
+; CHECK-NEXT:    [[V:%.*]] = ashr exact i8 [[X:%.*]], 2
+; CHECK-NEXT:    call void @use.i8(i8 [[V]])
+; CHECK-NEXT:    switch i8 [[V]], label [[DEFAULT:%.*]] [
+; CHECK-NEXT:      i8 -12, label [[L12:%.*]]
+; CHECK-NEXT:      i8 16, label [[L48:%.*]]
+; CHECK-NEXT:      i8 3, label [[L60:%.*]]
+; CHECK-NEXT:      i8 0, label [[L0:%.*]]
+; CHECK-NEXT:    ]
+; CHECK:       l12:
+; CHECK-NEXT:    ret i8 12
+; CHECK:       l48:
+; CHECK-NEXT:    ret i8 44
+; CHECK:       l60:
+; CHECK-NEXT:    ret i8 3
+; CHECK:       l0:
+; CHECK-NEXT:    ret i8 9
+; CHECK:       default:
+; CHECK-NEXT:    ret i8 -1
+;
+  %v = ashr exact i8 %x, 2
+  call void @use.i8(i8 %v)
+  switch i8 %v, label %default[
+  i8 -12, label %l12
+  i8 16, label %l48
+  i8 3, label %l60
+  i8 0, label %l0
+  ]
+
+l12:
+  ret i8 12
+l48:
+  ret i8 44
+l60:
+  ret i8 3
+l0:
+  ret i8 9
+default:
+  ret i8 -1
+}
+
+define i8 @simplify_switch_ashr_fail_shiftout(i8 %x) {
+; CHECK-LABEL: @simplify_switch_ashr_fail_shiftout(
+; CHECK-NEXT:    [[V:%.*]] = ashr i8 [[X:%.*]], 2
+; CHECK-NEXT:    switch i8 [[V]], label [[DEFAULT:%.*]] [
+; CHECK-NEXT:      i8 -12, label [[L12:%.*]]
+; CHECK-NEXT:      i8 16, label [[L48:%.*]]
+; CHECK-NEXT:      i8 3, label [[L60:%.*]]
+; CHECK-NEXT:      i8 -128, label [[L0:%.*]]
+; CHECK-NEXT:    ]
+; CHECK:       l12:
+; CHECK-NEXT:    ret i8 12
+; CHECK:       l48:
+; CHECK-NEXT:    ret i8 44
+; CHECK:       l60:
+; CHECK-NEXT:    ret i8 3
+; CHECK:       l0:
+; CHECK-NEXT:    ret i8 9
+; CHECK:       default:
+; CHECK-NEXT:    ret i8 -1
+;
+  %v = ashr i8 %x, 2
+  switch i8 %v, label %default[
+  i8 -12, label %l12
+  i8 16, label %l48
+  i8 3, label %l60
+  i8 128, label %l0
+  ]
+
+l12:
+  ret i8 12
+l48:
+  ret i8 44
+l60:
+  ret i8 3
+l0:
+  ret i8 9
+default:
+  ret i8 -1
+}
+
+define i8 @simplify_switch_bitreverse(i8 %x) {
+; CHECK-LABEL: @simplify_switch_bitreverse(
+; CHECK-NEXT:    [[V:%.*]] = call i8 @llvm.bitreverse.i8(i8 [[X:%.*]])
+; CHECK-NEXT:    switch i8 [[V]], label [[DEFAULT:%.*]] [
+; CHECK-NEXT:      i8 -12, label [[L12:%.*]]
+; CHECK-NEXT:      i8 16, label [[L48:%.*]]
+; CHECK-NEXT:      i8 30, label [[L60:%.*]]
+; CHECK-NEXT:      i8 -128, label [[L0:%.*]]
+; CHECK-NEXT:    ]
+; CHECK:       l12:
+; CHECK-NEXT:    ret i8 12
+; CHECK:       l48:
+; CHECK-NEXT:    ret i8 44
+; CHECK:       l60:
+; CHECK-NEXT:    ret i8 3
+; CHECK:       l0:
+; CHECK-NEXT:    ret i8 9
+; CHECK:       default:
+; CHECK-NEXT:    ret i8 -1
+;
+  %v = call i8 @llvm.bitreverse.i8(i8 %x)
+  switch i8 %v, label %default[
+  i8 -12, label %l12
+  i8 16, label %l48
+  i8 30, label %l60
+  i8 128, label %l0
+  ]
+
+l12:
+  ret i8 12
+l48:
+  ret i8 44
+l60:
+  ret i8 3
+l0:
+  ret i8 9
+default:
+  ret i8 -1
+}
+
+define i16 @simplify_switch_bswap(i16 %x) {
+; CHECK-LABEL: @simplify_switch_bswap(
+; CHECK-NEXT:    [[V:%.*]] = call i16 @llvm.bswap.i16(i16 [[X:%.*]])
+; CHECK-NEXT:    switch i16 [[V]], label [[DEFAULT:%.*]] [
+; CHECK-NEXT:      i16 -12, label [[L12:%.*]]
+; CHECK-NEXT:      i16 16, label [[L48:%.*]]
+; CHECK-NEXT:      i16 30, label [[L60:%.*]]
+; CHECK-NEXT:      i16 128, label [[L0:%.*]]
+; CHECK-NEXT:    ]
+; CHECK:       l12:
+; CHECK-NEXT:    ret i16 12
+; CHECK:       l48:
+; CHECK-NEXT:    ret i16 44
+; CHECK:       l60:
+; CHECK-NEXT:    ret i16 3
+; CHECK:       l0:
+; CHECK-NEXT:    ret i16 9
+; CHECK:       default:
+; CHECK-NEXT:    ret i16 -1
+;
+  %v = call i16 @llvm.bswap.i16(i16 %x)
+  switch i16 %v, label %default[
+  i16 -12, label %l12
+  i16 16, label %l48
+  i16 30, label %l60
+  i16 128, label %l0
+  ]
+
+l12:
+  ret i16 12
+l48:
+  ret i16 44
+l60:
+  ret i16 3
+l0:
+  ret i16 9
+default:
+  ret i16 -1
+}
+
+define i8 @simplify_switch_fshr(i8 %x) {
+; CHECK-LABEL: @simplify_switch_fshr(
+; CHECK-NEXT:    switch i8 [[V:%.*]], label [[DEFAULT:%.*]] [
+; CHECK-NEXT:      i8 -89, label [[L12:%.*]]
+; CHECK-NEXT:      i8 -128, label [[L0:%.*]]
+; CHECK-NEXT:      i8 -16, label [[L60:%.*]]
+; CHECK-NEXT:      i8 4, label [[L1:%.*]]
+; CHECK-NEXT:    ]
+; CHECK:       l12:
+; CHECK-NEXT:    ret i8 12
+; CHECK:       l48:
+; CHECK-NEXT:    ret i8 44
+; CHECK:       l60:
+; CHECK-NEXT:    ret i8 3
+; CHECK:       l0:
+; CHECK-NEXT:    ret i8 9
+; CHECK:       default:
+; CHECK-NEXT:    ret i8 -1
+;
+  %v = call i8 @llvm.fshr.i8(i8 %x, i8 %x, i8 3)
+  switch i8 %v, label %default[
+  i8 -12, label %l12
+  i8 16, label %l48
+  i8 30, label %l60
+  i8 128, label %l0
+  ]
+
+l12:
+  ret i8 12
+l48:
+  ret i8 44
+l60:
+  ret i8 3
+l0:
+  ret i8 9
+default:
+  ret i8 -1
+}
+
+define i8 @simplify_switch_fshl(i8 %x) {
+; CHECK-LABEL: @simplify_switch_fshl(
+; CHECK-NEXT:    switch i8 [[V:%.*]], label [[DEFAULT:%.*]] [
+; CHECK-NEXT:      i8 -98, label [[L12:%.*]]
+; CHECK-NEXT:      i8 2, label [[L49:%.*]]
+; CHECK-NEXT:      i8 -61, label [[L60:%.*]]
+; CHECK-NEXT:      i8 16, label [[L48:%.*]]
+; CHECK-NEXT:    ]
+; CHECK:       l12:
+; CHECK-NEXT:    ret i8 12
+; CHECK:       l48:
+; CHECK-NEXT:    ret i8 44
+; CHECK:       l60:
+; CHECK-NEXT:    ret i8 3
+; CHECK:       l0:
+; CHECK-NEXT:    ret i8 9
+; CHECK:       default:
+; CHECK-NEXT:    ret i8 -1
+;
+  %v = call i8 @llvm.fshl.i8(i8 %x, i8 %x, i8 3)
+  switch i8 %v, label %default[
+  i8 -12, label %l12
+  i8 16, label %l48
+  i8 30, label %l60
+  i8 128, label %l0
+  ]
+
+l12:
+  ret i8 12
+l48:
+  ret i8 44
+l60:
+  ret i8 3
+l0:
+  ret i8 9
+default:
+  ret i8 -1
+}

>From 8a5b167aeaf71d6ecc0f74383a8da87a903623ce Mon Sep 17 00:00:00 2001
From: Noah Goldstein <goldstein.w.n at gmail.com>
Date: Fri, 22 Mar 2024 15:12:47 -0500
Subject: [PATCH 4/6] [InstCombine] Add helper simplifying Instruction w/
 constants with eq/ne Constants; NFC

We want to be able to simplify these types of relationships in
multiple places (simplify `icmp eq/ne` and `switch` statements) so it
makes sense to roll all our logic into a single helper.
---
 .../Transforms/InstCombine/InstCombiner.h     |  18 ++
 .../InstCombine/InstructionCombining.cpp      | 228 ++++++++++++++++++
 2 files changed, 246 insertions(+)

diff --git a/llvm/include/llvm/Transforms/InstCombine/InstCombiner.h b/llvm/include/llvm/Transforms/InstCombine/InstCombiner.h
index 93090431cbb69f..4b89ea73f16e37 100644
--- a/llvm/include/llvm/Transforms/InstCombine/InstCombiner.h
+++ b/llvm/include/llvm/Transforms/InstCombine/InstCombiner.h
@@ -198,6 +198,24 @@ class LLVM_LIBRARY_VISIBILITY InstCombiner {
                                                 PatternMatch::m_Value()));
   }
 
+  /// Assumes that we have `Op eq/ne Vals` (either icmp or switch). Will try to
+  /// constant fold `Vals` so that we can use `Op' eq/ne Vals'`. For example if
+  /// we have `Op` as `add X, C0`, it will simplify all `Vals` as `Vals[i] - C0`
+  /// and return `X`.
+  Value *simplifyOpWithConstantEqConsts(Value *Op, BuilderTy &Builder,
+                                        SmallVector<Constant *> &Vals,
+                                        bool ReqOneUseAdd = true);
+
+  Value *simplifyOpWithConstantEqConsts(Value *Op, BuilderTy &Builder,
+                                        Constant *&Val,
+                                        bool ReqOneUseAdd = true) {
+    SmallVector<Constant *> CVals;
+    CVals.push_back(Val);
+    Value *R = simplifyOpWithConstantEqConsts(Op, Builder, CVals, ReqOneUseAdd);
+    Val = CVals[0];
+    return R;
+  }
+
   /// Return nonnull value if V is free to invert under the condition of
   /// WillInvertAllUses.
   /// If Builder is nonnull, it will return a simplified ~V.
diff --git a/llvm/lib/Transforms/InstCombine/InstructionCombining.cpp b/llvm/lib/Transforms/InstCombine/InstructionCombining.cpp
index b6611cfbbfc1f4..2ce8e0d789c457 100644
--- a/llvm/lib/Transforms/InstCombine/InstructionCombining.cpp
+++ b/llvm/lib/Transforms/InstCombine/InstructionCombining.cpp
@@ -3572,6 +3572,234 @@ Instruction *InstCombinerImpl::visitBranchInst(BranchInst &BI) {
   return nullptr;
 }
 
+Value *
+InstCombiner::simplifyOpWithConstantEqConsts(Value *Op, BuilderTy &Builder,
+                                             SmallVector<Constant *> &Vals,
+                                             bool ReqOneUseAdd) {
+
+  Operator *I = dyn_cast<Operator>(Op);
+  if (!I)
+    return nullptr;
+
+  auto ReverseAll = [&](function_ref<Constant *(Constant *)> ReverseF) {
+    for (size_t i = 0, e = Vals.size(); i < e; ++i) {
+      Vals[i] = ReverseF(Vals[i]);
+    }
+  };
+
+  SmallVector<const APInt *, 4> ValsAsAPInt;
+  for (Constant *C : Vals) {
+    const APInt *CAPInt;
+    if (!match(C, m_APInt(CAPInt)))
+      break;
+    ValsAsAPInt.push_back(CAPInt);
+  }
+  bool UseAPInt = ValsAsAPInt.size() == Vals.size();
+
+  auto ReverseAllAPInt = [&](function_ref<APInt(const APInt *)> ReverseF) {
+    assert(UseAPInt && "Can't reverse non-apint constants!");
+    for (size_t i = 0, e = Vals.size(); i < e; ++i) {
+      Vals[i] = ConstantInt::get(Vals[i]->getType(), ReverseF(ValsAsAPInt[i]));
+    }
+  };
+
+  Constant *C;
+  switch (I->getOpcode()) {
+  default:
+    break;
+  case Instruction::Or:
+    if (!match(I, m_DisjointOr(m_Value(), m_Value())))
+      break;
+    // Can treat `or disjoint` as add
+    [[fallthrough]];
+  case Instruction::Add:
+    // We get some regressions if we drop the OneUse for add in some cases.
+    // See discussion in D58633.
+    if (ReqOneUseAdd && !I->hasOneUse())
+      break;
+    if (!match(I->getOperand(1), m_ImmConstant(C)))
+      break;
+    // X + C0 == C1 -> X == C1 - C0
+    ReverseAll([&](Constant *Val) { return ConstantExpr::getSub(Val, C); });
+    return I->getOperand(0);
+  case Instruction::Sub:
+    if (!match(I->getOperand(0), m_ImmConstant(C)))
+      break;
+    // C0 - X == C1 -> X == C0 - C1
+    ReverseAll([&](Constant *Val) { return ConstantExpr::getSub(C, Val); });
+    return I->getOperand(1);
+  case Instruction::Xor:
+    if (!match(I->getOperand(1), m_ImmConstant(C)))
+      break;
+    // X ^ C0 == C1 -> X == C1 ^ C0
+    ReverseAll([&](Constant *Val) { return ConstantExpr::getXor(Val, C); });
+    return I->getOperand(0);
+  case Instruction::Mul: {
+    const APInt *MC;
+    if (!UseAPInt || !match(I->getOperand(1), m_APInt(MC)) || MC->isZero())
+      break;
+    OverflowingBinaryOperator *Mul = cast<OverflowingBinaryOperator>(I);
+    if (!Mul->hasNoUnsignedWrap())
+      break;
+
+    // X nuw C0 == C1 -> X == C1 u/ C0 iff C1 u% C0 == 0
+    if (all_of(ValsAsAPInt,
+               [&](const APInt * AC) { return AC->urem(*MC).isZero(); })) {
+      ReverseAllAPInt([&](const APInt *Val) { return Val->udiv(*MC); });
+      return I->getOperand(0);
+    }
+
+    // X nuw C0 == C1 -> X == C1 s/ C0 iff C1 s% C0 == 0
+    if (all_of(ValsAsAPInt, [&](const APInt * AC) {
+          return (!AC->isMinSignedValue() || !MC->isAllOnes()) &&
+                 AC->srem(*MC).isZero();
+        })) {
+      ReverseAllAPInt([&](const APInt *Val) { return Val->sdiv(*MC); });
+      return I->getOperand(0);
+    }
+    break;
+  }
+  case Instruction::UDiv:
+  case Instruction::SDiv: {
+    const APInt *DC;
+    if (!UseAPInt)
+      break;
+    if (!UseAPInt || !match(I->getOperand(1), m_APInt(DC)))
+      break;
+    if (!cast<PossiblyExactOperator>(Op)->isExact())
+      break;
+    // X u/ C0 == C1 -> X == C0 * C1 iff C0 * C1 is nuw
+    // X s/ C0 == C1 -> X == C0 * C1 iff C0 * C1 is nsw
+    if (!all_of(ValsAsAPInt, [&](const APInt *AC) {
+          bool Ov;
+          (void)(I->getOpcode() == Instruction::UDiv ? DC->umul_ov(*AC, Ov)
+                                                     : DC->smul_ov(*AC, Ov));
+          return !Ov;
+        }))
+      break;
+
+    ReverseAllAPInt([&](const APInt *Val) { return (*Val) * (*DC); });
+    return I->getOperand(0);
+  }
+  case Instruction::ZExt:
+  case Instruction::SExt: {
+    if (!UseAPInt)
+      break;
+    bool IsZExt = isa<ZExtInst>(I);
+    Type *SrcTy = I->getOperand(0)->getType();
+    unsigned NewWidth = SrcTy->getScalarSizeInBits();
+    // zext(X) == C1 -> X == trunc C1 iff zext(trunc(C1)) == C1
+    // sext(X) == C1 -> X == trunc C1 iff sext(trunc(C1)) == C1
+    if (!all_of(ValsAsAPInt, [&](const APInt *AC) {
+          return IsZExt ? AC->isIntN(NewWidth) : AC->isSignedIntN(NewWidth);
+        }))
+      break;
+
+    for (size_t i = 0, e = Vals.size(); i < e; ++i) {
+      Vals[i] = ConstantInt::get(SrcTy, ValsAsAPInt[i]->trunc(NewWidth));
+    }
+    return I->getOperand(0);
+  }
+  case Instruction::Shl:
+  case Instruction::LShr:
+  case Instruction::AShr: {
+    if (!UseAPInt)
+      break;
+    uint64_t ShAmtC;
+    if (!match(I->getOperand(1), m_ConstantInt(ShAmtC)))
+      break;
+    if (ShAmtC >= I->getType()->getScalarSizeInBits())
+      break;
+
+    // X << C0 == C1 -> X == C1 >> C0 iff C1 >> C0 is exact
+    // X u>> C0 == C1 -> X == C1 << C0 iff C1 << C0 is nuw
+    // X s>> C0 == C1 -> X == C1 << C0 iff C1 << C0 is nsw
+    if (!all_of(ValsAsAPInt, [&](const APInt *AC) {
+          switch (I->getOpcode()) {
+          case Instruction::Shl:
+            return AC->countr_zero() >= ShAmtC;
+          case Instruction::LShr:
+            return AC->countl_zero() >= ShAmtC;
+          case Instruction::AShr:
+            return AC->getNumSignBits() >= ShAmtC;
+            return false;
+          default:
+            llvm_unreachable("Already checked Opcode");
+          }
+        }))
+      break;
+
+    bool HasExact = false, HasNUW = false, HasNSW = false;
+    if (I->getOpcode() == Instruction::Shl) {
+      OverflowingBinaryOperator *Shl = cast<OverflowingBinaryOperator>(I);
+      HasNUW = Shl->hasNoUnsignedWrap();
+      HasNSW = Shl->hasNoSignedWrap();
+    } else {
+      HasExact = cast<PossiblyExactOperator>(Op)->isExact();
+    }
+
+    Value *R = I->getOperand(0);
+    if (!HasExact && !HasNUW && !HasNSW) {
+      if (!I->hasOneUse())
+        break;
+
+      // We may be shifting out 1s from X, so need to mask it.
+      unsigned BitWidth = R->getType()->getScalarSizeInBits();
+      R = Builder.CreateAnd(
+          R, I->getOpcode() == Instruction::Shl
+                 ? APInt::getLowBitsSet(BitWidth, BitWidth - ShAmtC)
+                 : APInt::getHighBitsSet(BitWidth, BitWidth - ShAmtC));
+    }
+
+    ReverseAllAPInt([&](const APInt *Val) {
+      if (I->getOpcode() == Instruction::Shl)
+        return HasNSW ? Val->ashr(ShAmtC) : Val->lshr(ShAmtC);
+      return Val->shl(ShAmtC);
+    });
+    return R;
+  }
+  case Instruction::Call:
+  case Instruction::Invoke: {
+    if (IntrinsicInst *II = dyn_cast<IntrinsicInst>(I)) {
+      switch (II->getIntrinsicID()) {
+      default:
+        break;
+      case Intrinsic::bitreverse:
+        if (!UseAPInt)
+          break;
+        // bitreverse(X) == C -> X == bitreverse(C)
+        ReverseAllAPInt([&](const APInt *Val) { return Val->reverseBits(); });
+        return II->getArgOperand(0);
+      case Intrinsic::bswap:
+        if (!UseAPInt)
+          break;
+        // bswap(X) == C -> X == bswap(C)
+        ReverseAllAPInt([&](const APInt *Val) { return Val->byteSwap(); });
+        return II->getArgOperand(0);
+      case Intrinsic::fshr:
+      case Intrinsic::fshl: {
+        if (!UseAPInt)
+          break;
+        if (II->getArgOperand(0) != II->getArgOperand(1))
+          break;
+        const APInt *RotAmtC;
+        if (!match(II->getArgOperand(2), m_APInt(RotAmtC)))
+          break;
+        // rol(X, C0) == C1 -> X == ror(C0, C1)
+        // ror(X, C0) == C1 -> X == rol(C0, C1)
+        ReverseAllAPInt([&](const APInt *Val) {
+          return II->getIntrinsicID() == Intrinsic::fshl ? Val->rotr(*RotAmtC)
+                                                         : Val->rotl(*RotAmtC);
+        });
+        return II->getArgOperand(0);
+      }
+      }
+    }
+  }
+  }
+  return nullptr;
+}
+
 Instruction *InstCombinerImpl::visitSwitchInst(SwitchInst &SI) {
   Value *Cond = SI.getCondition();
   Value *Op0;

>From 1f31efe5fd0bc61ec734d509f0a4b79e26c72c5d Mon Sep 17 00:00:00 2001
From: Noah Goldstein <goldstein.w.n at gmail.com>
Date: Fri, 22 Mar 2024 15:12:52 -0500
Subject: [PATCH 5/6] [InstCombine] Use `simplifyOpWithConstantEqConsts` in
 `foldICmpEquality`

I dropped the obviously redundant cases, but we still have some
sitting around.
---
 .../InstCombine/InstCombineCompares.cpp       | 32 +++++--------------
 llvm/test/Transforms/InstCombine/icmp-add.ll  |  6 ++--
 .../InstCombine/icmp-equality-xor.ll          |  3 +-
 llvm/test/Transforms/InstCombine/icmp-sub.ll  |  6 ++--
 .../InstCombine/prevent-cmp-merge.ll          | 12 +++----
 .../Transforms/InstCombine/simplify-cmp-eq.ll |  6 ++--
 6 files changed, 21 insertions(+), 44 deletions(-)

diff --git a/llvm/lib/Transforms/InstCombine/InstCombineCompares.cpp b/llvm/lib/Transforms/InstCombine/InstCombineCompares.cpp
index db302d7e526844..19a59bcc96d506 100644
--- a/llvm/lib/Transforms/InstCombine/InstCombineCompares.cpp
+++ b/llvm/lib/Transforms/InstCombine/InstCombineCompares.cpp
@@ -3572,16 +3572,6 @@ Instruction *InstCombinerImpl::foldICmpEqIntrinsicWithConstant(
       return new ICmpInst(Pred, II->getArgOperand(0), ConstantInt::get(Ty, C));
     break;
 
-  case Intrinsic::bswap:
-    // bswap(A) == C  ->  A == bswap(C)
-    return new ICmpInst(Pred, II->getArgOperand(0),
-                        ConstantInt::get(Ty, C.byteSwap()));
-
-  case Intrinsic::bitreverse:
-    // bitreverse(A) == C  ->  A == bitreverse(C)
-    return new ICmpInst(Pred, II->getArgOperand(0),
-                        ConstantInt::get(Ty, C.reverseBits()));
-
   case Intrinsic::ctlz:
   case Intrinsic::cttz: {
     // ctz(A) == bitwidth(A)  ->  A == 0 and likewise for !=
@@ -3618,20 +3608,6 @@ Instruction *InstCombinerImpl::foldICmpEqIntrinsicWithConstant(
     break;
   }
 
-  case Intrinsic::fshl:
-  case Intrinsic::fshr:
-    if (II->getArgOperand(0) == II->getArgOperand(1)) {
-      const APInt *RotAmtC;
-      // ror(X, RotAmtC) == C --> X == rol(C, RotAmtC)
-      // rol(X, RotAmtC) == C --> X == ror(C, RotAmtC)
-      if (match(II->getArgOperand(2), m_APInt(RotAmtC)))
-        return new ICmpInst(Pred, II->getArgOperand(0),
-                            II->getIntrinsicID() == Intrinsic::fshl
-                                ? ConstantInt::get(Ty, C.rotr(*RotAmtC))
-                                : ConstantInt::get(Ty, C.rotl(*RotAmtC)));
-    }
-    break;
-
   case Intrinsic::umax:
   case Intrinsic::uadd_sat: {
     // uadd.sat(a, b) == 0  ->  (a | b) == 0
@@ -5456,6 +5432,14 @@ Instruction *InstCombinerImpl::foldICmpEquality(ICmpInst &I) {
 
   Value *Op0 = I.getOperand(0), *Op1 = I.getOperand(1);
   const CmpInst::Predicate Pred = I.getPredicate();
+  {
+    Constant *C;
+    if (match(Op1, m_ImmConstant(C))) {
+      if (auto *R = simplifyOpWithConstantEqConsts(Op0, Builder, C))
+        return new ICmpInst(Pred, R, C);
+    }
+  }
+
   Value *A, *B, *C, *D;
   if (match(Op0, m_Xor(m_Value(A), m_Value(B)))) {
     if (A == Op1 || B == Op1) { // (A^B) == A  ->  B == 0
diff --git a/llvm/test/Transforms/InstCombine/icmp-add.ll b/llvm/test/Transforms/InstCombine/icmp-add.ll
index b99ed20d7d431c..5caf881a7d6d4f 100644
--- a/llvm/test/Transforms/InstCombine/icmp-add.ll
+++ b/llvm/test/Transforms/InstCombine/icmp-add.ll
@@ -2371,8 +2371,7 @@ define <2 x i1> @icmp_eq_add_non_splat(<2 x i32> %a) {
 
 define <2 x i1> @icmp_eq_add_undef2(<2 x i32> %a) {
 ; CHECK-LABEL: @icmp_eq_add_undef2(
-; CHECK-NEXT:    [[ADD:%.*]] = add <2 x i32> [[A:%.*]], <i32 5, i32 5>
-; CHECK-NEXT:    [[CMP:%.*]] = icmp eq <2 x i32> [[ADD]], <i32 10, i32 undef>
+; CHECK-NEXT:    [[CMP:%.*]] = icmp eq <2 x i32> [[A:%.*]], <i32 5, i32 undef>
 ; CHECK-NEXT:    ret <2 x i1> [[CMP]]
 ;
   %add = add <2 x i32> %a, <i32 5, i32 5>
@@ -2382,8 +2381,7 @@ define <2 x i1> @icmp_eq_add_undef2(<2 x i32> %a) {
 
 define <2 x i1> @icmp_eq_add_non_splat2(<2 x i32> %a) {
 ; CHECK-LABEL: @icmp_eq_add_non_splat2(
-; CHECK-NEXT:    [[ADD:%.*]] = add <2 x i32> [[A:%.*]], <i32 5, i32 5>
-; CHECK-NEXT:    [[CMP:%.*]] = icmp eq <2 x i32> [[ADD]], <i32 10, i32 11>
+; CHECK-NEXT:    [[CMP:%.*]] = icmp eq <2 x i32> [[A:%.*]], <i32 5, i32 6>
 ; CHECK-NEXT:    ret <2 x i1> [[CMP]]
 ;
   %add = add <2 x i32> %a, <i32 5, i32 5>
diff --git a/llvm/test/Transforms/InstCombine/icmp-equality-xor.ll b/llvm/test/Transforms/InstCombine/icmp-equality-xor.ll
index f5d5ef32c81e81..f9ba74bcbf7b99 100644
--- a/llvm/test/Transforms/InstCombine/icmp-equality-xor.ll
+++ b/llvm/test/Transforms/InstCombine/icmp-equality-xor.ll
@@ -136,8 +136,7 @@ define i1 @foo2(i32 %x, i32 %y) {
 define <2 x i1> @foo3(<2 x i8> %x) {
 ; CHECK-LABEL: @foo3(
 ; CHECK-NEXT:  entry:
-; CHECK-NEXT:    [[XOR:%.*]] = xor <2 x i8> [[X:%.*]], <i8 -2, i8 -1>
-; CHECK-NEXT:    [[CMP:%.*]] = icmp ne <2 x i8> [[XOR]], <i8 9, i8 79>
+; CHECK-NEXT:    [[CMP:%.*]] = icmp ne <2 x i8> [[X:%.*]], <i8 -9, i8 -80>
 ; CHECK-NEXT:    ret <2 x i1> [[CMP]]
 ;
 entry:
diff --git a/llvm/test/Transforms/InstCombine/icmp-sub.ll b/llvm/test/Transforms/InstCombine/icmp-sub.ll
index 5645dededf2e4b..422e8116f1b38c 100644
--- a/llvm/test/Transforms/InstCombine/icmp-sub.ll
+++ b/llvm/test/Transforms/InstCombine/icmp-sub.ll
@@ -164,8 +164,7 @@ define <2 x i1> @icmp_eq_sub_non_splat(<2 x i32> %a) {
 
 define <2 x i1> @icmp_eq_sub_undef2(<2 x i32> %a) {
 ; CHECK-LABEL: @icmp_eq_sub_undef2(
-; CHECK-NEXT:    [[SUB:%.*]] = sub <2 x i32> <i32 15, i32 15>, [[A:%.*]]
-; CHECK-NEXT:    [[CMP:%.*]] = icmp eq <2 x i32> [[SUB]], <i32 10, i32 undef>
+; CHECK-NEXT:    [[CMP:%.*]] = icmp eq <2 x i32> [[A:%.*]], <i32 5, i32 undef>
 ; CHECK-NEXT:    ret <2 x i1> [[CMP]]
 ;
   %sub = sub <2 x i32> <i32 15, i32 15>, %a
@@ -175,8 +174,7 @@ define <2 x i1> @icmp_eq_sub_undef2(<2 x i32> %a) {
 
 define <2 x i1> @icmp_eq_sub_non_splat2(<2 x i32> %a) {
 ; CHECK-LABEL: @icmp_eq_sub_non_splat2(
-; CHECK-NEXT:    [[SUB:%.*]] = sub <2 x i32> <i32 15, i32 15>, [[A:%.*]]
-; CHECK-NEXT:    [[CMP:%.*]] = icmp eq <2 x i32> [[SUB]], <i32 10, i32 11>
+; CHECK-NEXT:    [[CMP:%.*]] = icmp eq <2 x i32> [[A:%.*]], <i32 5, i32 4>
 ; CHECK-NEXT:    ret <2 x i1> [[CMP]]
 ;
   %sub = sub <2 x i32> <i32 15, i32 15>, %a
diff --git a/llvm/test/Transforms/InstCombine/prevent-cmp-merge.ll b/llvm/test/Transforms/InstCombine/prevent-cmp-merge.ll
index cd05022b0d35da..0453029fb5e977 100644
--- a/llvm/test/Transforms/InstCombine/prevent-cmp-merge.ll
+++ b/llvm/test/Transforms/InstCombine/prevent-cmp-merge.ll
@@ -7,9 +7,9 @@
 
 define zeroext i1 @test1(i32 %lhs, i32 %rhs) {
 ; CHECK-LABEL: @test1(
-; CHECK-NEXT:    [[XOR:%.*]] = xor i32 [[LHS:%.*]], 5
-; CHECK-NEXT:    [[CMP1:%.*]] = icmp eq i32 [[XOR]], 10
-; CHECK-NEXT:    [[CMP2:%.*]] = icmp eq i32 [[XOR]], [[RHS:%.*]]
+; CHECK-NEXT:    [[CMP1:%.*]] = icmp eq i32 [[LHS:%.*]], 15
+; CHECK-NEXT:    [[TMP1:%.*]] = xor i32 [[LHS]], [[RHS:%.*]]
+; CHECK-NEXT:    [[CMP2:%.*]] = icmp eq i32 [[TMP1]], 5
 ; CHECK-NEXT:    [[SEL:%.*]] = or i1 [[CMP1]], [[CMP2]]
 ; CHECK-NEXT:    ret i1 [[SEL]]
 ;
@@ -23,9 +23,9 @@ define zeroext i1 @test1(i32 %lhs, i32 %rhs) {
 
 define zeroext i1 @test1_logical(i32 %lhs, i32 %rhs) {
 ; CHECK-LABEL: @test1_logical(
-; CHECK-NEXT:    [[XOR:%.*]] = xor i32 [[LHS:%.*]], 5
-; CHECK-NEXT:    [[CMP1:%.*]] = icmp eq i32 [[XOR]], 10
-; CHECK-NEXT:    [[CMP2:%.*]] = icmp eq i32 [[XOR]], [[RHS:%.*]]
+; CHECK-NEXT:    [[CMP1:%.*]] = icmp eq i32 [[LHS:%.*]], 15
+; CHECK-NEXT:    [[TMP1:%.*]] = xor i32 [[LHS]], [[RHS:%.*]]
+; CHECK-NEXT:    [[CMP2:%.*]] = icmp eq i32 [[TMP1]], 5
 ; CHECK-NEXT:    [[SEL:%.*]] = select i1 [[CMP1]], i1 true, i1 [[CMP2]]
 ; CHECK-NEXT:    ret i1 [[SEL]]
 ;
diff --git a/llvm/test/Transforms/InstCombine/simplify-cmp-eq.ll b/llvm/test/Transforms/InstCombine/simplify-cmp-eq.ll
index d5cd9061763945..94a896b39f2a25 100644
--- a/llvm/test/Transforms/InstCombine/simplify-cmp-eq.ll
+++ b/llvm/test/Transforms/InstCombine/simplify-cmp-eq.ll
@@ -4,8 +4,7 @@
 declare void @use.i8(i8)
 define <2 x i1> @simplify_cmp_or_disjoint(<2 x i8> %x) {
 ; CHECK-LABEL: @simplify_cmp_or_disjoint(
-; CHECK-NEXT:    [[V:%.*]] = or disjoint <2 x i8> [[X:%.*]], <i8 12, i8 13>
-; CHECK-NEXT:    [[R:%.*]] = icmp ne <2 x i8> [[V]], <i8 0, i8 45>
+; CHECK-NEXT:    [[R:%.*]] = icmp ne <2 x i8> [[X:%.*]], <i8 -12, i8 32>
 ; CHECK-NEXT:    ret <2 x i1> [[R]]
 ;
   %v = or disjoint <2 x i8> %x, <i8 12, i8 13>
@@ -49,8 +48,7 @@ define i1 @simplify_cmp_add_fail_multiuse(i8 %x) {
 
 define <2 x i1> @simplify_cmp_sub(<2 x i8> %x) {
 ; CHECK-LABEL: @simplify_cmp_sub(
-; CHECK-NEXT:    [[V:%.*]] = sub <2 x i8> <i8 12, i8 13>, [[X:%.*]]
-; CHECK-NEXT:    [[R:%.*]] = icmp eq <2 x i8> [[V]], <i8 0, i8 55>
+; CHECK-NEXT:    [[R:%.*]] = icmp eq <2 x i8> [[X:%.*]], <i8 12, i8 -42>
 ; CHECK-NEXT:    ret <2 x i1> [[R]]
 ;
   %v = sub <2 x i8> <i8 12, i8 13>, %x

>From f4a845a1a67851566a3e760bdbdaadf535875bd9 Mon Sep 17 00:00:00 2001
From: Noah Goldstein <goldstein.w.n at gmail.com>
Date: Fri, 22 Mar 2024 16:11:36 -0500
Subject: [PATCH 6/6] [InstCombine] Use `simplifyOpWithConstantEqConsts` in
 `visitSwitchInst`

Replaces bespoke logic with logic shared by `visitICmp`. The new logic
is more complete.
---
 .../InstCombine/InstructionCombining.cpp      | 86 ++----------------
 .../2009-02-20-InstCombine-SROA.ll            | 16 ++--
 .../Transforms/InstCombine/narrow-switch.ll   | 16 ++--
 .../Transforms/InstCombine/simplify-cmp-eq.ll | 87 +++++++++----------
 .../InstCombine/switch-constant-expr.ll       |  8 +-
 5 files changed, 71 insertions(+), 142 deletions(-)

diff --git a/llvm/lib/Transforms/InstCombine/InstructionCombining.cpp b/llvm/lib/Transforms/InstCombine/InstructionCombining.cpp
index 2ce8e0d789c457..f4a93434761c63 100644
--- a/llvm/lib/Transforms/InstCombine/InstructionCombining.cpp
+++ b/llvm/lib/Transforms/InstCombine/InstructionCombining.cpp
@@ -3802,85 +3802,17 @@ InstCombiner::simplifyOpWithConstantEqConsts(Value *Op, BuilderTy &Builder,
 
 Instruction *InstCombinerImpl::visitSwitchInst(SwitchInst &SI) {
   Value *Cond = SI.getCondition();
-  Value *Op0;
-  ConstantInt *AddRHS;
-  if (match(Cond, m_Add(m_Value(Op0), m_ConstantInt(AddRHS)))) {
-    // Change 'switch (X+4) case 1:' into 'switch (X) case -3'.
-    for (auto Case : SI.cases()) {
-      Constant *NewCase = ConstantExpr::getSub(Case.getCaseValue(), AddRHS);
-      assert(isa<ConstantInt>(NewCase) &&
-             "Result of expression should be constant");
-      Case.setValue(cast<ConstantInt>(NewCase));
-    }
-    return replaceOperand(SI, 0, Op0);
-  }
 
-  ConstantInt *SubLHS;
-  if (match(Cond, m_Sub(m_ConstantInt(SubLHS), m_Value(Op0)))) {
-    // Change 'switch (1-X) case 1:' into 'switch (X) case 0'.
-    for (auto Case : SI.cases()) {
-      Constant *NewCase = ConstantExpr::getSub(SubLHS, Case.getCaseValue());
-      assert(isa<ConstantInt>(NewCase) &&
-             "Result of expression should be constant");
-      Case.setValue(cast<ConstantInt>(NewCase));
-    }
-    return replaceOperand(SI, 0, Op0);
-  }
-
-  uint64_t ShiftAmt;
-  if (match(Cond, m_Shl(m_Value(Op0), m_ConstantInt(ShiftAmt))) &&
-      ShiftAmt < Op0->getType()->getScalarSizeInBits() &&
-      all_of(SI.cases(), [&](const auto &Case) {
-        return Case.getCaseValue()->getValue().countr_zero() >= ShiftAmt;
-      })) {
-    // Change 'switch (X << 2) case 4:' into 'switch (X) case 1:'.
-    OverflowingBinaryOperator *Shl = cast<OverflowingBinaryOperator>(Cond);
-    if (Shl->hasNoUnsignedWrap() || Shl->hasNoSignedWrap() ||
-        Shl->hasOneUse()) {
-      Value *NewCond = Op0;
-      if (!Shl->hasNoUnsignedWrap() && !Shl->hasNoSignedWrap()) {
-        // If the shift may wrap, we need to mask off the shifted bits.
-        unsigned BitWidth = Op0->getType()->getScalarSizeInBits();
-        NewCond = Builder.CreateAnd(
-            Op0, APInt::getLowBitsSet(BitWidth, BitWidth - ShiftAmt));
-      }
-      for (auto Case : SI.cases()) {
-        const APInt &CaseVal = Case.getCaseValue()->getValue();
-        APInt ShiftedCase = Shl->hasNoSignedWrap() ? CaseVal.ashr(ShiftAmt)
-                                                   : CaseVal.lshr(ShiftAmt);
-        Case.setValue(ConstantInt::get(SI.getContext(), ShiftedCase));
-      }
-      return replaceOperand(SI, 0, NewCond);
-    }
-  }
+  SmallVector<Constant *> CaseVals;
+  for (const auto &Case : SI.cases())
+    CaseVals.push_back(Case.getCaseValue());
 
-  // Fold switch(zext/sext(X)) into switch(X) if possible.
-  if (match(Cond, m_ZExtOrSExt(m_Value(Op0)))) {
-    bool IsZExt = isa<ZExtInst>(Cond);
-    Type *SrcTy = Op0->getType();
-    unsigned NewWidth = SrcTy->getScalarSizeInBits();
-
-    if (all_of(SI.cases(), [&](const auto &Case) {
-          const APInt &CaseVal = Case.getCaseValue()->getValue();
-          return IsZExt ? CaseVal.isIntN(NewWidth)
-                        : CaseVal.isSignedIntN(NewWidth);
-        })) {
-      for (auto &Case : SI.cases()) {
-        APInt TruncatedCase = Case.getCaseValue()->getValue().trunc(NewWidth);
-        Case.setValue(ConstantInt::get(SI.getContext(), TruncatedCase));
-      }
-      return replaceOperand(SI, 0, Op0);
-    }
-  }
-
-  // Fold 'switch(rol(x, C1)) case C2:' to 'switch(x) case rol(C2, -C1):'
-  if (match(Cond,
-            m_FShl(m_Value(Op0), m_Deferred(Op0), m_ConstantInt(ShiftAmt)))) {
-    for (auto &Case : SI.cases()) {
-      const APInt NewCase = Case.getCaseValue()->getValue().rotr(ShiftAmt);
-      Case.setValue(ConstantInt::get(SI.getContext(), NewCase));
-    }
-    return replaceOperand(SI, 0, Op0);
+  if (auto *R = simplifyOpWithConstantEqConsts(Cond, Builder, CaseVals,
+                                               /*ReqOneUseAdd=*/false)) {
+    unsigned i = 0;
+    for (auto &Case : SI.cases())
+      Case.setValue(cast<ConstantInt>(CaseVals[i++]));
+    return replaceOperand(SI, 0, R);
   }
 
   KnownBits Known = computeKnownBits(Cond, 0, &SI);
diff --git a/llvm/test/Transforms/InstCombine/2009-02-20-InstCombine-SROA.ll b/llvm/test/Transforms/InstCombine/2009-02-20-InstCombine-SROA.ll
index b532c815567389..978b4e29ed628a 100644
--- a/llvm/test/Transforms/InstCombine/2009-02-20-InstCombine-SROA.ll
+++ b/llvm/test/Transforms/InstCombine/2009-02-20-InstCombine-SROA.ll
@@ -92,11 +92,11 @@ define ptr @_Z3fooRSt6vectorIiSaIiEE(ptr %X) {
 ; IC-NEXT:    [[TMP37:%.*]] = load ptr, ptr [[__FIRST_ADDR_I_I]], align 4
 ; IC-NEXT:    [[TMP38:%.*]] = ptrtoint ptr [[TMP37]] to i32
 ; IC-NEXT:    [[TMP39:%.*]] = sub i32 [[TMP36]], [[TMP38]]
-; IC-NEXT:    [[TMP40:%.*]] = ashr i32 [[TMP39]], 2
+; IC-NEXT:    [[TMP40:%.*]] = and i32 [[TMP39]], -4
 ; IC-NEXT:    switch i32 [[TMP40]], label [[BB26_I_I:%.*]] [
-; IC-NEXT:      i32 1, label [[BB22_I_I:%.*]]
-; IC-NEXT:      i32 2, label [[BB18_I_I:%.*]]
-; IC-NEXT:      i32 3, label [[BB14_I_I:%.*]]
+; IC-NEXT:      i32 4, label [[BB22_I_I:%.*]]
+; IC-NEXT:      i32 8, label [[BB18_I_I:%.*]]
+; IC-NEXT:      i32 12, label [[BB14_I_I:%.*]]
 ; IC-NEXT:    ]
 ; IC:       bb14.i.i:
 ; IC-NEXT:    [[TMP41:%.*]] = load ptr, ptr [[__FIRST_ADDR_I_I]], align 4
@@ -199,11 +199,11 @@ define ptr @_Z3fooRSt6vectorIiSaIiEE(ptr %X) {
 ; IC_SROA-NEXT:    [[TMP21:%.*]] = ptrtoint ptr [[TMP1]] to i32
 ; IC_SROA-NEXT:    [[TMP22:%.*]] = ptrtoint ptr [[__FIRST_ADDR_I_I_SROA_0_0]] to i32
 ; IC_SROA-NEXT:    [[TMP23:%.*]] = sub i32 [[TMP21]], [[TMP22]]
-; IC_SROA-NEXT:    [[TMP24:%.*]] = ashr i32 [[TMP23]], 2
+; IC_SROA-NEXT:    [[TMP24:%.*]] = and i32 [[TMP23]], -4
 ; IC_SROA-NEXT:    switch i32 [[TMP24]], label [[BB26_I_I:%.*]] [
-; IC_SROA-NEXT:      i32 1, label [[BB22_I_I:%.*]]
-; IC_SROA-NEXT:      i32 2, label [[BB18_I_I:%.*]]
-; IC_SROA-NEXT:      i32 3, label [[BB14_I_I:%.*]]
+; IC_SROA-NEXT:      i32 4, label [[BB22_I_I:%.*]]
+; IC_SROA-NEXT:      i32 8, label [[BB18_I_I:%.*]]
+; IC_SROA-NEXT:      i32 12, label [[BB14_I_I:%.*]]
 ; IC_SROA-NEXT:    ]
 ; IC_SROA:       bb14.i.i:
 ; IC_SROA-NEXT:    [[TMP25:%.*]] = load i32, ptr [[__FIRST_ADDR_I_I_SROA_0_0]], align 4
diff --git a/llvm/test/Transforms/InstCombine/narrow-switch.ll b/llvm/test/Transforms/InstCombine/narrow-switch.ll
index 05a30b910e5ee0..8fd2bfb8e5cf9e 100644
--- a/llvm/test/Transforms/InstCombine/narrow-switch.ll
+++ b/llvm/test/Transforms/InstCombine/narrow-switch.ll
@@ -104,13 +104,13 @@ return:
 
 define void @trunc64to58(i64 %a) {
 ; ALL-LABEL: @trunc64to58(
-; CHECK32:         switch i58
-; CHECK32-NEXT:    i58 0, label %sw.bb1
-; CHECK32-NEXT:    i58 18717182647723699, label %sw.bb2
+; CHECK32:         switch i4
+; CHECK32-NEXT:    i4 0, label %sw.bb1
+; CHECK32-NEXT:    i4 1, label %sw.bb2
 ; CHECK32-NEXT:    ]
 ; CHECK64:         switch i64
 ; CHECK64-NEXT:    i64 0, label %sw.bb1
-; CHECK64-NEXT:    i64 18717182647723699, label %sw.bb2
+; CHECK64-NEXT:    i64 1, label %sw.bb2
 ; CHECK64-NEXT:    ]
 ;
 entry:
@@ -170,10 +170,10 @@ case124:
 ; condition is evaluated on the original type
 define i32 @trunc32to16(i32 %a0) #0 {
 ; ALL-LABEL: @trunc32to16(
-; ALL:         switch i16
-; ALL-NEXT:    i16 63, label %sw.bb
-; ALL-NEXT:    i16 1, label %sw.bb1
-; ALL-NEXT:    i16 100, label %sw.bb2
+; ALL:         switch i32
+; ALL-NEXT:    i32 1033306112, label %sw.bb
+; ALL-NEXT:    i32 1034485760, label %sw.bb1
+; ALL-NEXT:    i32 1036779520, label %sw.bb2
 ; ALL-NEXT:    ]
 ;
 entry:
diff --git a/llvm/test/Transforms/InstCombine/simplify-cmp-eq.ll b/llvm/test/Transforms/InstCombine/simplify-cmp-eq.ll
index 94a896b39f2a25..273589957b9c74 100644
--- a/llvm/test/Transforms/InstCombine/simplify-cmp-eq.ll
+++ b/llvm/test/Transforms/InstCombine/simplify-cmp-eq.ll
@@ -446,11 +446,10 @@ define i1 @simplify_cmp_fshl_fail_not_rotate(i8 %x, i8 %y) {
 
 define i8 @simplify_switch_or_disjoint(i8 %x) {
 ; CHECK-LABEL: @simplify_switch_or_disjoint(
-; CHECK-NEXT:    [[V:%.*]] = or disjoint i8 [[X:%.*]], 12
-; CHECK-NEXT:    switch i8 [[V]], label [[DEFAULT:%.*]] [
-; CHECK-NEXT:      i8 12, label [[L12:%.*]]
-; CHECK-NEXT:      i8 44, label [[L44:%.*]]
-; CHECK-NEXT:      i8 45, label [[L45:%.*]]
+; CHECK-NEXT:    switch i8 [[V:%.*]], label [[DEFAULT:%.*]] [
+; CHECK-NEXT:      i8 0, label [[L12:%.*]]
+; CHECK-NEXT:      i8 32, label [[L44:%.*]]
+; CHECK-NEXT:      i8 33, label [[L45:%.*]]
 ; CHECK-NEXT:    ]
 ; CHECK:       l12:
 ; CHECK-NEXT:    ret i8 12
@@ -554,10 +553,10 @@ define i8 @simplify_switch_xor(i8 %x) {
 ; CHECK-LABEL: @simplify_switch_xor(
 ; CHECK-NEXT:    [[V:%.*]] = xor i8 [[X:%.*]], 12
 ; CHECK-NEXT:    call void @use.i8(i8 [[V]])
-; CHECK-NEXT:    switch i8 [[V]], label [[DEFAULT:%.*]] [
-; CHECK-NEXT:      i8 12, label [[L12:%.*]]
-; CHECK-NEXT:      i8 44, label [[L44:%.*]]
-; CHECK-NEXT:      i8 45, label [[L45:%.*]]
+; CHECK-NEXT:    switch i8 [[X]], label [[DEFAULT:%.*]] [
+; CHECK-NEXT:      i8 0, label [[L12:%.*]]
+; CHECK-NEXT:      i8 32, label [[L44:%.*]]
+; CHECK-NEXT:      i8 33, label [[L45:%.*]]
 ; CHECK-NEXT:    ]
 ; CHECK:       l12:
 ; CHECK-NEXT:    ret i8 12
@@ -591,10 +590,10 @@ define i8 @simplify_switch_mul_udiv(i8 %x) {
 ; CHECK-LABEL: @simplify_switch_mul_udiv(
 ; CHECK-NEXT:    [[V:%.*]] = mul nuw i8 [[X:%.*]], 12
 ; CHECK-NEXT:    call void @use.i8(i8 [[V]])
-; CHECK-NEXT:    switch i8 [[V]], label [[DEFAULT:%.*]] [
-; CHECK-NEXT:      i8 12, label [[L12:%.*]]
-; CHECK-NEXT:      i8 48, label [[L48:%.*]]
-; CHECK-NEXT:      i8 60, label [[L60:%.*]]
+; CHECK-NEXT:    switch i8 [[X]], label [[DEFAULT:%.*]] [
+; CHECK-NEXT:      i8 1, label [[L12:%.*]]
+; CHECK-NEXT:      i8 4, label [[L48:%.*]]
+; CHECK-NEXT:      i8 5, label [[L60:%.*]]
 ; CHECK-NEXT:      i8 0, label [[L0:%.*]]
 ; CHECK-NEXT:    ]
 ; CHECK:       l12:
@@ -675,10 +674,10 @@ define i8 @simplify_switch_mul_sdiv(i8 %x) {
 ; CHECK-LABEL: @simplify_switch_mul_sdiv(
 ; CHECK-NEXT:    [[V:%.*]] = mul nuw i8 [[X:%.*]], 12
 ; CHECK-NEXT:    call void @use.i8(i8 [[V]])
-; CHECK-NEXT:    switch i8 [[V]], label [[DEFAULT:%.*]] [
-; CHECK-NEXT:      i8 -12, label [[L12:%.*]]
-; CHECK-NEXT:      i8 48, label [[L48:%.*]]
-; CHECK-NEXT:      i8 -60, label [[L60:%.*]]
+; CHECK-NEXT:    switch i8 [[X]], label [[DEFAULT:%.*]] [
+; CHECK-NEXT:      i8 -1, label [[L12:%.*]]
+; CHECK-NEXT:      i8 4, label [[L48:%.*]]
+; CHECK-NEXT:      i8 -5, label [[L60:%.*]]
 ; CHECK-NEXT:      i8 0, label [[L0:%.*]]
 ; CHECK-NEXT:    ]
 ; CHECK:       l12:
@@ -759,10 +758,10 @@ define i8 @simplify_switch_udiv(i8 %x) {
 ; CHECK-LABEL: @simplify_switch_udiv(
 ; CHECK-NEXT:    [[V:%.*]] = udiv exact i8 [[X:%.*]], 12
 ; CHECK-NEXT:    call void @use.i8(i8 [[V]])
-; CHECK-NEXT:    switch i8 [[V]], label [[DEFAULT:%.*]] [
-; CHECK-NEXT:      i8 12, label [[L12:%.*]]
-; CHECK-NEXT:      i8 3, label [[L48:%.*]]
-; CHECK-NEXT:      i8 9, label [[L60:%.*]]
+; CHECK-NEXT:    switch i8 [[X]], label [[DEFAULT:%.*]] [
+; CHECK-NEXT:      i8 -112, label [[L12:%.*]]
+; CHECK-NEXT:      i8 36, label [[L48:%.*]]
+; CHECK-NEXT:      i8 108, label [[L60:%.*]]
 ; CHECK-NEXT:      i8 0, label [[L0:%.*]]
 ; CHECK-NEXT:    ]
 ; CHECK:       l12:
@@ -843,10 +842,10 @@ define i8 @simplify_switch_sdiv(i8 %x) {
 ; CHECK-LABEL: @simplify_switch_sdiv(
 ; CHECK-NEXT:    [[V:%.*]] = sdiv exact i8 [[X:%.*]], 12
 ; CHECK-NEXT:    call void @use.i8(i8 [[V]])
-; CHECK-NEXT:    switch i8 [[V]], label [[DEFAULT:%.*]] [
-; CHECK-NEXT:      i8 4, label [[L12:%.*]]
-; CHECK-NEXT:      i8 -3, label [[L48:%.*]]
-; CHECK-NEXT:      i8 7, label [[L60:%.*]]
+; CHECK-NEXT:    switch i8 [[X]], label [[DEFAULT:%.*]] [
+; CHECK-NEXT:      i8 48, label [[L12:%.*]]
+; CHECK-NEXT:      i8 -36, label [[L48:%.*]]
+; CHECK-NEXT:      i8 84, label [[L60:%.*]]
 ; CHECK-NEXT:      i8 0, label [[L0:%.*]]
 ; CHECK-NEXT:    ]
 ; CHECK:       l12:
@@ -1290,10 +1289,10 @@ define i8 @simplify_switch_lshr(i8 %x) {
 ; CHECK-LABEL: @simplify_switch_lshr(
 ; CHECK-NEXT:    [[V:%.*]] = lshr exact i8 [[X:%.*]], 2
 ; CHECK-NEXT:    call void @use.i8(i8 [[V]])
-; CHECK-NEXT:    switch i8 [[V]], label [[DEFAULT:%.*]] [
-; CHECK-NEXT:      i8 12, label [[L12:%.*]]
-; CHECK-NEXT:      i8 16, label [[L48:%.*]]
-; CHECK-NEXT:      i8 30, label [[L60:%.*]]
+; CHECK-NEXT:    switch i8 [[X]], label [[DEFAULT:%.*]] [
+; CHECK-NEXT:      i8 48, label [[L12:%.*]]
+; CHECK-NEXT:      i8 64, label [[L48:%.*]]
+; CHECK-NEXT:      i8 120, label [[L60:%.*]]
 ; CHECK-NEXT:      i8 0, label [[L0:%.*]]
 ; CHECK-NEXT:    ]
 ; CHECK:       l12:
@@ -1372,10 +1371,10 @@ define i8 @simplify_switch_ashr(i8 %x) {
 ; CHECK-LABEL: @simplify_switch_ashr(
 ; CHECK-NEXT:    [[V:%.*]] = ashr exact i8 [[X:%.*]], 2
 ; CHECK-NEXT:    call void @use.i8(i8 [[V]])
-; CHECK-NEXT:    switch i8 [[V]], label [[DEFAULT:%.*]] [
-; CHECK-NEXT:      i8 -12, label [[L12:%.*]]
-; CHECK-NEXT:      i8 16, label [[L48:%.*]]
-; CHECK-NEXT:      i8 3, label [[L60:%.*]]
+; CHECK-NEXT:    switch i8 [[X]], label [[DEFAULT:%.*]] [
+; CHECK-NEXT:      i8 -48, label [[L12:%.*]]
+; CHECK-NEXT:      i8 64, label [[L48:%.*]]
+; CHECK-NEXT:      i8 12, label [[L60:%.*]]
 ; CHECK-NEXT:      i8 0, label [[L0:%.*]]
 ; CHECK-NEXT:    ]
 ; CHECK:       l12:
@@ -1452,12 +1451,11 @@ default:
 
 define i8 @simplify_switch_bitreverse(i8 %x) {
 ; CHECK-LABEL: @simplify_switch_bitreverse(
-; CHECK-NEXT:    [[V:%.*]] = call i8 @llvm.bitreverse.i8(i8 [[X:%.*]])
-; CHECK-NEXT:    switch i8 [[V]], label [[DEFAULT:%.*]] [
-; CHECK-NEXT:      i8 -12, label [[L12:%.*]]
-; CHECK-NEXT:      i8 16, label [[L48:%.*]]
-; CHECK-NEXT:      i8 30, label [[L60:%.*]]
-; CHECK-NEXT:      i8 -128, label [[L0:%.*]]
+; CHECK-NEXT:    switch i8 [[V:%.*]], label [[DEFAULT:%.*]] [
+; CHECK-NEXT:      i8 47, label [[L12:%.*]]
+; CHECK-NEXT:      i8 8, label [[L48:%.*]]
+; CHECK-NEXT:      i8 120, label [[L60:%.*]]
+; CHECK-NEXT:      i8 1, label [[L0:%.*]]
 ; CHECK-NEXT:    ]
 ; CHECK:       l12:
 ; CHECK-NEXT:    ret i8 12
@@ -1492,12 +1490,11 @@ default:
 
 define i16 @simplify_switch_bswap(i16 %x) {
 ; CHECK-LABEL: @simplify_switch_bswap(
-; CHECK-NEXT:    [[V:%.*]] = call i16 @llvm.bswap.i16(i16 [[X:%.*]])
-; CHECK-NEXT:    switch i16 [[V]], label [[DEFAULT:%.*]] [
-; CHECK-NEXT:      i16 -12, label [[L12:%.*]]
-; CHECK-NEXT:      i16 16, label [[L48:%.*]]
-; CHECK-NEXT:      i16 30, label [[L60:%.*]]
-; CHECK-NEXT:      i16 128, label [[L0:%.*]]
+; CHECK-NEXT:    switch i16 [[V:%.*]], label [[DEFAULT:%.*]] [
+; CHECK-NEXT:      i16 -2817, label [[L12:%.*]]
+; CHECK-NEXT:      i16 4096, label [[L48:%.*]]
+; CHECK-NEXT:      i16 7680, label [[L60:%.*]]
+; CHECK-NEXT:      i16 -32768, label [[L0:%.*]]
 ; CHECK-NEXT:    ]
 ; CHECK:       l12:
 ; CHECK-NEXT:    ret i16 12
diff --git a/llvm/test/Transforms/InstCombine/switch-constant-expr.ll b/llvm/test/Transforms/InstCombine/switch-constant-expr.ll
index e3a5e2ac8c117c..6b05e468fba99b 100644
--- a/llvm/test/Transforms/InstCombine/switch-constant-expr.ll
+++ b/llvm/test/Transforms/InstCombine/switch-constant-expr.ll
@@ -6,7 +6,7 @@
 ; PR30486
 define i32 @single_case() {
 ; CHECK-LABEL: @single_case(
-; CHECK-NEXT:    switch i32 add (i32 ptrtoint (ptr @g to i32), i32 -1), label [[X:%.*]] [
+; CHECK-NEXT:    switch i32 ptrtoint (ptr @g to i32), label [[X:%.*]] [
 ; CHECK-NEXT:    ]
 ; CHECK:       x:
 ; CHECK-NEXT:    ret i32 0
@@ -18,9 +18,9 @@ x:
 
 define i32 @multiple_cases() {
 ; CHECK-LABEL: @multiple_cases(
-; CHECK-NEXT:    switch i32 add (i32 ptrtoint (ptr @g to i32), i32 -1), label [[X:%.*]] [
-; CHECK-NEXT:    i32 1, label [[ONE:%.*]]
-; CHECK-NEXT:    i32 2, label [[TWO:%.*]]
+; CHECK-NEXT:    switch i32 ptrtoint (ptr @g to i32), label [[X:%.*]] [
+; CHECK-NEXT:      i32 2, label [[TWO:%.*]]
+; CHECK-NEXT:      i32 3, label [[TWO1:%.*]]
 ; CHECK-NEXT:    ]
 ; CHECK:       x:
 ; CHECK-NEXT:    ret i32 0



More information about the llvm-commits mailing list