[llvm] [DAGCombiner] Fold (or (seteq X, 0), (seteq X, -1)) to (setult (add X, 1), 2) (PR #192183)

Jim Lin via llvm-commits llvm-commits at lists.llvm.org
Tue Apr 14 22:12:27 PDT 2026


https://github.com/tclin914 created https://github.com/llvm/llvm-project/pull/192183

This is the De Morgan dual of the existing fold:
    (and (setne X, 0), (setne X, -1)) --> (setuge (add X, 1), 2)

The or-of-equalities version checks if X is either 0 or -1, which is
equivalent to (X+1) < 2 (unsigned). This reduces two comparisons and
an or to one add and one comparison.


>From 251ed15f8a7f6dc330fa2aba87a019efe08e40d5 Mon Sep 17 00:00:00 2001
From: Jim Lin <jim at andestech.com>
Date: Tue, 14 Apr 2026 06:44:54 +0000
Subject: [PATCH 1/2] [ARM] Pre-commit test for (or (seteq X, 0), (seteq X,
 -1)) fold

NFC. Baseline test for an upcoming DAGCombiner fold.
---
 llvm/test/CodeGen/ARM/setcc-logic.ll | 16 ++++++++++++++++
 1 file changed, 16 insertions(+)

diff --git a/llvm/test/CodeGen/ARM/setcc-logic.ll b/llvm/test/CodeGen/ARM/setcc-logic.ll
index cf482f39f2b5b..29fa0cb626680 100644
--- a/llvm/test/CodeGen/ARM/setcc-logic.ll
+++ b/llvm/test/CodeGen/ARM/setcc-logic.ll
@@ -15,6 +15,22 @@ define zeroext i1 @ne_neg1_and_ne_zero(i32 %x) nounwind {
   ret i1 %and
 }
 
+define zeroext i1 @eq_zero_or_eq_neg1(i32 %x) nounwind {
+; CHECK-LABEL: eq_zero_or_eq_neg1:
+; CHECK:       @ %bb.0:
+; CHECK-NEXT:    add r1, r0, #1
+; CHECK-NEXT:    clz r0, r0
+; CHECK-NEXT:    clz r1, r1
+; CHECK-NEXT:    lsr r0, r0, #5
+; CHECK-NEXT:    lsr r1, r1, #5
+; CHECK-NEXT:    orr r0, r0, r1
+; CHECK-NEXT:    bx lr
+  %cmp1 = icmp eq i32 %x, 0
+  %cmp2 = icmp eq i32 %x, -1
+  %or = or i1 %cmp1, %cmp2
+  ret i1 %or
+}
+
 ; PR32401 - https://bugs.llvm.org/show_bug.cgi?id=32401
 
 define zeroext i1 @and_eq(i32 %a, i32 %b, i32 %c, i32 %d) nounwind {

>From 3d4e354c211bb0d1bc6056db8feff730fb0a1dea Mon Sep 17 00:00:00 2001
From: Jim Lin <jim at andestech.com>
Date: Mon, 13 Apr 2026 09:11:14 +0800
Subject: [PATCH 2/2] [DAGCombiner] Fold (or (seteq X, 0), (seteq X, -1)) to
 (setult (add X, 1), 2)

This is the De Morgan dual of the existing fold:
  (and (setne X, 0), (setne X, -1)) --> (setuge (add X, 1), 2)

The or-of-equalities version checks if X is either 0 or -1, which is
equivalent to (X+1) < 2 (unsigned). This reduces two comparisons and
an or to one add and one comparison.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply at anthropic.com>
---
 llvm/lib/CodeGen/SelectionDAG/DAGCombiner.cpp | 10 ++++++----
 llvm/test/CodeGen/ARM/setcc-logic.ll          |  8 +++-----
 2 files changed, 9 insertions(+), 9 deletions(-)

diff --git a/llvm/lib/CodeGen/SelectionDAG/DAGCombiner.cpp b/llvm/lib/CodeGen/SelectionDAG/DAGCombiner.cpp
index aee5aabdc9e02..b72ed539be473 100644
--- a/llvm/lib/CodeGen/SelectionDAG/DAGCombiner.cpp
+++ b/llvm/lib/CodeGen/SelectionDAG/DAGCombiner.cpp
@@ -6605,17 +6605,19 @@ SDValue DAGCombiner::foldLogicOfSetCCs(bool IsAnd, SDValue N0, SDValue N1,
     }
   }
 
-  // TODO: What is the 'or' equivalent of this fold?
   // (and (setne X, 0), (setne X, -1)) --> (setuge (add X, 1), 2)
-  if (IsAnd && LL == RL && CC0 == CC1 && OpVT.getScalarSizeInBits() > 1 &&
-      IsInteger && CC0 == ISD::SETNE &&
+  // (or  (seteq X, 0), (seteq X, -1)) --> (setult (add X, 1), 2)
+  if (LL == RL && CC0 == CC1 && OpVT.getScalarSizeInBits() > 1 &&
+      IsInteger &&
+      ((IsAnd && CC0 == ISD::SETNE) || (!IsAnd && CC0 == ISD::SETEQ)) &&
       ((isNullConstant(LR) && isAllOnesConstant(RR)) ||
        (isAllOnesConstant(LR) && isNullConstant(RR)))) {
     SDValue One = DAG.getConstant(1, DL, OpVT);
     SDValue Two = DAG.getConstant(2, DL, OpVT);
     SDValue Add = DAG.getNode(ISD::ADD, SDLoc(N0), OpVT, LL, One);
     AddToWorklist(Add.getNode());
-    return DAG.getSetCC(DL, VT, Add, Two, ISD::SETUGE);
+    return DAG.getSetCC(DL, VT, Add, Two,
+                        IsAnd ? ISD::SETUGE : ISD::SETULT);
   }
 
   // Try more general transforms if the predicates match and the only user of
diff --git a/llvm/test/CodeGen/ARM/setcc-logic.ll b/llvm/test/CodeGen/ARM/setcc-logic.ll
index 29fa0cb626680..dc34db54614f7 100644
--- a/llvm/test/CodeGen/ARM/setcc-logic.ll
+++ b/llvm/test/CodeGen/ARM/setcc-logic.ll
@@ -19,11 +19,9 @@ define zeroext i1 @eq_zero_or_eq_neg1(i32 %x) nounwind {
 ; CHECK-LABEL: eq_zero_or_eq_neg1:
 ; CHECK:       @ %bb.0:
 ; CHECK-NEXT:    add r1, r0, #1
-; CHECK-NEXT:    clz r0, r0
-; CHECK-NEXT:    clz r1, r1
-; CHECK-NEXT:    lsr r0, r0, #5
-; CHECK-NEXT:    lsr r1, r1, #5
-; CHECK-NEXT:    orr r0, r0, r1
+; CHECK-NEXT:    mov r0, #0
+; CHECK-NEXT:    cmp r1, #2
+; CHECK-NEXT:    movwlo r0, #1
 ; CHECK-NEXT:    bx lr
   %cmp1 = icmp eq i32 %x, 0
   %cmp2 = icmp eq i32 %x, -1



More information about the llvm-commits mailing list