[llvm] [DAGCombiner] Fold sext_in_reg when adding sign bit to an already extended value. (PR #214848)

Usman Nadeem via llvm-commits llvm-commits at lists.llvm.org
Fri Aug 7 21:39:12 PDT 2026


https://github.com/UsmanNadeem updated https://github.com/llvm/llvm-project/pull/214848

>From 2e1da7d788ac4a7d11874741aaee0b21e7e3d552 Mon Sep 17 00:00:00 2001
From: Usman Nadeem <mnadeem at qti.qualcomm.com>
Date: Fri, 7 Aug 2026 13:45:14 -0700
Subject: [PATCH 1/2] [DAGCombiner] Fold sext_in_reg when adding sign bit to an
 already extended value.

Change-Id: Icbd1c7b02734a198cb5eb653a3912b09a6a3140e
Proof: https://alive2.llvm.org/ce/z/HEaaA5
---
 llvm/lib/CodeGen/SelectionDAG/DAGCombiner.cpp | 19 +++++++++++++++++++
 llvm/test/CodeGen/ARM/sdiv-pow2-arm-size.ll   |  1 -
 llvm/test/CodeGen/ARM/sdiv-pow2-thumb-size.ll |  4 ----
 llvm/test/CodeGen/RISCV/sdiv-pow2-cmov.ll     |  4 ++--
 4 files changed, 21 insertions(+), 7 deletions(-)

diff --git a/llvm/lib/CodeGen/SelectionDAG/DAGCombiner.cpp b/llvm/lib/CodeGen/SelectionDAG/DAGCombiner.cpp
index f5620743d6ed1..6973bcdc9d259 100644
--- a/llvm/lib/CodeGen/SelectionDAG/DAGCombiner.cpp
+++ b/llvm/lib/CodeGen/SelectionDAG/DAGCombiner.cpp
@@ -17223,6 +17223,25 @@ SDValue DAGCombiner::visitSIGN_EXTEND_INREG(SDNode *N) {
   if (DAG.MaskedValueIsZero(N0, APInt::getOneBitSet(VTBits, ExtVTBits - 1)))
     return DAG.getZeroExtendInReg(N0, DL, ExtVT);
 
+  // fold (sext_in_reg add(x, sign_bit_of(x))) -> add(x, sign_bit_of(x))
+  // if we are not extending beyond the original extension type of x.
+  {
+    SDValue AddOp;
+    uint64_t BitNo;
+    APInt BitMask;
+    if (sd_match(N0,
+                 m_c_BinOp(ISD::ADD, m_Value(AddOp),
+                           m_Srl(m_And(m_Deferred(AddOp), m_ConstInt(BitMask)),
+                                 m_ConstInt(BitNo)))) &&
+        BitMask == APInt::getOneBitSet(VTBits, BitNo)) {
+      unsigned SignBits = DAG.ComputeNumSignBits(AddOp);
+      unsigned NonSignBits = VTBits - DAG.ComputeNumSignBits(AddOp);
+      unsigned ExtendedBits = VTBits - ExtVTBits;
+      if (BitNo >= NonSignBits && ExtendedBits < SignBits)
+        return N0;
+    }
+  }
+
   // fold operands of sext_in_reg based on knowledge that the top bits are not
   // demanded.
   if (SimplifyDemandedBits(SDValue(N, 0)))
diff --git a/llvm/test/CodeGen/ARM/sdiv-pow2-arm-size.ll b/llvm/test/CodeGen/ARM/sdiv-pow2-arm-size.ll
index 53bc7f603bde1..e7490803924d3 100644
--- a/llvm/test/CodeGen/ARM/sdiv-pow2-arm-size.ll
+++ b/llvm/test/CodeGen/ARM/sdiv-pow2-arm-size.ll
@@ -30,7 +30,6 @@ define dso_local signext i16 @f0(i16 signext %F) local_unnamed_addr #0 {
 ; NODIV:       @ %bb.0: @ %entry
 ; NODIV-NEXT:    uxth r1, r0
 ; NODIV-NEXT:    add r0, r0, r1, lsr #15
-; NODIV-NEXT:    sxth r0, r0
 ; NODIV-NEXT:    asr r0, r0, #1
 ; NODIV-NEXT:    bx lr
 
diff --git a/llvm/test/CodeGen/ARM/sdiv-pow2-thumb-size.ll b/llvm/test/CodeGen/ARM/sdiv-pow2-thumb-size.ll
index cfd37bd3b86c0..819c14823a8b6 100644
--- a/llvm/test/CodeGen/ARM/sdiv-pow2-thumb-size.ll
+++ b/llvm/test/CodeGen/ARM/sdiv-pow2-thumb-size.ll
@@ -26,7 +26,6 @@ define dso_local signext i16 @f0(i16 signext %F) local_unnamed_addr #0 {
 ; V6M-NEXT:    uxth r1, r0
 ; V6M-NEXT:    lsrs r1, r1, #15
 ; V6M-NEXT:    adds r0, r0, r1
-; V6M-NEXT:    sxth r0, r0
 ; V6M-NEXT:    asrs r0, r0, #1
 ; V6M-NEXT:    bx lr
 
@@ -117,7 +116,6 @@ define dso_local signext i16 @f4(i16 signext %F) {
 ; T2:       @ %bb.0: @ %entry
 ; T2-NEXT:    uxth r1, r0
 ; T2-NEXT:    add.w r0, r0, r1, lsr #15
-; T2-NEXT:    sxth r0, r0
 ; T2-NEXT:    asrs r0, r0, #1
 ; T2-NEXT:    bx lr
 ;
@@ -126,7 +124,6 @@ define dso_local signext i16 @f4(i16 signext %F) {
 ; T1-NEXT:    uxth r1, r0
 ; T1-NEXT:    lsrs r1, r1, #15
 ; T1-NEXT:    adds r0, r0, r1
-; T1-NEXT:    sxth r0, r0
 ; T1-NEXT:    asrs r0, r0, #1
 ; T1-NEXT:    bx lr
 ;
@@ -135,7 +132,6 @@ define dso_local signext i16 @f4(i16 signext %F) {
 ; V6M-NEXT:    uxth r1, r0
 ; V6M-NEXT:    lsrs r1, r1, #15
 ; V6M-NEXT:    adds r0, r0, r1
-; V6M-NEXT:    sxth r0, r0
 ; V6M-NEXT:    asrs r0, r0, #1
 ; V6M-NEXT:    bx lr
 
diff --git a/llvm/test/CodeGen/RISCV/sdiv-pow2-cmov.ll b/llvm/test/CodeGen/RISCV/sdiv-pow2-cmov.ll
index f7dda82885678..7bbc9a55834f2 100644
--- a/llvm/test/CodeGen/RISCV/sdiv-pow2-cmov.ll
+++ b/llvm/test/CodeGen/RISCV/sdiv-pow2-cmov.ll
@@ -9,7 +9,7 @@ define signext i32 @sdiv2_32(i32 signext %0) {
 ; NOSFB:       # %bb.0:
 ; NOSFB-NEXT:    srliw a1, a0, 31
 ; NOSFB-NEXT:    add a0, a0, a1
-; NOSFB-NEXT:    sraiw a0, a0, 1
+; NOSFB-NEXT:    srai a0, a0, 1
 ; NOSFB-NEXT:    ret
 ;
 ; SFB-LABEL: sdiv2_32:
@@ -29,7 +29,7 @@ define signext i32 @sdivneg2_32(i32 signext %0) {
 ; NOSFB:       # %bb.0:
 ; NOSFB-NEXT:    srliw a1, a0, 31
 ; NOSFB-NEXT:    add a0, a0, a1
-; NOSFB-NEXT:    sraiw a0, a0, 1
+; NOSFB-NEXT:    srai a0, a0, 1
 ; NOSFB-NEXT:    neg a0, a0
 ; NOSFB-NEXT:    ret
 ;

>From ddb86e20225b641eda680b71f984d0c6f8bd78a7 Mon Sep 17 00:00:00 2001
From: Usman Nadeem <mnadeem at qti.qualcomm.com>
Date: Fri, 7 Aug 2026 21:38:48 -0700
Subject: [PATCH 2/2] Move code to getnumsignbits

Change-Id: I43d4d7194376d17edf7c1608cf391b249204bb8c
---
 llvm/lib/CodeGen/SelectionDAG/DAGCombiner.cpp | 19 ---------------
 .../lib/CodeGen/SelectionDAG/SelectionDAG.cpp | 23 +++++++++++++------
 2 files changed, 16 insertions(+), 26 deletions(-)

diff --git a/llvm/lib/CodeGen/SelectionDAG/DAGCombiner.cpp b/llvm/lib/CodeGen/SelectionDAG/DAGCombiner.cpp
index 6973bcdc9d259..f5620743d6ed1 100644
--- a/llvm/lib/CodeGen/SelectionDAG/DAGCombiner.cpp
+++ b/llvm/lib/CodeGen/SelectionDAG/DAGCombiner.cpp
@@ -17223,25 +17223,6 @@ SDValue DAGCombiner::visitSIGN_EXTEND_INREG(SDNode *N) {
   if (DAG.MaskedValueIsZero(N0, APInt::getOneBitSet(VTBits, ExtVTBits - 1)))
     return DAG.getZeroExtendInReg(N0, DL, ExtVT);
 
-  // fold (sext_in_reg add(x, sign_bit_of(x))) -> add(x, sign_bit_of(x))
-  // if we are not extending beyond the original extension type of x.
-  {
-    SDValue AddOp;
-    uint64_t BitNo;
-    APInt BitMask;
-    if (sd_match(N0,
-                 m_c_BinOp(ISD::ADD, m_Value(AddOp),
-                           m_Srl(m_And(m_Deferred(AddOp), m_ConstInt(BitMask)),
-                                 m_ConstInt(BitNo)))) &&
-        BitMask == APInt::getOneBitSet(VTBits, BitNo)) {
-      unsigned SignBits = DAG.ComputeNumSignBits(AddOp);
-      unsigned NonSignBits = VTBits - DAG.ComputeNumSignBits(AddOp);
-      unsigned ExtendedBits = VTBits - ExtVTBits;
-      if (BitNo >= NonSignBits && ExtendedBits < SignBits)
-        return N0;
-    }
-  }
-
   // fold operands of sext_in_reg based on knowledge that the top bits are not
   // demanded.
   if (SimplifyDemandedBits(SDValue(N, 0)))
diff --git a/llvm/lib/CodeGen/SelectionDAG/SelectionDAG.cpp b/llvm/lib/CodeGen/SelectionDAG/SelectionDAG.cpp
index db40d2d31e363..83403c1899349 100644
--- a/llvm/lib/CodeGen/SelectionDAG/SelectionDAG.cpp
+++ b/llvm/lib/CodeGen/SelectionDAG/SelectionDAG.cpp
@@ -5259,17 +5259,17 @@ unsigned SelectionDAG::ComputeNumSignBits(SDValue Op, const APInt &DemandedElts,
     }
     break;
   case ISD::ADD:
-  case ISD::ADDC:
+  case ISD::ADDC: {
+    SDValue Op0 = Op.getOperand(0);
+    SDValue Op1 = Op.getOperand(1);
     // TODO: Move Operand 1 check before Operand 0 check
-    Tmp = ComputeNumSignBits(Op.getOperand(0), DemandedElts, Depth + 1);
+    Tmp = ComputeNumSignBits(Op0, DemandedElts, Depth + 1);
     if (Tmp == 1) return 1; // Early out.
 
     // Special case decrementing a value (ADD X, -1):
-    if (ConstantSDNode *CRHS =
-            isConstOrConstSplat(Op.getOperand(1), DemandedElts))
+    if (ConstantSDNode *CRHS = isConstOrConstSplat(Op1, DemandedElts))
       if (CRHS->isAllOnes()) {
-        KnownBits Known =
-            computeKnownBits(Op.getOperand(0), DemandedElts, Depth + 1);
+        KnownBits Known = computeKnownBits(Op0, DemandedElts, Depth + 1);
 
         // If the input is known to be 0 or 1, the output is 0/-1, which is all
         // sign bits set.
@@ -5282,12 +5282,21 @@ unsigned SelectionDAG::ComputeNumSignBits(SDValue Op, const APInt &DemandedElts,
           return Tmp;
       }
 
-    Tmp2 = ComputeNumSignBits(Op.getOperand(1), DemandedElts, Depth + 1);
+    Tmp2 = ComputeNumSignBits(Op1, DemandedElts, Depth + 1);
     if (Tmp2 == 1) return 1; // Early out.
 
+    // Adding sign bit to a value. Adding zero to any value doesn't do anything.
+    // Adding 1 to a sext value can change the sign e.g. -1 + 1 = 0 but it
+    // doesn't decrease the number of sign bits.
+    SDValue AddOp;
+    if (sd_match(Op, m_Add(m_Value(AddOp), m_Srl(m_Deferred(AddOp),
+                                                 m_SpecificInt(VTBits - 1)))))
+      return (Op0 == AddOp) ? Tmp : Tmp2;
+
     // Add can have at most one carry bit.  Thus we know that the output
     // is, at worst, one more bit than the inputs.
     return std::min(Tmp, Tmp2) - 1;
+  }
   case ISD::SUB:
     Tmp2 = ComputeNumSignBits(Op.getOperand(1), DemandedElts, Depth + 1);
     if (Tmp2 == 1) return 1; // Early out.



More information about the llvm-commits mailing list