[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