[llvm] [SimplifyCFG] Handle that first matched eq cond in if chain can be Extra condition. (PR #154007)

Andreas Jonson via llvm-commits llvm-commits at lists.llvm.org
Sun Aug 17 23:54:16 PDT 2025


https://github.com/andjo403 updated https://github.com/llvm/llvm-project/pull/154007

>From f009efead55b02f1834b92fd9c534a85214d7752 Mon Sep 17 00:00:00 2001
From: Andreas Jonson <andjo403 at hotmail.com>
Date: Sun, 17 Aug 2025 10:23:25 +0200
Subject: [PATCH 1/3] [SimplifyCFG] Add test with multiple eq cond in if chain
 (NFC)

---
 .../Transforms/SimplifyCFG/switch_create.ll   | 66 +++++++++++++++++++
 1 file changed, 66 insertions(+)

diff --git a/llvm/test/Transforms/SimplifyCFG/switch_create.ll b/llvm/test/Transforms/SimplifyCFG/switch_create.ll
index f446d718f8206..f9fcc8615c0ce 100644
--- a/llvm/test/Transforms/SimplifyCFG/switch_create.ll
+++ b/llvm/test/Transforms/SimplifyCFG/switch_create.ll
@@ -1068,3 +1068,69 @@ if:
 else:
   ret void
 }
