[llvm] [InstCombine] Fold logic of zero-checks to multiplication for MinSize (PR #171805)

via llvm-commits llvm-commits at lists.llvm.org
Thu Dec 11 06:20:28 PST 2025


https://github.com/TelGome updated https://github.com/llvm/llvm-project/pull/171805

>From 708f01b09bcba8d10b61e23827d46c5cb7acde86 Mon Sep 17 00:00:00 2001
From: Dongyan Chen <chendongyan at isrc.iscas.ac.cn>
Date: Wed, 10 Dec 2025 22:06:31 +0800
Subject: [PATCH 1/2] [InstCombine] Fold logic of zero-checks to multiplication
 for MinSize

---
 llvm/lib/CodeGen/SelectionDAG/DAGCombiner.cpp | 60 +++++++++++++++++++
 .../CodeGen/RISCV/fold-zero-check-minsize.ll  | 57 ++++++++++++++++++
 2 files changed, 117 insertions(+)
 mode change 100644 => 100755 llvm/lib/CodeGen/SelectionDAG/DAGCombiner.cpp
 create mode 100755 llvm/test/CodeGen/RISCV/fold-zero-check-minsize.ll

diff --git a/llvm/lib/CodeGen/SelectionDAG/DAGCombiner.cpp b/llvm/lib/CodeGen/SelectionDAG/DAGCombiner.cpp
old mode 100644
new mode 100755
index 6a99d4e29b64f..7861f0937459d
--- a/llvm/lib/CodeGen/SelectionDAG/DAGCombiner.cpp
+++ b/llvm/lib/CodeGen/SelectionDAG/DAGCombiner.cpp
@@ -631,6 +631,7 @@ namespace {
 
     SDValue foldAddToAvg(SDNode *N, const SDLoc &DL);
     SDValue foldSubToAvg(SDNode *N, const SDLoc &DL);
+    SDValue foldLogicSetCCToMul(SDNode *N, const SDLoc &DL);
 
     SDValue SimplifyNodeWithTwoResults(SDNode *N, unsigned LoOp,
                                          unsigned HiOp);
@@ -6648,6 +6649,59 @@ static unsigned getMinMaxOpcodeForFP(SDValue Operand1, SDValue Operand2,
   return ISD::DELETED_NODE;
 }
 
+// Fold the following patterns for small integers in -Oz mode.
+// (X == 0) || (Y == 0) --> (X * Y) == 0
+// (X != 0) && (Y != 0) --> (X * Y) != 0
+SDValue DAGCombiner::foldLogicSetCCToMul(SDNode *N, const SDLoc &DL) {
+  if (OptLevel == CodeGenOptLevel::None ||
+      !DAG.getMachineFunction().getFunction().hasMinSize())
+    return SDValue();
+
+  unsigned Opcode = N->getOpcode();
+  SDValue N0 = N->getOperand(0);
+  SDValue N1 = N->getOperand(1);
+
+  ISD::CondCode ExpectedCC;
+  if (Opcode == ISD::OR) {
+    ExpectedCC = ISD::SETEQ;
+  } else if (Opcode == ISD::AND) {
+    ExpectedCC = ISD::SETNE;
+  } else {
+    return SDValue();
+  }
+
+  if (N0.getOpcode() != ISD::SETCC || N1.getOpcode() != ISD::SETCC)
+    return SDValue();
+
+  SDValue A = N0.getOperand(0);
+  SDValue B = N1.getOperand(0);
+  SDValue C0 = N0.getOperand(1);
+  SDValue C1 = N1.getOperand(1);
+  ISD::CondCode CC0 = cast<CondCodeSDNode>(N0.getOperand(2))->get();
+  ISD::CondCode CC1 = cast<CondCodeSDNode>(N1.getOperand(2))->get();
+
+  if (CC0 != ExpectedCC || CC1 != ExpectedCC || !isNullConstant(C0) ||
+      !isNullConstant(C1) || A.getValueType() != B.getValueType() ||
+      !A.getValueType().isScalarInteger())
+    return SDValue();
+
+  unsigned BitWidth = A.getValueSizeInBits();
+  KnownBits KnownA = DAG.computeKnownBits(A);
+  KnownBits KnownB = DAG.computeKnownBits(B);
+
+  if (KnownA.countMaxActiveBits() + KnownB.countMaxActiveBits() > BitWidth)
+    return SDValue();
+
+  SDNodeFlags Flags;
+  Flags.setNoUnsignedWrap(true);
+  Flags.setNoSignedWrap(true);
+
+  SDValue Mul = DAG.getNode(ISD::MUL, DL, A.getValueType(), A, B, Flags);
+
+  return DAG.getSetCC(DL, N->getValueType(0), Mul,
+                      DAG.getConstant(0, DL, A.getValueType()), ExpectedCC);
+}
+
 static SDValue foldAndOrOfSETCC(SDNode *LogicOp, SelectionDAG &DAG) {
   using AndOrSETCCFoldKind = TargetLowering::AndOrSETCCFoldKind;
   assert(
@@ -7555,6 +7609,9 @@ SDValue DAGCombiner::visitAND(SDNode *N) {
   if (N1C && DAG.MaskedValueIsZero(SDValue(N, 0), APInt::getAllOnes(BitWidth)))
     return DAG.getConstant(0, DL, VT);
 
+  if (SDValue R = foldLogicSetCCToMul(N, DL))
+    return R;
+
   if (SDValue R = foldAndOrOfSETCC(N, DAG))
     return R;
 
@@ -8520,6 +8577,9 @@ SDValue DAGCombiner::visitOR(SDNode *N) {
   if (N1C && DAG.MaskedValueIsZero(N0, ~N1C->getAPIntValue()))
     return N1;
 
+  if (SDValue R = foldLogicSetCCToMul(N, DL))
+    return R;
+
   if (SDValue R = foldAndOrOfSETCC(N, DAG))
     return R;
 
diff --git a/llvm/test/CodeGen/RISCV/fold-zero-check-minsize.ll b/llvm/test/CodeGen/RISCV/fold-zero-check-minsize.ll
new file mode 100755
index 0000000000000..19fc9fb544fb4
--- /dev/null
+++ b/llvm/test/CodeGen/RISCV/fold-zero-check-minsize.ll
@@ -0,0 +1,57 @@
+; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py
+; RUN: llc -mtriple=riscv64 -mattr=+m -verify-machineinstrs < %s \
+; RUN:   | FileCheck %s
+
+define i1 @foldLogicSetCCToMul0(i16 zeroext %a, i16 zeroext %b) minsize {
+; CHECK-LABEL: foldLogicSetCCToMul0:
+; CHECK:       # %bb.0:
+; CHECK-NEXT:    mul a0, a0, a1
+; CHECK-NEXT:    seqz a0, a0
+; CHECK-NEXT:    ret
+entry:
+  %cmp1 = icmp eq i16 %a, 0
+  %cmp2 = icmp eq i16 %b, 0
+  %or = or i1 %cmp1, %cmp2
+  ret i1 %or
+}
+
+define i1 @foldLogicSetCCToMul1(i16 zeroext %a, i16 zeroext %b) minsize {
+; CHECK-LABEL: foldLogicSetCCToMul1:
+; CHECK:       # %bb.0:
+; CHECK-NEXT:    mul a0, a0, a1
+; CHECK-NEXT:    snez a0, a0
+; CHECK-NEXT:    ret
+entry:
+  %cmp1 = icmp ne i16 %a, 0
+  %cmp2 = icmp ne i16 %b, 0
+  %and = and i1 %cmp1, %cmp2
+  ret i1 %and
+}
+
+define i1 @foldLogicSetCCToMul2(i64 %a, i64 %b) minsize {
+; CHECK-LABEL: foldLogicSetCCToMul2:
+; CHECK:       # %bb.0:
+; CHECK-NEXT:    seqz a0, a0
+; CHECK-NEXT:    seqz a1, a1
+; CHECK-NEXT:    or a0, a0, a1
+; CHECK-NEXT:    ret
+entry:
+  %cmp1 = icmp eq i64 %a, 0
+  %cmp2 = icmp eq i64 %b, 0
+  %or = or i1 %cmp1, %cmp2
+  ret i1 %or
+}
+
+define i1 @foldLogicSetCCToMul3(i16 zeroext %a, i16 zeroext %b) {
+; CHECK-LABEL: foldLogicSetCCToMul3:
+; CHECK:       # %bb.0:
+; CHECK-NEXT:    seqz a0, a0
+; CHECK-NEXT:    seqz a1, a1
+; CHECK-NEXT:    or a0, a0, a1
+; CHECK-NEXT:    ret
+entry:
+  %cmp1 = icmp eq i16 %a, 0
+  %cmp2 = icmp eq i16 %b, 0
+  %or = or i1 %cmp1, %cmp2
+  ret i1 %or
+}
\ No newline at end of file

>From 6c14b48cd35368e00287fa836685d4ae896d89a8 Mon Sep 17 00:00:00 2001
From: Dongyan Chen <chendongyan at isrc.iscas.ac.cn>
Date: Thu, 11 Dec 2025 22:13:41 +0800
Subject: [PATCH 2/2] fix and add testcases

---
 llvm/lib/CodeGen/SelectionDAG/DAGCombiner.cpp | 13 +++--
 .../CodeGen/RISCV/fold-zero-check-minsize.ll  | 49 +++++++++++++++++--
 2 files changed, 52 insertions(+), 10 deletions(-)

diff --git a/llvm/lib/CodeGen/SelectionDAG/DAGCombiner.cpp b/llvm/lib/CodeGen/SelectionDAG/DAGCombiner.cpp
index 7861f0937459d..bebf58db2f8c6 100755
--- a/llvm/lib/CodeGen/SelectionDAG/DAGCombiner.cpp
+++ b/llvm/lib/CodeGen/SelectionDAG/DAGCombiner.cpp
@@ -6653,8 +6653,7 @@ static unsigned getMinMaxOpcodeForFP(SDValue Operand1, SDValue Operand2,
 // (X == 0) || (Y == 0) --> (X * Y) == 0
 // (X != 0) && (Y != 0) --> (X * Y) != 0
 SDValue DAGCombiner::foldLogicSetCCToMul(SDNode *N, const SDLoc &DL) {
-  if (OptLevel == CodeGenOptLevel::None ||
-      !DAG.getMachineFunction().getFunction().hasMinSize())
+  if (!DAG.getMachineFunction().getFunction().hasMinSize())
     return SDValue();
 
   unsigned Opcode = N->getOpcode();
@@ -6680,9 +6679,10 @@ SDValue DAGCombiner::foldLogicSetCCToMul(SDNode *N, const SDLoc &DL) {
   ISD::CondCode CC0 = cast<CondCodeSDNode>(N0.getOperand(2))->get();
   ISD::CondCode CC1 = cast<CondCodeSDNode>(N1.getOperand(2))->get();
 
-  if (CC0 != ExpectedCC || CC1 != ExpectedCC || !isNullConstant(C0) ||
-      !isNullConstant(C1) || A.getValueType() != B.getValueType() ||
-      !A.getValueType().isScalarInteger())
+  if (CC0 != ExpectedCC || CC1 != ExpectedCC ||
+      !A.getValueType().isScalarInteger() ||
+      A.getValueType() != B.getValueType() || !isNullConstant(C0) ||
+      !isNullConstant(C1))
     return SDValue();
 
   unsigned BitWidth = A.getValueSizeInBits();
@@ -6698,8 +6698,7 @@ SDValue DAGCombiner::foldLogicSetCCToMul(SDNode *N, const SDLoc &DL) {
 
   SDValue Mul = DAG.getNode(ISD::MUL, DL, A.getValueType(), A, B, Flags);
 
-  return DAG.getSetCC(DL, N->getValueType(0), Mul,
-                      DAG.getConstant(0, DL, A.getValueType()), ExpectedCC);
+  return DAG.getSetCC(DL, N->getValueType(0), Mul, C0, ExpectedCC);
 }
 
 static SDValue foldAndOrOfSETCC(SDNode *LogicOp, SelectionDAG &DAG) {
diff --git a/llvm/test/CodeGen/RISCV/fold-zero-check-minsize.ll b/llvm/test/CodeGen/RISCV/fold-zero-check-minsize.ll
index 19fc9fb544fb4..8ce7dd7f1bf17 100755
--- a/llvm/test/CodeGen/RISCV/fold-zero-check-minsize.ll
+++ b/llvm/test/CodeGen/RISCV/fold-zero-check-minsize.ll
@@ -1,6 +1,5 @@
 ; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py
-; RUN: llc -mtriple=riscv64 -mattr=+m -verify-machineinstrs < %s \
-; RUN:   | FileCheck %s
+; RUN: llc -mtriple=riscv64 -mattr=+m -enable-machine-outliner=never < %s | FileCheck %s
 
 define i1 @foldLogicSetCCToMul0(i16 zeroext %a, i16 zeroext %b) minsize {
 ; CHECK-LABEL: foldLogicSetCCToMul0:
@@ -54,4 +53,48 @@ entry:
   %cmp2 = icmp eq i16 %b, 0
   %or = or i1 %cmp1, %cmp2
   ret i1 %or
-}
\ No newline at end of file
+}
+
+define i1 @foldLogicSetCCToMul4(i16 zeroext %a, i16 zeroext %b) minsize {
+; CHECK-LABEL: foldLogicSetCCToMul4:
+; CHECK-NOT: mul
+; CHECK: ret
+entry:
+  %cmp1 = icmp eq i16 %a, 0
+  %cmp2 = icmp ne i16 %b, 0
+  %or = or i1 %cmp1, %cmp2
+  ret i1 %or
+}
+
+define i1 @foldLogicSetCCToMul5(i16 zeroext %a, i16 zeroext %b) minsize {
+; CHECK-LABEL: foldLogicSetCCToMul5:
+; CHECK-NOT: mul
+; CHECK: ret
+entry:
+  %cmp1 = icmp eq i16 %a, 1;
+  %cmp2 = icmp eq i16 %b, 0
+  %or = or i1 %cmp1, %cmp2
+  ret i1 %or
+}
+
+define i1 @foldLogicSetCCToMul6(i16 zeroext %a, i16 zeroext %b) minsize {
+; CHECK-LABEL: foldLogicSetCCToMul6:
+; CHECK-NOT: mul
+; CHECK: ret
+entry:
+  %cmp1 = icmp eq i16 %a, 0;
+  %cmp2 = icmp eq i16 %b, 1
+  %or = or i1 %cmp1, %cmp2
+  ret i1 %or
+}
+
+define i1 @foldLogicSetCCToMul7(i16 zeroext %a, i32 %b) minsize {
+; CHECK-LABEL: foldLogicSetCCToMul7:
+; CHECK-NOT: mul
+; CHECK: ret
+entry:
+  %cmp1 = icmp eq i16 %a, 0
+  %cmp2 = icmp eq i32 %b, 0
+  %or = or i1 %cmp1, %cmp2
+  ret i1 %or
+}



More information about the llvm-commits mailing list