[llvm] [PredicateInfo][SCCP] Handle switch comprehensively (PR #165258)

Kunqiu Chen via llvm-commits llvm-commits at lists.llvm.org
Mon Oct 27 08:44:43 PDT 2025


https://github.com/Camsyn updated https://github.com/llvm/llvm-project/pull/165258

>From 941b89deec075cf558c4b5264f84852f4acce39b Mon Sep 17 00:00:00 2001
From: Camsyn <camsyn at foxmail.com>
Date: Mon, 27 Oct 2025 17:19:39 +0800
Subject: [PATCH 1/3] Add new tests before commit

---
 llvm/test/Transforms/NewGVN/edge.ll           |  95 +++++++++++
 llvm/test/Transforms/SCCP/switch.ll           | 153 ++++++++++++++----
 .../Transforms/Util/PredicateInfo/condprop.ll |  32 ++--
 .../Transforms/Util/PredicateInfo/edge.ll     | 103 +++++++++++-
 4 files changed, 334 insertions(+), 49 deletions(-)

diff --git a/llvm/test/Transforms/NewGVN/edge.ll b/llvm/test/Transforms/NewGVN/edge.ll
index 143e52cd139c5..4235f7fbfef14 100644
--- a/llvm/test/Transforms/NewGVN/edge.ll
+++ b/llvm/test/Transforms/NewGVN/edge.ll
@@ -262,3 +262,98 @@ return:
   ret double %retval
 
 }