+
+define void @extra_cond_is_eq_cmp(i8 %c, i32 %x)  {
+; CHECK-LABEL: @extra_cond_is_eq_cmp(
+; CHECK-NEXT:  entry:
+; CHECK-NEXT:    [[CMP:%.*]] = icmp eq i32 [[X:%.*]], 32
+; CHECK-NEXT:    [[CMP4:%.*]] = icmp eq i8 [[C:%.*]], 97
+; CHECK-NEXT:    [[OR_COND:%.*]] = or i1 [[CMP]], [[CMP4]]
+; CHECK-NEXT:    [[CMP9:%.*]] = icmp eq i8 [[C]], 99
+; CHECK-NEXT:    [[TMP0:%.*]] = or i1 [[OR_COND]], [[CMP9]]
+; CHECK-NEXT:    br i1 [[TMP0]], label [[IF_THEN:%.*]], label [[SWITCH_EARLY_TEST:%.*]]
+; CHECK:       common.ret:
+; CHECK-NEXT:    ret void
+; CHECK:       if.then:
+; CHECK-NEXT:    tail call void @foo1()
+; CHECK-NEXT:    br label [[SWITCH_EARLY_TEST]]
+;
+entry:
+  %cmp = icmp eq i32 %x, 32
+  %cmp4 = icmp eq i8 %c, 97
+  %or.cond = or i1 %cmp, %cmp4
+  %cmp9 = icmp eq i8 %c, 99
+  %or.cond11 = or i1 %or.cond, %cmp9
+  br i1 %or.cond11, label %if.then, label %if.end
+
+if.then:
+  tail call void @foo1()
+  ret void
+
+if.end:
+  ret void
+
+}
+
+define void @extra_cond_is_eq_cmp_c(i8 %c, i32 %x)  {
+; CHECK-LABEL: @extra_cond_is_eq_cmp_c(
+; CHECK-NEXT:  entry:
+; CHECK-NEXT:    [[CMP:%.*]] = icmp eq i32 [[X:%.*]], 32
+; CHECK-NEXT:    [[TMP0:%.*]] = freeze i1 [[CMP]]
+; CHECK-NEXT:    br i1 [[TMP0]], label [[IF_THEN:%.*]], label [[SWITCH_EARLY_TEST:%.*]]
+; CHECK:       switch.early.test:
+; CHECK-NEXT:    switch i8 [[C:%.*]], label [[COMMON_RET:%.*]] [
+; CHECK-NEXT:      i8 99, label [[IF_THEN]]
+; CHECK-NEXT:      i8 97, label [[IF_THEN]]
+; CHECK-NEXT:    ]
+; CHECK:       common.ret:
+; CHECK-NEXT:    ret void
+; CHECK:       if.then:
+; CHECK-NEXT:    tail call void @foo1()
+; CHECK-NEXT:    br label [[COMMON_RET]]
+;
+entry:
+  %cmp = icmp eq i32 %x, 32
+  %cmp4 = icmp eq i8 %c, 97
+  %or.cond = or i1 %cmp4, %cmp
+  %cmp9 = icmp eq i8 %c, 99
+  %or.cond11 = or i1 %or.cond, %cmp9
+  br i1 %or.cond11, label %if.then, label %if.end
+
+if.then:
+  tail call void @foo1()
+  ret void
+
+if.end:
+  ret void
+
+}

>From 2e35b842b0fd096c5ffcef2c04b6a688a26f055a Mon Sep 17 00:00:00 2001
From: Andreas Jonson <andjo403 at hotmail.com>
Date: Sun, 17 Aug 2025 10:28:24 +0200
Subject: [PATCH 2/3] [SimplifyCFG] Handle that first matched eq cond in if
 chain can be Extra condition.

---
 llvm/lib/Transforms/Utils/SimplifyCFG.cpp         | 14 ++++++++++++++
 llvm/test/Transforms/SimplifyCFG/switch_create.ll | 12 +++++++-----
 2 files changed, 21 insertions(+), 5 deletions(-)

diff --git a/llvm/lib/Transforms/Utils/SimplifyCFG.cpp b/llvm/lib/Transforms/Utils/SimplifyCFG.cpp
index 1436e479ba091..42b35c0c7e69e 100644
--- a/llvm/lib/Transforms/Utils/SimplifyCFG.cpp
+++ b/llvm/lib/Transforms/Utils/SimplifyCFG.cpp
@@ -564,9 +564,19 @@ struct ConstantComparesGatherer {
   /// Number of comparisons matched in the and/or chain
   unsigned UsedICmps = 0;
 
+  // Used to check if the first matched CompValue shall be the Extra check.
+  bool IgnoreFirstMatch = false;
+
   /// Construct and compute the result for the comparison instruction Cond
   ConstantComparesGatherer(Instruction *Cond, const DataLayout &DL) : DL(DL) {
     gather(Cond);
+    if (CompValue)
+      return;
+    Extra = nullptr;
+    Vals.clear();
+    UsedICmps = 0;
+    IgnoreFirstMatch = true;
+    gather(Cond);
   }
 
   ConstantComparesGatherer(const ConstantComparesGatherer &) = delete;
@@ -577,6 +587,10 @@ struct ConstantComparesGatherer {
   /// Try to set the current value used for the comparison, it succeeds only if
   /// it wasn't set before or if the new value is the same as the old one
   bool setValueOnce(Value *NewVal) {
+    if (IgnoreFirstMatch && NewVal) {
+      IgnoreFirstMatch = false;
+      return false;
+    }
     if (CompValue && CompValue != NewVal)
       return false;
     CompValue = NewVal;
diff --git a/llvm/test/Transforms/SimplifyCFG/switch_create.ll b/llvm/test/Transforms/SimplifyCFG/switch_create.ll
index f9fcc8615c0ce..5f3c7b7c0fd5d 100644
--- a/llvm/test/Transforms/SimplifyCFG/switch_create.ll
+++ b/llvm/test/Transforms/SimplifyCFG/switch_create.ll
@@ -1073,16 +1073,18 @@ define void @extra_cond_is_eq_cmp(i8 %c, i32 %x)  {
 ; CHECK-LABEL: @extra_cond_is_eq_cmp(
 ; CHECK-NEXT:  entry:
 ; CHECK-NEXT:    [[CMP:%.*]] = icmp eq i32 [[X:%.*]], 32
-; CHECK-NEXT:    [[CMP4:%.*]] = icmp eq i8 [[C:%.*]], 97
-; CHECK-NEXT:    [[OR_COND:%.*]] = or i1 [[CMP]], [[CMP4]]
-; CHECK-NEXT:    [[CMP9:%.*]] = icmp eq i8 [[C]], 99
-; CHECK-NEXT:    [[TMP0:%.*]] = or i1 [[OR_COND]], [[CMP9]]
+; CHECK-NEXT:    [[TMP0:%.*]] = freeze i1 [[CMP]]
 ; CHECK-NEXT:    br i1 [[TMP0]], label [[IF_THEN:%.*]], label [[SWITCH_EARLY_TEST:%.*]]
+; CHECK:       switch.early.test:
+; CHECK-NEXT:    switch i8 [[C:%.*]], label [[COMMON_RET:%.*]] [
+; CHECK-NEXT:      i8 99, label [[IF_THEN]]
+; CHECK-NEXT:      i8 97, label [[IF_THEN]]
+; CHECK-NEXT:    ]
 ; CHECK:       common.ret:
 ; CHECK-NEXT:    ret void
 ; CHECK:       if.then:
 ; CHECK-NEXT:    tail call void @foo1()
-; CHECK-NEXT:    br label [[SWITCH_EARLY_TEST]]
+; CHECK-NEXT:    br label [[COMMON_RET]]
 ;
 entry:
   %cmp = icmp eq i32 %x, 32

>From 51eec75af0351d0fbe5ccd99472170cc87a45e20 Mon Sep 17 00:00:00 2001
From: Andreas Jonson <andjo403 at hotmail.com>
Date: Mon, 18 Aug 2025 08:53:59 +0200
Subject: [PATCH 3/3] [SimplifyCFG] Speedup ConstantComparesGatherer (NFC)

---
 llvm/lib/Transforms/Utils/SimplifyCFG.cpp | 26 +++++++++++++++++------
 1 file changed, 19 insertions(+), 7 deletions(-)

diff --git a/llvm/lib/Transforms/Utils/SimplifyCFG.cpp b/llvm/lib/Transforms/Utils/SimplifyCFG.cpp
index 42b35c0c7e69e..1815fbb291705 100644
--- a/llvm/lib/Transforms/Utils/SimplifyCFG.cpp
+++ b/llvm/lib/Transforms/Utils/SimplifyCFG.cpp
@@ -566,11 +566,12 @@ struct ConstantComparesGatherer {
 
   // Used to check if the first matched CompValue shall be the Extra check.
   bool IgnoreFirstMatch = false;
+  bool MultipleMatches = false;
 
   /// Construct and compute the result for the comparison instruction Cond
   ConstantComparesGatherer(Instruction *Cond, const DataLayout &DL) : DL(DL) {
     gather(Cond);
-    if (CompValue)
+    if (CompValue || !MultipleMatches)
       return;
     Extra = nullptr;
     Vals.clear();
@@ -591,8 +592,10 @@ struct ConstantComparesGatherer {
       IgnoreFirstMatch = false;
       return false;
     }
-    if (CompValue && CompValue != NewVal)
+    if (CompValue && CompValue != NewVal) {
+      MultipleMatches = true;
       return false;
+    }
     CompValue = NewVal;
     return (CompValue != nullptr);
   }
@@ -749,7 +752,6 @@ struct ConstantComparesGatherer {
   /// vector.
   /// One "Extra" case is allowed to differ from the other.
   void gather(Value *V) {
-    bool isEQ = match(V, m_LogicalOr(m_Value(), m_Value()));
 
     // Keep a stack (SmallVector for efficiency) for depth-first traversal
     SmallVector<Value *, 8> DFT;
@@ -757,15 +759,25 @@ struct ConstantComparesGatherer {
 
     // Initialize
     Visited.insert(V);
-    DFT.push_back(V);
+    Value *Op0, *Op1;
+    bool IsEq;
+    if (match(V, m_LogicalOr(m_Value(Op0), m_Value(Op1))))
+      IsEq = true;
+    else if (match(V, m_LogicalAnd(m_Value(Op0), m_Value(Op1))))
+      IsEq = false;
+    else
+      return;
+    Visited.insert(Op1);
+    DFT.push_back(Op1);
+    Visited.insert(Op0);
+    DFT.push_back(Op0);
 
     while (!DFT.empty()) {
       V = DFT.pop_back_val();
 
       if (Instruction *I = dyn_cast<Instruction>(V)) {
         // If it is a || (or && depending on isEQ), process the operands.
-        Value *Op0, *Op1;
-        if (isEQ ? match(I, m_LogicalOr(m_Value(Op0), m_Value(Op1)))
+        if (IsEq ? match(I, m_LogicalOr(m_Value(Op0), m_Value(Op1)))
                  : match(I, m_LogicalAnd(m_Value(Op0), m_Value(Op1)))) {
           if (Visited.insert(Op1).second)
             DFT.push_back(Op1);
@@ -776,7 +788,7 @@ struct ConstantComparesGatherer {
         }
 
         // Try to match the current instruction
-        if (matchInstruction(I, isEQ))
+        if (matchInstruction(I, IsEq))
           // Match succeed, continue the loop
           continue;
       }



More information about the llvm-commits mailing list