+
+define i32 @switch_default_dest(i32 %x) {
+; CHECK-LABEL: define i32 @switch_default_dest(
+; CHECK-SAME: i32 [[X:%.*]]) {
+; CHECK-NEXT:  case0:
+; CHECK-NEXT:    switch i32 [[X]], label [[DEFAULT:%.*]] [
+; CHECK-NEXT:      i32 0, label [[PHI:%.*]]
+; CHECK-NEXT:      i32 1, label [[CASE1:%.*]]
+; CHECK-NEXT:    ]
+; CHECK:       case1:
+; CHECK-NEXT:    br label [[PHI]]
+; CHECK:       default:
+; CHECK-NEXT:    br label [[PHI]]
+; CHECK:       phi:
+; CHECK-NEXT:    [[RES:%.*]] = phi i32 [ 0, [[CASE1]] ], [ 1, [[CASE0:%.*]] ], [ [[X]], [[DEFAULT]] ]
+; CHECK-NEXT:    [[FOO:%.*]] = add i32 [[RES]], [[X]]
+; CHECK-NEXT:    ret i32 [[FOO]]
+;
+case0:
+  switch i32 %x, label %default [
+    i32 0, label %phi
+    i32 1, label %case1
+  ]
+
+case1:
+  br label %phi
+
+default:
+  br label %phi
+
+phi:
+  %res = phi i32 [ 0, %case1 ], [ 1, %case0 ], [ %x, %default ]
+  %foo = add i32 %res, %x
+  ret i32 %foo
+}
+
+define i32 @switch_multicases_dest(i32 %x) {
+; CHECK-LABEL: define i32 @switch_multicases_dest(
+; CHECK-SAME: i32 [[X:%.*]]) {
+; CHECK-NEXT:  entry:
+; CHECK-NEXT:    switch i32 [[X]], label [[PHI:%.*]] [
+; CHECK-NEXT:      i32 0, label [[CASE:%.*]]
+; CHECK-NEXT:      i32 1, label [[CASE]]
+; CHECK-NEXT:    ]
+; CHECK:       case:
+; CHECK-NEXT:    br label [[PHI]]
+; CHECK:       phi:
+; CHECK-NEXT:    [[RES:%.*]] = phi i32 [ [[X]], [[CASE]] ], [ 0, [[ENTRY:%.*]] ]
+; CHECK-NEXT:    [[FOO:%.*]] = add i32 [[RES]], [[X]]
+; CHECK-NEXT:    ret i32 [[FOO]]
+;
+entry:
+  switch i32 %x, label %phi [
+    i32 0, label %case
+    i32 1, label %case
+  ]
+
+case:
+  br label %phi
+
+phi:
+  %res = phi i32 [ %x, %case ], [ 0, %entry ]
+  %foo = add i32 %res, %x
+  ret i32 %foo
+}
+
+define i32 @switch_multicases_dest2(i32 %x) {
+; CHECK-LABEL: define i32 @switch_multicases_dest2(
+; CHECK-SAME: i32 [[X:%.*]]) {
+; CHECK-NEXT:  entry:
+; CHECK-NEXT:    switch i32 [[X]], label [[DEFAULT:%.*]] [
+; CHECK-NEXT:      i32 0, label [[PHI:%.*]]
+; CHECK-NEXT:      i32 1, label [[PHI]]
+; CHECK-NEXT:    ]
+; CHECK:       default:
+; CHECK-NEXT:    br label [[PHI]]
+; CHECK:       phi:
+; CHECK-NEXT:    [[RES:%.*]] = phi i32 [ [[X]], [[ENTRY:%.*]] ], [ [[X]], [[ENTRY]] ], [ 0, [[DEFAULT]] ]
+; CHECK-NEXT:    [[FOO:%.*]] = add i32 [[RES]], [[X]]
+; CHECK-NEXT:    ret i32 [[FOO]]
+;
+entry:
+  switch i32 %x, label %default [
+    i32 0, label %phi
+    i32 1, label %phi
+  ]
+
+default:
+  br label %phi
+
+phi:
+  %res = phi i32 [ %x, %entry ], [ %x, %entry ], [ 0, %default ]
+  %foo = add i32 %res, %x
+  ret i32 %foo
+}
diff --git a/llvm/test/Transforms/SCCP/switch.ll b/llvm/test/Transforms/SCCP/switch.ll
index fb81213ed12dc..c4365486e63b4 100644
--- a/llvm/test/Transforms/SCCP/switch.ll
+++ b/llvm/test/Transforms/SCCP/switch.ll
@@ -37,8 +37,8 @@ entry:
 
 switch:
   switch i32 -1, label %switch.default [
-  i32 0, label %end
-  i32 1, label %end
+    i32 0, label %end
+    i32 1, label %end
   ]
 
 switch.default:
@@ -65,8 +65,8 @@ entry:
 
 switch:
   switch i32 0, label %switch.default [
-  i32 0, label %end
-  i32 1, label %end
+    i32 0, label %end
+    i32 1, label %end
   ]
 
 switch.default:
@@ -102,11 +102,11 @@ entry:
 switch:
   %x = load i32, ptr %p, !range !{i32 0, i32 3}
   switch i32 %x, label %switch.default [
-  i32 0, label %switch.default
-  i32 1, label %switch.0
-  i32 2, label %switch.0
-  i32 3, label %switch.1
-  i32 4, label %switch.1
+    i32 0, label %switch.default
+    i32 1, label %switch.0
+    i32 2, label %switch.0
+    i32 3, label %switch.1
+    i32 4, label %switch.1
   ]
 
 switch.default:
@@ -140,10 +140,10 @@ define i32 @test_local_range(ptr %p) {
 ;
   %x = load i32, ptr %p, !range !{i32 0, i32 3}
   switch i32 %x, label %switch.default [
-  i32 0, label %switch.0
-  i32 1, label %switch.1
-  i32 2, label %switch.2
-  i32 3, label %switch.3
+    i32 0, label %switch.0
+    i32 1, label %switch.1
+    i32 2, label %switch.2
+    i32 3, label %switch.3
   ]
 
 switch.default:
@@ -182,12 +182,12 @@ define i32 @test_duplicate_successors(ptr %p) {
 ;
   %x = load i32, ptr %p, !range !{i32 0, i32 3}
   switch i32 %x, label %switch.default [
-  i32 0, label %switch.0
-  i32 1, label %switch.0
-  i32 2, label %switch.1
-  i32 3, label %switch.1
-  i32 4, label %switch.2
-  i32 5, label %switch.2
+    i32 0, label %switch.0
+    i32 1, label %switch.0
+    i32 2, label %switch.1
+    i32 3, label %switch.1
+    i32 4, label %switch.2
+    i32 5, label %switch.2
   ]
 
 switch.default:
@@ -223,10 +223,10 @@ define internal i32 @test_ip_range(i32 %x) {
 ; CHECK-NEXT:    ret i32 3
 ;
   switch i32 %x, label %switch.default [
-  i32 0, label %switch.0
-  i32 1, label %switch.1
-  i32 2, label %switch.2
-  i32 3, label %switch.3
+    i32 0, label %switch.0
+    i32 1, label %switch.1
+    i32 2, label %switch.2
+    i32 3, label %switch.3
   ], !prof !{!"branch_weights", i32 1, i32 2, i32 3, i32 4, i32 5}
 
 switch.default:
@@ -295,8 +295,8 @@ else.2:
 switch:
   %p = phi i32 [ 0, %then.1 ], [ 2, %else.1 ], [ undef, %else.2 ]
   switch i32 %p, label %switch.default [
-  i32 0, label %end.1
-  i32 3, label %end.2
+    i32 0, label %end.1
+    i32 3, label %end.2
   ]
 
 switch.default:
@@ -346,10 +346,10 @@ entry:
 
 if.then:
   switch i32 %x, label %sw.epilog [
-  i32 0, label %sw.bb
-  i32 1, label %sw.bb2
-  i32 2, label %sw.bb4
-  i32 3, label %sw.bb6
+    i32 0, label %sw.bb
+    i32 1, label %sw.bb2
+    i32 2, label %sw.bb4
+    i32 3, label %sw.bb6
   ]
 
 sw.bb:
@@ -377,6 +377,101 @@ return:
   ret i32 %retval.0
 }
 
+define i1 @switch_default_dest(i32 %x) {
+; CHECK-LABEL: define i1 @switch_default_dest(
+; CHECK-SAME: i32 [[X:%.*]]) {
+; CHECK-NEXT:  case0:
+; CHECK-NEXT:    switch i32 [[X]], label [[DEFAULT:%.*]] [
+; CHECK-NEXT:      i32 0, label [[PHI:%.*]]
+; CHECK-NEXT:      i32 1, label [[CASE1:%.*]]
+; CHECK-NEXT:    ]
+; CHECK:       case1:
+; CHECK-NEXT:    br label [[PHI]]
+; CHECK:       default:
+; CHECK-NEXT:    br label [[PHI]]
+; CHECK:       phi:
+; CHECK-NEXT:    [[RES:%.*]] = phi i32 [ 2, [[CASE1]] ], [ 3, [[CASE0:%.*]] ], [ [[X]], [[DEFAULT]] ]
+; CHECK-NEXT:    [[RET:%.*]] = icmp ult i32 [[RES]], 2
+; CHECK-NEXT:    ret i1 [[RET]]
+;
+case0:
+  switch i32 %x, label %default [
+    i32 0, label %phi
+    i32 1, label %case1
+  ]
+
+case1:
+  br label %phi
+
+default:
+  br label %phi
+
+phi:
+  %res = phi i32 [ 2, %case1 ], [ 3, %case0 ], [ %x, %default ]
+  %ret = icmp ult i32 %res, 2
+  ret i1 %ret
+}
+
+define i1 @switch_multicases_dest(i32 %x) {
+; CHECK-LABEL: define i1 @switch_multicases_dest(
+; CHECK-SAME: i32 [[X:%.*]]) {
+; CHECK-NEXT:  entry:
+; CHECK-NEXT:    switch i32 [[X]], label [[PHI:%.*]] [
+; CHECK-NEXT:      i32 0, label [[CASE:%.*]]
+; CHECK-NEXT:      i32 1, label [[CASE]]
+; CHECK-NEXT:    ]
+; CHECK:       case:
+; CHECK-NEXT:    br label [[PHI]]
+; CHECK:       phi:
+; CHECK-NEXT:    [[RES:%.*]] = phi i32 [ [[X]], [[CASE]] ], [ 0, [[ENTRY:%.*]] ]
+; CHECK-NEXT:    [[RET:%.*]] = icmp ult i32 [[RES]], 2
+; CHECK-NEXT:    ret i1 [[RET]]
+;
+entry:
+  switch i32 %x, label %phi [
+    i32 0, label %case
+    i32 1, label %case
+  ]
+
+case:
+  br label %phi
+
+phi:
+  %res = phi i32 [ %x, %case ], [ 0, %entry ]
+  %ret = icmp ult i32 %res, 2
+  ret i1 %ret
+}
+
+define i1 @switch_multicases_dest2(i32 %x) {
+; CHECK-LABEL: define i1 @switch_multicases_dest2(
+; CHECK-SAME: i32 [[X:%.*]]) {
+; CHECK-NEXT:  entry:
+; CHECK-NEXT:    switch i32 [[X]], label [[DEFAULT:%.*]] [
+; CHECK-NEXT:      i32 0, label [[PHI:%.*]]
+; CHECK-NEXT:      i32 1, label [[PHI]]
+; CHECK-NEXT:    ]
+; CHECK:       default:
+; CHECK-NEXT:    br label [[PHI]]
+; CHECK:       phi:
+; CHECK-NEXT:    [[RES:%.*]] = phi i32 [ [[X]], [[ENTRY:%.*]] ], [ [[X]], [[ENTRY]] ], [ 0, [[DEFAULT]] ]
+; CHECK-NEXT:    [[RET:%.*]] = icmp ult i32 [[RES]], 2
+; CHECK-NEXT:    ret i1 [[RET]]
+;
+entry:
+  switch i32 %x, label %default [
+    i32 0, label %phi
+    i32 1, label %phi
+  ]
+
+default:
+  br label %phi
+
+phi:
+  %res = phi i32 [ %x, %entry ], [ %x, %entry ], [ 0, %default ]
+  %ret = icmp ult i32 %res, 2
+  ret i1 %ret
+}
+
 declare void @llvm.assume(i1)
 
 ;.
diff --git a/llvm/test/Transforms/Util/PredicateInfo/condprop.ll b/llvm/test/Transforms/Util/PredicateInfo/condprop.ll
index 0235732b95a83..d1a0335f7e490 100644
--- a/llvm/test/Transforms/Util/PredicateInfo/condprop.ll
+++ b/llvm/test/Transforms/Util/PredicateInfo/condprop.ll
@@ -133,19 +133,19 @@ define void @test4(i1 %b, i32 %x) {
 ; CHECK-LABEL: @test4(
 ; CHECK-NEXT:    br i1 [[B:%.*]], label [[SW:%.*]], label [[CASE3:%.*]]
 ; CHECK:       sw:
-; CHECK:         i32 0, label [[CASE0:%.*]]
-; CHECK-NEXT:    i32 1, label [[CASE1:%.*]]
-; CHECK-NEXT:    i32 2, label [[CASE0]]
-; CHECK-NEXT:    i32 3, label [[CASE3]]
-; CHECK-NEXT:    i32 4, label [[DEFAULT:%.*]]
-; CHECK-NEXT:    ] Edge: [label [[SW]],label %case1], RenamedOp: [[X:%.*]] }
+; CHECK:           i32 0, label [[CASE0:%.*]]
+; CHECK-NEXT:      i32 1, label [[CASE1:%.*]]
+; CHECK-NEXT:      i32 2, label [[CASE0]]
+; CHECK-NEXT:      i32 3, label [[CASE3]]
+; CHECK-NEXT:      i32 4, label [[DEFAULT:%.*]]
+; CHECK-NEXT:  ] Edge: [label [[SW]],label %case1], RenamedOp: [[X:%.*]] }
 ; CHECK-NEXT:    [[X_0:%.*]] = bitcast i32 [[X]] to i32
 ; CHECK-NEXT:    switch i32 [[X]], label [[DEFAULT]] [
-; CHECK-NEXT:    i32 0, label [[CASE0]]
-; CHECK-NEXT:    i32 1, label [[CASE1]]
-; CHECK-NEXT:    i32 2, label [[CASE0]]
-; CHECK-NEXT:    i32 3, label [[CASE3]]
-; CHECK-NEXT:    i32 4, label [[DEFAULT]]
+; CHECK-NEXT:      i32 0, label [[CASE0]]
+; CHECK-NEXT:      i32 1, label [[CASE1]]
+; CHECK-NEXT:      i32 2, label [[CASE0]]
+; CHECK-NEXT:      i32 3, label [[CASE3]]
+; CHECK-NEXT:      i32 4, label [[DEFAULT]]
 ; CHECK-NEXT:    ]
 ; CHECK:       default:
 ; CHECK-NEXT:    call void @bar(i32 [[X]])
@@ -163,11 +163,11 @@ define void @test4(i1 %b, i32 %x) {
   br i1 %b, label %sw, label %case3
 sw:
   switch i32 %x, label %default [
-  i32 0, label %case0
-  i32 1, label %case1
-  i32 2, label %case0
-  i32 3, label %case3
-  i32 4, label %default
+    i32 0, label %case0
+    i32 1, label %case1
+    i32 2, label %case0
+    i32 3, label %case3
+    i32 4, label %default
   ]
 default:
   call void @bar(i32 %x)
diff --git a/llvm/test/Transforms/Util/PredicateInfo/edge.ll b/llvm/test/Transforms/Util/PredicateInfo/edge.ll
index ef757f323921a..79d8e4023e111 100644
--- a/llvm/test/Transforms/Util/PredicateInfo/edge.ll
+++ b/llvm/test/Transforms/Util/PredicateInfo/edge.ll
@@ -1,5 +1,5 @@
 ; NOTE: Assertions have been autogenerated by utils/update_test_checks.py
-; RUN: opt -passes=print-predicateinfo < %s 2>&1 | FileCheck %s
+; RUN: opt -passes=print-predicateinfo -disable-output < %s 2>&1 | FileCheck %s
 
 define i32 @f1(i32 %x) {
 ; CHECK-LABEL: @f1(
@@ -52,14 +52,16 @@ bb2:
 define i32 @f3(i32 %x) {
 ; CHECK-LABEL: @f3(
 ; CHECK-NEXT:  bb0:
-; CHECK:         [[X_0:%.*]] = bitcast i32 [[X:%.*]] to i32
+; CHECK:           i32 0, label [[BB2:%.*]]
+; CHECK-NEXT:  ] Edge: [label [[BB0:%.*]],label %bb2], RenamedOp: [[X:%.*]] }
+; CHECK-NEXT:    [[X_0:%.*]] = bitcast i32 [[X]] to i32
 ; CHECK-NEXT:    switch i32 [[X]], label [[BB1:%.*]] [
-; CHECK-NEXT:    i32 0, label [[BB2:%.*]]
+; CHECK-NEXT:      i32 0, label [[BB2]]
 ; CHECK-NEXT:    ]
 ; CHECK:       bb1:
 ; CHECK-NEXT:    br label [[BB2]]
 ; CHECK:       bb2:
-; CHECK-NEXT:    [[COND:%.*]] = phi i32 [ [[X_0]], [[BB0:%.*]] ], [ 0, [[BB1]] ]
+; CHECK-NEXT:    [[COND:%.*]] = phi i32 [ [[X_0]], [[BB0]] ], [ 0, [[BB1]] ]
 ; CHECK-NEXT:    [[FOO:%.*]] = add i32 [[COND]], [[X]]
 ; CHECK-NEXT:    ret i32 [[FOO]]
 ;
@@ -240,3 +242,96 @@ return:
   ret double %retval
 
 }
+
+define i32 @switch_default_dest(i32 %x) {
+; CHECK-LABEL: @switch_default_dest(
+; CHECK-NEXT:  case0:
+; CHECK-NEXT:    switch i32 [[X:%.*]], label [[DEFAULT:%.*]] [
+; CHECK-NEXT:      i32 0, label [[PHI:%.*]]
+; CHECK-NEXT:      i32 1, label [[CASE1:%.*]]
+; CHECK-NEXT:    ]
+; CHECK:       case1:
+; CHECK-NEXT:    br label [[PHI]]
+; CHECK:       default:
+; CHECK-NEXT:    br label [[PHI]]
+; CHECK:       phi:
+; CHECK-NEXT:    [[RES:%.*]] = phi i32 [ 0, [[CASE1]] ], [ 1, [[CASE0:%.*]] ], [ [[X]], [[DEFAULT]] ]
+; CHECK-NEXT:    [[FOO:%.*]] = add i32 [[RES]], [[X]]
+; CHECK-NEXT:    ret i32 [[FOO]]
+;
+case0:
+  switch i32 %x, label %default [
+    i32 0, label %phi
+    i32 1, label %case1
+  ]
+
+case1:
+  br label %phi
+
+default:
+  br label %phi
+
+phi:
+  %res = phi i32 [ 0, %case1 ], [ 1, %case0 ], [ %x, %default ]
+  %foo = add i32 %res, %x
+  ret i32 %foo
+}
+
+define i32 @switch_multicases_dest(i32 %x) {
+; CHECK-LABEL: @switch_multicases_dest(
+; CHECK-NEXT:  entry:
+; CHECK-NEXT:    switch i32 [[X:%.*]], label [[PHI:%.*]] [
+; CHECK-NEXT:      i32 0, label [[CASE:%.*]]
+; CHECK-NEXT:      i32 1, label [[CASE]]
+; CHECK-NEXT:    ]
+; CHECK:       case:
+; CHECK-NEXT:    br label [[PHI]]
+; CHECK:       phi:
+; CHECK-NEXT:    [[RES:%.*]] = phi i32 [ [[X]], [[CASE]] ], [ 0, [[ENTRY:%.*]] ]
+; CHECK-NEXT:    [[FOO:%.*]] = add i32 [[RES]], [[X]]
+; CHECK-NEXT:    ret i32 [[FOO]]
+;
+entry:
+  switch i32 %x, label %phi [
+    i32 0, label %case
+    i32 1, label %case
+  ]
+
+case:
+  br label %phi
+
+phi:
+  %res = phi i32 [ %x, %case ], [ 0, %entry ]
+  %foo = add i32 %res, %x
+  ret i32 %foo
+}
+
+define i32 @switch_multicases_dest2(i32 %x) {
+; CHECK-LABEL: @switch_multicases_dest2(
+; CHECK-NEXT:  entry:
+; CHECK-NEXT:    switch i32 [[X:%.*]], label [[DEFAULT:%.*]] [
+; CHECK-NEXT:      i32 0, label [[PHI:%.*]]
+; CHECK-NEXT:      i32 1, label [[PHI]]
+; CHECK-NEXT:    ]
+; CHECK:       default:
+; CHECK-NEXT:    br label [[PHI]]
+; CHECK:       phi:
+; CHECK-NEXT:    [[RES:%.*]] = phi i32 [ [[X]], [[ENTRY:%.*]] ], [ [[X]], [[ENTRY]] ], [ 0, [[DEFAULT]] ]
+; CHECK-NEXT:    [[FOO:%.*]] = add i32 [[RES]], [[X]]
+; CHECK-NEXT:    ret i32 [[FOO]]
+;
+entry:
+  switch i32 %x, label %default [
+    i32 0, label %phi
+    i32 1, label %phi
+  ]
+
+default:
+  br label %phi
+
+phi:
+  %res = phi i32 [ %x, %entry ], [ %x, %entry ], [ 0, %default ]
+  %foo = add i32 %res, %x
+  ret i32 %foo
+}
+

>From ffea262875d67603808673d4ec2caa47f6b248e7 Mon Sep 17 00:00:00 2001
From: Camsyn <camsyn at foxmail.com>
Date: Mon, 27 Oct 2025 17:10:05 +0800
Subject: [PATCH 2/3] [PredicateInfo] Handle switch comprehensively

Now we can handle default-dst and multi-cases dest of switch for
PredicateInfo, via using a constant range to model such scenario.
---
 .../llvm/Transforms/Utils/PredicateInfo.h     |  20 ++-
 llvm/lib/Transforms/Utils/PredicateInfo.cpp   | 123 +++++++++++++++---
 llvm/lib/Transforms/Utils/SCCPSolver.cpp      |  83 +++++++-----
 3 files changed, 175 insertions(+), 51 deletions(-)

diff --git a/llvm/include/llvm/Transforms/Utils/PredicateInfo.h b/llvm/include/llvm/Transforms/Utils/PredicateInfo.h
index 3df3495f84470..64edaa77b2ac9 100644
--- a/llvm/include/llvm/Transforms/Utils/PredicateInfo.h
+++ b/llvm/include/llvm/Transforms/Utils/PredicateInfo.h
@@ -102,6 +102,8 @@ class PredicateBase {
 
   /// Fetch condition in the form of PredicateConstraint, if possible.
   LLVM_ABI std::optional<PredicateConstraint> getConstraint() const;
+  /// Fetch condition in the form of a ConstantRange, if possible.
+  LLVM_ABI std::optional<ConstantRange> getRangeConstraint() const;
 
 protected:
   PredicateBase(PredicateType PT, Value *Op, Value *Condition)
@@ -157,18 +159,24 @@ class PredicateBranch : public PredicateWithEdge {
 
 class PredicateSwitch : public PredicateWithEdge {
 public:
-  Value *CaseValue;
+  using CaseValuesVec = SmallVector<ConstantInt *, 2>;
+  CaseValuesVec CaseValues;
   // This is the switch instruction.
   SwitchInst *Switch;
+  bool IsDefault;
   PredicateSwitch(Value *Op, BasicBlock *SwitchBB, BasicBlock *TargetBB,
-                  Value *CaseValue, SwitchInst *SI)
+                  ArrayRef<ConstantInt *> CaseValues, SwitchInst *SI,
+                  bool IsDefault)
       : PredicateWithEdge(PT_Switch, Op, SwitchBB, TargetBB,
                           SI->getCondition()),
-        CaseValue(CaseValue), Switch(SI) {}
+        CaseValues(CaseValues), Switch(SI), IsDefault(IsDefault) {}
+  PredicateSwitch(Value *Op, BasicBlock *SwitchBB, BasicBlock *TargetBB,
+                  CaseValuesVec &&CaseValues, SwitchInst *SI, bool IsDefault)
+      : PredicateWithEdge(PT_Switch, Op, SwitchBB, TargetBB,
+                          SI->getCondition()),
+        CaseValues(CaseValues), Switch(SI), IsDefault(IsDefault) {}
   PredicateSwitch() = delete;
-  static bool classof(const PredicateBase *PB) {
-    return PB->Type == PT_Switch;
-  }
+  static bool classof(const PredicateBase *PB) { return PB->Type == PT_Switch; }
 };
 
 /// Encapsulates PredicateInfo, including all data associated with memory
diff --git a/llvm/lib/Transforms/Utils/PredicateInfo.cpp b/llvm/lib/Transforms/Utils/PredicateInfo.cpp
index 371d9e6c83163..da828fef583f1 100644
--- a/llvm/lib/Transforms/Utils/PredicateInfo.cpp
+++ b/llvm/lib/Transforms/Utils/PredicateInfo.cpp
@@ -14,8 +14,10 @@
 #include "llvm/ADT/DenseMap.h"
 #include "llvm/ADT/STLExtras.h"
 #include "llvm/ADT/SmallPtrSet.h"
+#include "llvm/ADT/StringExtras.h"
 #include "llvm/Analysis/AssumptionCache.h"
 #include "llvm/IR/AssemblyAnnotationWriter.h"
+#include "llvm/IR/Constants.h"
 #include "llvm/IR/Dominators.h"
 #include "llvm/IR/IRBuilder.h"
 #include "llvm/IR/InstIterator.h"
@@ -442,6 +444,7 @@ void PredicateInfoBuilder::processBranch(
     }
   }
 }
+
 // Process a block terminating switch, and place relevant operations to be
 // renamed into OpsToRename.
 void PredicateInfoBuilder::processSwitch(
@@ -450,21 +453,41 @@ void PredicateInfoBuilder::processSwitch(
   Value *Op = SI->getCondition();
   if ((!isa<Instruction>(Op) && !isa<Argument>(Op)) || Op->hasOneUse())
     return;
+  using CaseValuesVec = PredicateSwitch::CaseValuesVec;
+
+  BasicBlock *DefaultDest = SI->getDefaultDest();
+  // Remember all cases for PT_Switch related to the default dest.
+  CaseValuesVec AllCases;
+  AllCases.reserve(SI->getNumCases());
 
-  // Remember how many outgoing edges there are to every successor.
-  SmallDenseMap<BasicBlock *, unsigned, 16> SwitchEdges;
-  for (BasicBlock *TargetBlock : successors(BranchBB))
-    ++SwitchEdges[TargetBlock];
+  // For each successor, remember all its related case values.
+  SmallDenseMap<BasicBlock *, CaseValuesVec, 16> SwitchEdges;
 
-  // Now propagate info for each case value
   for (auto C : SI->cases()) {
     BasicBlock *TargetBlock = C.getCaseSuccessor();
-    if (SwitchEdges.lookup(TargetBlock) == 1) {
-      PredicateSwitch *PS = new (Allocator) PredicateSwitch(
-          Op, SI->getParent(), TargetBlock, C.getCaseValue(), SI);
-      addInfoFor(OpsToRename, Op, PS);
-    }
+    /// TODO: Replace this if with an assertion if we can guarantee that
+    /// this function must be called after SimplifyCFG, as a canonical switch
+    /// should not have case dest being the default dest.
+    if (TargetBlock == DefaultDest)
+      continue;
+    // Only collect real case values
+    ConstantInt *CaseValue = C.getCaseValue();
+    AllCases.push_back(CaseValue);
+    SwitchEdges[TargetBlock].push_back(CaseValue);
   }
+
+  // Now propagate info for each case successor
+  for (auto *CaseSucc : SwitchEdges.keys()) {
+    auto &CaseValues = SwitchEdges.at(CaseSucc);
+    PredicateSwitch *PS = new (Allocator) PredicateSwitch(
+        Op, SI->getParent(), CaseSucc, std::move(CaseValues), SI, false);
+    addInfoFor(OpsToRename, Op, PS);
+  }
+
+  // Finally, propagate info for the default case
+  PredicateSwitch *PS = new (Allocator) PredicateSwitch(
+      Op, SI->getParent(), DefaultDest, std::move(AllCases), SI, true);
+  addInfoFor(OpsToRename, Op, PS);
 }
 
 // Build predicate info for our function
@@ -500,8 +523,8 @@ void PredicateInfoBuilder::buildPredicateInfo() {
 // Given the renaming stack, make all the operands currently on the stack real
 // by inserting them into the IR.  Return the last operation's value.
 Value *PredicateInfoBuilder::materializeStack(unsigned int &Counter,
-                                             ValueDFSStack &RenameStack,
-                                             Value *OrigOp) {
+                                              ValueDFSStack &RenameStack,
+                                              Value *OrigOp) {
   // Find the first thing we have to materialize
   auto RevIter = RenameStack.rbegin();
   for (; RevIter != RenameStack.rend(); ++RevIter)
@@ -601,7 +624,8 @@ void PredicateInfoBuilder::renameUses(SmallVectorImpl<Value *> &OpsToRename) {
         // block, and handle it specially. We know that it goes last, and only
         // dominate phi uses.
         auto BlockEdge = getBlockEdge(PossibleCopy);
-        if (!BlockEdge.second->getSinglePredecessor()) {
+        // We use unique predecessor to identify the mult-cases dest in switch
+        if (!BlockEdge.second->getUniquePredecessor()) {
           VD.LocalNum = LN_Last;
           auto *DomNode = DT.getNode(BlockEdge.first);
           if (DomNode) {
@@ -759,8 +783,63 @@ std::optional<PredicateConstraint> PredicateBase::getConstraint() const {
       // TODO: Make this an assertion once RenamedOp is fully accurate.
       return std::nullopt;
     }
+    const auto &PS = *cast<PredicateSwitch>(this);
+    unsigned NumCases = PS.CaseValues.size();
+    assert(NumCases != 0 && "PT_Switch with no cases is invalid");
+    // PT_Switch with >1 cases is too complex to derive a PredicateConstraint.
+    if (NumCases > 1)
+      return std::nullopt;
+    // If we have a single case, we can derive a predicate constraint.
+    return {
+        {PS.IsDefault ? CmpInst::ICMP_NE : CmpInst::ICMP_EQ, PS.CaseValues[0]}};
+  }
+  llvm_unreachable("Unknown predicate type");
+}
 
-    return {{CmpInst::ICMP_EQ, cast<PredicateSwitch>(this)->CaseValue}};
+std::optional<ConstantRange> PredicateBase::getRangeConstraint() const {
+  switch (Type) {
+  case PT_Assume:
+  case PT_Branch: {
+    // For PT_Assume/PT_Branch, we derive the condition constant range from
+    // its predicate constraint.
+    const std::optional<PredicateConstraint> &Constraint = getConstraint();
+    if (!Constraint)
+      return std::nullopt;
+    CmpInst::Predicate Pred = Constraint->Predicate;
+    Value *OtherOp = Constraint->OtherOp;
+    const APInt *IntOp;
+    // If the other operand is not a constant integer, we can't derive a
+    // constant range.
+    if (!match(OtherOp, m_APInt(IntOp)))
+      return std::nullopt;
+    return {ConstantRange::makeExactICmpRegion(Pred, *IntOp)};
+  }
+  case PT_Switch:
+    // For PT_Switch, we directly derive the constant range from its case
+    // values.
+    if (Condition != RenamedOp) {
+      // TODO: Make this an assertion once RenamedOp is fully accurate.
+      return std::nullopt;
+    }
+
+    const auto &PS = *cast<PredicateSwitch>(this);
+    assert(!PS.CaseValues.empty() && "SwitchInfo with no cases is invalid");
+
+    unsigned BitWidth = PS.Condition->getType()->getScalarSizeInBits();
+
+    // For case values, CR = emptyset ∪ {case1, case2,..., caseN}
+    // For default, CR = fullset ∩ ~{case1} ∩ ~{case2} ∩ ... ∩ ~{caseN}
+    bool IsDefault = PS.IsDefault;
+    ConstantRange CR = IsDefault ? ConstantRange::getFull(BitWidth)
+                                 : ConstantRange::getEmpty(BitWidth);
+    for (ConstantInt *Case : PS.CaseValues) {
+      assert(Case && "CaseValue in switch should not be null");
+      CR = IsDefault
+               ? CR.intersectWith(ConstantRange(Case->getValue()).inverse())
+               : CR.unionWith(Case->getValue());
+    }
+
+    return {CR};
   }
   llvm_unreachable("Unknown predicate type");
 }
@@ -818,8 +897,20 @@ class PredicateInfoAnnotatedWriter : public AssemblyAnnotationWriter {
         PB->To->printAsOperand(OS);
         OS << "]";
       } else if (const auto *PS = dyn_cast<PredicateSwitch>(PI)) {
-        OS << "; switch predicate info { CaseValue: " << *PS->CaseValue
-           << " Switch:" << *PS->Switch << " Edge: [";
+        OS << "; switch predicate info { ";
+        if (PS->IsDefault) {
+          OS << "Case: default";
+        } else if (PS->CaseValues.size() == 1) {
+          OS << "CaseValue: " << *PS->CaseValues[0];
+        } else {
+          auto CaseValues =
+              llvm::map_range(PS->CaseValues, [](ConstantInt *Case) {
+                return std::to_string(Case->getSExtValue());
+              });
+          OS << "CaseValues: " << *PS->Condition->getType() << " [ "
+             << join(CaseValues, ", ") << " ]";
+        }
+        OS << " Edge: [";
         PS->From->printAsOperand(OS);
         OS << ",";
         PS->To->printAsOperand(OS);
diff --git a/llvm/lib/Transforms/Utils/SCCPSolver.cpp b/llvm/lib/Transforms/Utils/SCCPSolver.cpp
index 4947d03a2dc66..3cde239c7af65 100644
--- a/llvm/lib/Transforms/Utils/SCCPSolver.cpp
+++ b/llvm/lib/Transforms/Utils/SCCPSolver.cpp
@@ -2021,33 +2021,13 @@ void SCCPInstVisitor::handleCallArguments(CallBase &CB) {
 
 void SCCPInstVisitor::handlePredicate(Instruction *I, Value *CopyOf,
                                       const PredicateBase *PI) {
+  const std::optional<ConstantRange> &RangeConstraint =
+      PI->getRangeConstraint();
   ValueLatticeElement CopyOfVal = getValueState(CopyOf);
-  const std::optional<PredicateConstraint> &Constraint = PI->getConstraint();
-  if (!Constraint) {
-    mergeInValue(ValueState[I], I, CopyOfVal);
-    return;
-  }
-
-  CmpInst::Predicate Pred = Constraint->Predicate;
-  Value *OtherOp = Constraint->OtherOp;
-
-  // Wait until OtherOp is resolved.
-  if (getValueState(OtherOp).isUnknown()) {
-    addAdditionalUser(OtherOp, I);
-    return;
-  }
-
-  ValueLatticeElement CondVal = getValueState(OtherOp);
-  ValueLatticeElement &IV = ValueState[I];
-  if (CondVal.isConstantRange() || CopyOfVal.isConstantRange()) {
-    auto ImposedCR =
-        ConstantRange::getFull(DL.getTypeSizeInBits(CopyOf->getType()));
-
-    // Get the range imposed by the condition.
-    if (CondVal.isConstantRange())
-      ImposedCR = ConstantRange::makeAllowedICmpRegion(
-          Pred, CondVal.getConstantRange());
 
+  auto MergeInValueWithImposedCR = [this, I, CopyOfVal,
+                                    CopyOf](ValueLatticeElement &IV,
+                                            ConstantRange ImposedCR) {
     // Combine range info for the original value with the new range from the
     // condition.
     auto CopyOfCR = CopyOfVal.asConstantRange(CopyOf->getType(),
@@ -2067,18 +2047,63 @@ void SCCPInstVisitor::handlePredicate(Instruction *I, Value *CopyOf,
     // unless we have conditions that are always true/false (e.g. icmp ule
     // i32, %a, i32_max). For the latter overdefined/empty range will be
     // inferred, but the branch will get folded accordingly anyways.
-    addAdditionalUser(OtherOp, I);
     mergeInValue(
         IV, I, ValueLatticeElement::getRange(NewCR, /*MayIncludeUndef*/ false));
+  };
+
+  if (RangeConstraint) {
+    // If we can derive a constant range directly from the predicate info,
+    // simply merge it into the lattice value.
+    // In such case, the relevant operands must be constants, and thus we do not
+    // need addAdditionalUser for such operands.
+    MergeInValueWithImposedCR(ValueState[I], *RangeConstraint);
+    return;
+  }
+
+  // If we can't simply get the constant range directly from the predicate info,
+  // then fallback to PredicateConstraint and let SCCPSolver resolve the
+  // possible Imposed CR.
+
+  const std::optional<PredicateConstraint> &Constraint = PI->getConstraint();
+  if (!Constraint) {
+    mergeInValue(ValueState[I], I, CopyOfVal);
+    return;
+  }
+
+  CmpInst::Predicate Pred = Constraint->Predicate;
+  Value *OtherOp = Constraint->OtherOp;
+
+  // Wait until OtherOp is resolved.
+  if (getValueState(OtherOp).isUnknown()) {
+    addAdditionalUser(OtherOp, I);
     return;
-  } else if (Pred == CmpInst::ICMP_EQ &&
-             (CondVal.isConstant() || CondVal.isNotConstant())) {
+  }
+
+  ValueLatticeElement CondVal = getValueState(OtherOp);
+  ValueLatticeElement &IV = ValueState[I];
+  if (CondVal.isConstantRange() || CopyOfVal.isConstantRange()) {
+    // Get the range imposed by the condition.
+    auto ImposedCR =
+        CondVal.isConstantRange()
+            ? ConstantRange::makeAllowedICmpRegion(Pred,
+                                                   CondVal.getConstantRange())
+            : ConstantRange::getFull(DL.getTypeSizeInBits(CopyOf->getType()));
+
+    addAdditionalUser(OtherOp, I);
+    MergeInValueWithImposedCR(IV, ImposedCR);
+    return;
+  }
+
+  if (Pred == CmpInst::ICMP_EQ &&
+      (CondVal.isConstant() || CondVal.isNotConstant())) {
     // For non-integer values or integer constant expressions, only
     // propagate equal constants or not-constants.
     addAdditionalUser(OtherOp, I);
     mergeInValue(IV, I, CondVal);
     return;
-  } else if (Pred == CmpInst::ICMP_NE && CondVal.isConstant()) {
+  }
+
+  if (Pred == CmpInst::ICMP_NE && CondVal.isConstant()) {
     // Propagate inequalities.
     addAdditionalUser(OtherOp, I);
     mergeInValue(IV, I, ValueLatticeElement::getNot(CondVal.getConstant()));

>From 2f10deb05a8403b824d9fef50e96f8f94507a07b Mon Sep 17 00:00:00 2001
From: Camsyn <camsyn at foxmail.com>
Date: Mon, 27 Oct 2025 21:48:30 +0800
Subject: [PATCH 3/3] Regenerate the tests after commit

---
 llvm/test/Transforms/SCCP/switch.ll           |  9 +++-----
 .../Transforms/Util/PredicateInfo/condprop.ll | 20 +++++++---------
 .../Transforms/Util/PredicateInfo/edge.ll     | 23 ++++++++++---------
 3 files changed, 23 insertions(+), 29 deletions(-)

diff --git a/llvm/test/Transforms/SCCP/switch.ll b/llvm/test/Transforms/SCCP/switch.ll
index c4365486e63b4..dfbacdb84e54c 100644
--- a/llvm/test/Transforms/SCCP/switch.ll
+++ b/llvm/test/Transforms/SCCP/switch.ll
@@ -391,8 +391,7 @@ define i1 @switch_default_dest(i32 %x) {
 ; CHECK-NEXT:    br label [[PHI]]
 ; CHECK:       phi:
 ; CHECK-NEXT:    [[RES:%.*]] = phi i32 [ 2, [[CASE1]] ], [ 3, [[CASE0:%.*]] ], [ [[X]], [[DEFAULT]] ]
-; CHECK-NEXT:    [[RET:%.*]] = icmp ult i32 [[RES]], 2
-; CHECK-NEXT:    ret i1 [[RET]]
+; CHECK-NEXT:    ret i1 false
 ;
 case0:
   switch i32 %x, label %default [
@@ -424,8 +423,7 @@ define i1 @switch_multicases_dest(i32 %x) {
 ; CHECK-NEXT:    br label [[PHI]]
 ; CHECK:       phi:
 ; CHECK-NEXT:    [[RES:%.*]] = phi i32 [ [[X]], [[CASE]] ], [ 0, [[ENTRY:%.*]] ]
-; CHECK-NEXT:    [[RET:%.*]] = icmp ult i32 [[RES]], 2
-; CHECK-NEXT:    ret i1 [[RET]]
+; CHECK-NEXT:    ret i1 true
 ;
 entry:
   switch i32 %x, label %phi [
@@ -454,8 +452,7 @@ define i1 @switch_multicases_dest2(i32 %x) {
 ; CHECK-NEXT:    br label [[PHI]]
 ; CHECK:       phi:
 ; CHECK-NEXT:    [[RES:%.*]] = phi i32 [ [[X]], [[ENTRY:%.*]] ], [ [[X]], [[ENTRY]] ], [ 0, [[DEFAULT]] ]
-; CHECK-NEXT:    [[RET:%.*]] = icmp ult i32 [[RES]], 2
-; CHECK-NEXT:    ret i1 [[RET]]
+; CHECK-NEXT:    ret i1 true
 ;
 entry:
   switch i32 %x, label %default [
diff --git a/llvm/test/Transforms/Util/PredicateInfo/condprop.ll b/llvm/test/Transforms/Util/PredicateInfo/condprop.ll
index d1a0335f7e490..2e51bdf6cfc35 100644
--- a/llvm/test/Transforms/Util/PredicateInfo/condprop.ll
+++ b/llvm/test/Transforms/Util/PredicateInfo/condprop.ll
@@ -133,28 +133,24 @@ define void @test4(i1 %b, i32 %x) {
 ; CHECK-LABEL: @test4(
 ; CHECK-NEXT:    br i1 [[B:%.*]], label [[SW:%.*]], label [[CASE3:%.*]]
 ; CHECK:       sw:
-; CHECK:           i32 0, label [[CASE0:%.*]]
+; CHECK:         [[X_0:%.*]] = bitcast i32 [[X:%.*]] to i32
+; CHECK:         [[X_1:%.*]] = bitcast i32 [[X]] to i32
+; CHECK:         [[X_2:%.*]] = bitcast i32 [[X]] to i32
+; CHECK-NEXT:    switch i32 [[X]], label [[DEFAULT:%.*]] [
+; CHECK-NEXT:      i32 0, label [[CASE0:%.*]]
 ; CHECK-NEXT:      i32 1, label [[CASE1:%.*]]
 ; CHECK-NEXT:      i32 2, label [[CASE0]]
 ; CHECK-NEXT:      i32 3, label [[CASE3]]
-; CHECK-NEXT:      i32 4, label [[DEFAULT:%.*]]
-; CHECK-NEXT:  ] Edge: [label [[SW]],label %case1], RenamedOp: [[X:%.*]] }
-; CHECK-NEXT:    [[X_0:%.*]] = bitcast i32 [[X]] to i32
-; CHECK-NEXT:    switch i32 [[X]], label [[DEFAULT]] [
-; CHECK-NEXT:      i32 0, label [[CASE0]]
-; CHECK-NEXT:      i32 1, label [[CASE1]]
-; CHECK-NEXT:      i32 2, label [[CASE0]]
-; CHECK-NEXT:      i32 3, label [[CASE3]]
 ; CHECK-NEXT:      i32 4, label [[DEFAULT]]
 ; CHECK-NEXT:    ]
 ; CHECK:       default:
-; CHECK-NEXT:    call void @bar(i32 [[X]])
+; CHECK-NEXT:    call void @bar(i32 [[X_0]])
 ; CHECK-NEXT:    ret void
 ; CHECK:       case0:
-; CHECK-NEXT:    call void @bar(i32 [[X]])
+; CHECK-NEXT:    call void @bar(i32 [[X_1]])
 ; CHECK-NEXT:    ret void
 ; CHECK:       case1:
-; CHECK-NEXT:    call void @bar(i32 [[X_0]])
+; CHECK-NEXT:    call void @bar(i32 [[X_2]])
 ; CHECK-NEXT:    ret void
 ; CHECK:       case3:
 ; CHECK-NEXT:    call void @bar(i32 [[X]])
diff --git a/llvm/test/Transforms/Util/PredicateInfo/edge.ll b/llvm/test/Transforms/Util/PredicateInfo/edge.ll
index 79d8e4023e111..9560f1cadcfb2 100644
--- a/llvm/test/Transforms/Util/PredicateInfo/edge.ll
+++ b/llvm/test/Transforms/Util/PredicateInfo/edge.ll
@@ -52,16 +52,14 @@ bb2:
 define i32 @f3(i32 %x) {
 ; CHECK-LABEL: @f3(
 ; CHECK-NEXT:  bb0:
-; CHECK:           i32 0, label [[BB2:%.*]]
-; CHECK-NEXT:  ] Edge: [label [[BB0:%.*]],label %bb2], RenamedOp: [[X:%.*]] }
-; CHECK-NEXT:    [[X_0:%.*]] = bitcast i32 [[X]] to i32
+; CHECK:         [[X_0:%.*]] = bitcast i32 [[X:%.*]] to i32
 ; CHECK-NEXT:    switch i32 [[X]], label [[BB1:%.*]] [
-; CHECK-NEXT:      i32 0, label [[BB2]]
+; CHECK-NEXT:      i32 0, label [[BB2:%.*]]
 ; CHECK-NEXT:    ]
 ; CHECK:       bb1:
 ; CHECK-NEXT:    br label [[BB2]]
 ; CHECK:       bb2:
-; CHECK-NEXT:    [[COND:%.*]] = phi i32 [ [[X_0]], [[BB0]] ], [ 0, [[BB1]] ]
+; CHECK-NEXT:    [[COND:%.*]] = phi i32 [ [[X_0]], [[BB0:%.*]] ], [ 0, [[BB1]] ]
 ; CHECK-NEXT:    [[FOO:%.*]] = add i32 [[COND]], [[X]]
 ; CHECK-NEXT:    ret i32 [[FOO]]
 ;
@@ -246,7 +244,8 @@ return:
 define i32 @switch_default_dest(i32 %x) {
 ; CHECK-LABEL: @switch_default_dest(
 ; CHECK-NEXT:  case0:
-; CHECK-NEXT:    switch i32 [[X:%.*]], label [[DEFAULT:%.*]] [
+; CHECK:         [[X_0:%.*]] = bitcast i32 [[X:%.*]] to i32
+; CHECK-NEXT:    switch i32 [[X]], label [[DEFAULT:%.*]] [
 ; CHECK-NEXT:      i32 0, label [[PHI:%.*]]
 ; CHECK-NEXT:      i32 1, label [[CASE1:%.*]]
 ; CHECK-NEXT:    ]
@@ -255,7 +254,7 @@ define i32 @switch_default_dest(i32 %x) {
 ; CHECK:       default:
 ; CHECK-NEXT:    br label [[PHI]]
 ; CHECK:       phi:
-; CHECK-NEXT:    [[RES:%.*]] = phi i32 [ 0, [[CASE1]] ], [ 1, [[CASE0:%.*]] ], [ [[X]], [[DEFAULT]] ]
+; CHECK-NEXT:    [[RES:%.*]] = phi i32 [ 0, [[CASE1]] ], [ 1, [[CASE0:%.*]] ], [ [[X_0]], [[DEFAULT]] ]
 ; CHECK-NEXT:    [[FOO:%.*]] = add i32 [[RES]], [[X]]
 ; CHECK-NEXT:    ret i32 [[FOO]]
 ;
@@ -280,14 +279,15 @@ phi:
 define i32 @switch_multicases_dest(i32 %x) {
 ; CHECK-LABEL: @switch_multicases_dest(
 ; CHECK-NEXT:  entry:
-; CHECK-NEXT:    switch i32 [[X:%.*]], label [[PHI:%.*]] [
+; CHECK:         [[X_0:%.*]] = bitcast i32 [[X:%.*]] to i32
+; CHECK-NEXT:    switch i32 [[X]], label [[PHI:%.*]] [
 ; CHECK-NEXT:      i32 0, label [[CASE:%.*]]
 ; CHECK-NEXT:      i32 1, label [[CASE]]
 ; CHECK-NEXT:    ]
 ; CHECK:       case:
 ; CHECK-NEXT:    br label [[PHI]]
 ; CHECK:       phi:
-; CHECK-NEXT:    [[RES:%.*]] = phi i32 [ [[X]], [[CASE]] ], [ 0, [[ENTRY:%.*]] ]
+; CHECK-NEXT:    [[RES:%.*]] = phi i32 [ [[X_0]], [[CASE]] ], [ 0, [[ENTRY:%.*]] ]
 ; CHECK-NEXT:    [[FOO:%.*]] = add i32 [[RES]], [[X]]
 ; CHECK-NEXT:    ret i32 [[FOO]]
 ;
@@ -309,14 +309,15 @@ phi:
 define i32 @switch_multicases_dest2(i32 %x) {
 ; CHECK-LABEL: @switch_multicases_dest2(
 ; CHECK-NEXT:  entry:
-; CHECK-NEXT:    switch i32 [[X:%.*]], label [[DEFAULT:%.*]] [
+; CHECK:         [[X_0:%.*]] = bitcast i32 [[X:%.*]] to i32
+; CHECK-NEXT:    switch i32 [[X]], label [[DEFAULT:%.*]] [
 ; CHECK-NEXT:      i32 0, label [[PHI:%.*]]
 ; CHECK-NEXT:      i32 1, label [[PHI]]
 ; CHECK-NEXT:    ]
 ; CHECK:       default:
 ; CHECK-NEXT:    br label [[PHI]]
 ; CHECK:       phi:
-; CHECK-NEXT:    [[RES:%.*]] = phi i32 [ [[X]], [[ENTRY:%.*]] ], [ [[X]], [[ENTRY]] ], [ 0, [[DEFAULT]] ]
+; CHECK-NEXT:    [[RES:%.*]] = phi i32 [ [[X_0]], [[ENTRY:%.*]] ], [ [[X_0]], [[ENTRY]] ], [ 0, [[DEFAULT]] ]
 ; CHECK-NEXT:    [[FOO:%.*]] = add i32 [[RES]], [[X]]
 ; CHECK-NEXT:    ret i32 [[FOO]]
 ;



More information about the llvm-commits mailing list