[llvm] [DAGCombiner] Fold extract of signbit + srl to srl. (PR #214913)
Usman Nadeem via llvm-commits
llvm-commits at lists.llvm.org
Fri Aug 7 19:15:19 PDT 2026
https://github.com/UsmanNadeem created https://github.com/llvm/llvm-project/pull/214913
Use `ComputeNumSignBits` info to check if we are extracting the sign bit. If so, we can just shift the MSB to the right.
>From ecff22c52d2a66362db036d2078f02ff3e9c14a7 Mon Sep 17 00:00:00 2001
From: Usman Nadeem <mnadeem at qti.qualcomm.com>
Date: Fri, 7 Aug 2026 18:36:15 -0700
Subject: [PATCH 1/3] [DAGCombiner] Fold extract of signbit + srl to srl.
Use ComputeNumSignBits info to check if we are extracting the sign bit. If so, we just shift the MSB to the right.
Change-Id: I07dea1cb9fca4bffdd1a68eb2d87ef3a743a8fa1
---
llvm/lib/CodeGen/SelectionDAG/DAGCombiner.cpp | 12 ++++++++++++
llvm/test/CodeGen/ARM/sdiv-pow2-arm-size.ll | 3 +--
llvm/test/CodeGen/ARM/sdiv-pow2-thumb-size.ll | 12 ++++--------
llvm/test/CodeGen/LoongArch/bittest.ll | 2 +-
llvm/test/CodeGen/RISCV/bittest.ll | 2 +-
llvm/test/CodeGen/RISCV/div-by-constant.ll | 8 ++++----
llvm/test/CodeGen/RISCV/rv64zbb-zbkb.ll | 6 +++---
llvm/test/CodeGen/RISCV/sdiv-pow2-cmov.ll | 8 ++++----
llvm/test/CodeGen/RISCV/selectcc-to-shiftand.ll | 2 +-
llvm/test/CodeGen/RISCV/srem-lkk.ll | 8 ++++----
10 files changed, 35 insertions(+), 28 deletions(-)
diff --git a/llvm/lib/CodeGen/SelectionDAG/DAGCombiner.cpp b/llvm/lib/CodeGen/SelectionDAG/DAGCombiner.cpp
index f5620743d6ed1..4fccb8fc9f129 100644
--- a/llvm/lib/CodeGen/SelectionDAG/DAGCombiner.cpp
+++ b/llvm/lib/CodeGen/SelectionDAG/DAGCombiner.cpp
@@ -11991,6 +11991,18 @@ SDValue DAGCombiner::visitSRL(SDNode *N) {
m_BitReverse(m_Value(Y))))))
return DAG.getNode(ISD::CLMULH, DL, VT, X, Y);
+ // Extracting a bit that happens to be the sign bit using `AND` and shifting
+ // it to zero position. We can just get rid of the `AND` and shift the highest
+ // bit to the right.
+ if (N1C && sd_match(N0, m_And(m_Value(X),
+ m_SpecificInt(APInt::getOneBitSet(
+ OpSizeInBits, N1C->getZExtValue()))))) {
+ unsigned SignBits = DAG.ComputeNumSignBits(X);
+ if (N1C->getZExtValue() >= OpSizeInBits - SignBits)
+ return DAG.getNode(ISD::SRL, DL, VT, X,
+ DAG.getConstant(OpSizeInBits - 1, DL, VT));
+ }
+
return SDValue();
}
diff --git a/llvm/test/CodeGen/ARM/sdiv-pow2-arm-size.ll b/llvm/test/CodeGen/ARM/sdiv-pow2-arm-size.ll
index 53bc7f603bde1..e80e023bf4a93 100644
--- a/llvm/test/CodeGen/ARM/sdiv-pow2-arm-size.ll
+++ b/llvm/test/CodeGen/ARM/sdiv-pow2-arm-size.ll
@@ -28,8 +28,7 @@ define dso_local signext i16 @f0(i16 signext %F) local_unnamed_addr #0 {
;
; NODIV-LABEL: f0:
; NODIV: @ %bb.0: @ %entry
-; NODIV-NEXT: uxth r1, r0
-; NODIV-NEXT: add r0, r0, r1, lsr #15
+; NODIV-NEXT: add r0, r0, r0, lsr #31
; 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..8c48b3393349f 100644
--- a/llvm/test/CodeGen/ARM/sdiv-pow2-thumb-size.ll
+++ b/llvm/test/CodeGen/ARM/sdiv-pow2-thumb-size.ll
@@ -23,8 +23,7 @@ define dso_local signext i16 @f0(i16 signext %F) local_unnamed_addr #0 {
;
; V6M-LABEL: f0:
; V6M: @ %bb.0: @ %entry
-; V6M-NEXT: uxth r1, r0
-; V6M-NEXT: lsrs r1, r1, #15
+; V6M-NEXT: lsrs r1, r0, #31
; V6M-NEXT: adds r0, r0, r1
; V6M-NEXT: sxth r0, r0
; V6M-NEXT: asrs r0, r0, #1
@@ -115,16 +114,14 @@ attributes #0 = { minsize norecurse nounwind optsize readnone }
define dso_local signext i16 @f4(i16 signext %F) {
; T2-LABEL: f4:
; T2: @ %bb.0: @ %entry
-; T2-NEXT: uxth r1, r0
-; T2-NEXT: add.w r0, r0, r1, lsr #15
+; T2-NEXT: add.w r0, r0, r0, lsr #31
; T2-NEXT: sxth r0, r0
; T2-NEXT: asrs r0, r0, #1
; T2-NEXT: bx lr
;
; T1-LABEL: f4:
; T1: @ %bb.0: @ %entry
-; T1-NEXT: uxth r1, r0
-; T1-NEXT: lsrs r1, r1, #15
+; T1-NEXT: lsrs r1, r0, #31
; T1-NEXT: adds r0, r0, r1
; T1-NEXT: sxth r0, r0
; T1-NEXT: asrs r0, r0, #1
@@ -132,8 +129,7 @@ define dso_local signext i16 @f4(i16 signext %F) {
;
; V6M-LABEL: f4:
; V6M: @ %bb.0: @ %entry
-; V6M-NEXT: uxth r1, r0
-; V6M-NEXT: lsrs r1, r1, #15
+; V6M-NEXT: lsrs r1, r0, #31
; V6M-NEXT: adds r0, r0, r1
; V6M-NEXT: sxth r0, r0
; V6M-NEXT: asrs r0, r0, #1
diff --git a/llvm/test/CodeGen/LoongArch/bittest.ll b/llvm/test/CodeGen/LoongArch/bittest.ll
index 9cf24dc5f65cc..fdecb6992bf08 100644
--- a/llvm/test/CodeGen/LoongArch/bittest.ll
+++ b/llvm/test/CodeGen/LoongArch/bittest.ll
@@ -69,7 +69,7 @@ define signext i32 @bittest_31_i32(i32 signext %a) nounwind {
; LA64-LABEL: bittest_31_i32:
; LA64: # %bb.0:
; LA64-NEXT: nor $a0, $a0, $zero
-; LA64-NEXT: bstrpick.d $a0, $a0, 31, 31
+; LA64-NEXT: srli.d $a0, $a0, 63
; LA64-NEXT: ret
%shr = lshr i32 %a, 31
%not = xor i32 %shr, -1
diff --git a/llvm/test/CodeGen/RISCV/bittest.ll b/llvm/test/CodeGen/RISCV/bittest.ll
index 1432d14bc936b..075bad653ca6a 100644
--- a/llvm/test/CodeGen/RISCV/bittest.ll
+++ b/llvm/test/CodeGen/RISCV/bittest.ll
@@ -78,7 +78,7 @@ define signext i32 @bittest_31_i32(i32 signext %a) nounwind {
; RV64-LABEL: bittest_31_i32:
; RV64: # %bb.0:
; RV64-NEXT: not a0, a0
-; RV64-NEXT: srliw a0, a0, 31
+; RV64-NEXT: srli a0, a0, 63
; RV64-NEXT: ret
%shr = lshr i32 %a, 31
%not = xor i32 %shr, -1
diff --git a/llvm/test/CodeGen/RISCV/div-by-constant.ll b/llvm/test/CodeGen/RISCV/div-by-constant.ll
index 0cbfa79562806..8e9e5ee33929d 100644
--- a/llvm/test/CodeGen/RISCV/div-by-constant.ll
+++ b/llvm/test/CodeGen/RISCV/div-by-constant.ll
@@ -390,8 +390,8 @@ define i32 @sdiv_constant_add_srai(i32 %a) nounwind {
; RV64-NEXT: addi a1, a1, 1171
; RV64-NEXT: mul a1, a2, a1
; RV64-NEXT: srli a1, a1, 32
-; RV64-NEXT: add a0, a1, a0
-; RV64-NEXT: srliw a1, a0, 31
+; RV64-NEXT: addw a0, a1, a0
+; RV64-NEXT: srli a1, a0, 63
; RV64-NEXT: sraiw a0, a0, 2
; RV64-NEXT: add a0, a0, a1
; RV64-NEXT: ret
@@ -419,8 +419,8 @@ define i32 @sdiv_constant_sub_srai(i32 %a) nounwind {
; RV64-NEXT: addi a1, a1, -1171
; RV64-NEXT: mul a1, a2, a1
; RV64-NEXT: srli a1, a1, 32
-; RV64-NEXT: sub a1, a1, a0
-; RV64-NEXT: srliw a0, a1, 31
+; RV64-NEXT: subw a1, a1, a0
+; RV64-NEXT: srli a0, a1, 63
; RV64-NEXT: sraiw a1, a1, 2
; RV64-NEXT: add a0, a1, a0
; RV64-NEXT: ret
diff --git a/llvm/test/CodeGen/RISCV/rv64zbb-zbkb.ll b/llvm/test/CodeGen/RISCV/rv64zbb-zbkb.ll
index 7210deb504483..75a1299d32f00 100644
--- a/llvm/test/CodeGen/RISCV/rv64zbb-zbkb.ll
+++ b/llvm/test/CodeGen/RISCV/rv64zbb-zbkb.ll
@@ -407,7 +407,7 @@ define signext i32 @rori_i32_fshr(i32 signext %a) nounwind {
; RV64I-LABEL: rori_i32_fshr:
; RV64I: # %bb.0:
; RV64I-NEXT: slliw a1, a0, 1
-; RV64I-NEXT: srliw a0, a0, 31
+; RV64I-NEXT: srli a0, a0, 63
; RV64I-NEXT: or a0, a0, a1
; RV64I-NEXT: ret
;
@@ -423,8 +423,8 @@ define signext i32 @rori_i32_fshr(i32 signext %a) nounwind {
define void @rori_i32_fshr_nosext(i32 signext %a, ptr %x) nounwind {
; RV64I-LABEL: rori_i32_fshr_nosext:
; RV64I: # %bb.0:
-; RV64I-NEXT: slli a2, a0, 1
-; RV64I-NEXT: srliw a0, a0, 31
+; RV64I-NEXT: srli a2, a0, 63
+; RV64I-NEXT: slli a0, a0, 1
; RV64I-NEXT: or a0, a0, a2
; RV64I-NEXT: sw a0, 0(a1)
; RV64I-NEXT: ret
diff --git a/llvm/test/CodeGen/RISCV/sdiv-pow2-cmov.ll b/llvm/test/CodeGen/RISCV/sdiv-pow2-cmov.ll
index f7dda82885678..18aa8403cacfc 100644
--- a/llvm/test/CodeGen/RISCV/sdiv-pow2-cmov.ll
+++ b/llvm/test/CodeGen/RISCV/sdiv-pow2-cmov.ll
@@ -7,7 +7,7 @@
define signext i32 @sdiv2_32(i32 signext %0) {
; NOSFB-LABEL: sdiv2_32:
; NOSFB: # %bb.0:
-; NOSFB-NEXT: srliw a1, a0, 31
+; NOSFB-NEXT: srli a1, a0, 63
; NOSFB-NEXT: add a0, a0, a1
; NOSFB-NEXT: sraiw a0, a0, 1
; NOSFB-NEXT: ret
@@ -27,7 +27,7 @@ define signext i32 @sdiv2_32(i32 signext %0) {
define signext i32 @sdivneg2_32(i32 signext %0) {
; NOSFB-LABEL: sdivneg2_32:
; NOSFB: # %bb.0:
-; NOSFB-NEXT: srliw a1, a0, 31
+; NOSFB-NEXT: srli a1, a0, 63
; NOSFB-NEXT: add a0, a0, a1
; NOSFB-NEXT: sraiw a0, a0, 1
; NOSFB-NEXT: neg a0, a0
@@ -91,7 +91,7 @@ define i64 @sdivneg2_64(i64 %0) {
define signext i32 @srem2_32(i32 signext %0) {
; NOSFB-LABEL: srem2_32:
; NOSFB: # %bb.0:
-; NOSFB-NEXT: srliw a1, a0, 31
+; NOSFB-NEXT: srli a1, a0, 63
; NOSFB-NEXT: add a1, a1, a0
; NOSFB-NEXT: andi a1, a1, -2
; NOSFB-NEXT: subw a0, a0, a1
@@ -114,7 +114,7 @@ define signext i32 @srem2_32(i32 signext %0) {
define signext i32 @sremneg2_32(i32 signext %0) {
; NOSFB-LABEL: sremneg2_32:
; NOSFB: # %bb.0:
-; NOSFB-NEXT: srliw a1, a0, 31
+; NOSFB-NEXT: srli a1, a0, 63
; NOSFB-NEXT: add a1, a1, a0
; NOSFB-NEXT: andi a1, a1, -2
; NOSFB-NEXT: subw a0, a0, a1
diff --git a/llvm/test/CodeGen/RISCV/selectcc-to-shiftand.ll b/llvm/test/CodeGen/RISCV/selectcc-to-shiftand.ll
index fa1807cd7d911..6c509703f5baf 100644
--- a/llvm/test/CodeGen/RISCV/selectcc-to-shiftand.ll
+++ b/llvm/test/CodeGen/RISCV/selectcc-to-shiftand.ll
@@ -37,7 +37,7 @@ define i32 @neg_sel_special_constant(i32 signext %a) {
;
; RV64-LABEL: neg_sel_special_constant:
; RV64: # %bb.0:
-; RV64-NEXT: srliw a0, a0, 31
+; RV64-NEXT: srli a0, a0, 63
; RV64-NEXT: slli a0, a0, 9
; RV64-NEXT: ret
%tmp.1 = icmp slt i32 %a, 0
diff --git a/llvm/test/CodeGen/RISCV/srem-lkk.ll b/llvm/test/CodeGen/RISCV/srem-lkk.ll
index b6e7684695aef..024da55494559 100644
--- a/llvm/test/CodeGen/RISCV/srem-lkk.ll
+++ b/llvm/test/CodeGen/RISCV/srem-lkk.ll
@@ -45,8 +45,8 @@ define i32 @fold_srem_positive_odd(i32 %x) nounwind {
; RV64IM-NEXT: addi a1, a1, 389
; RV64IM-NEXT: mul a1, a2, a1
; RV64IM-NEXT: srli a1, a1, 32
-; RV64IM-NEXT: add a1, a1, a0
-; RV64IM-NEXT: srliw a2, a1, 31
+; RV64IM-NEXT: addw a1, a1, a0
+; RV64IM-NEXT: srli a2, a1, 63
; RV64IM-NEXT: sraiw a1, a1, 6
; RV64IM-NEXT: add a1, a1, a2
; RV64IM-NEXT: li a2, 95
@@ -270,8 +270,8 @@ define i32 @combine_srem_sdiv(i32 %x) nounwind {
; RV64IM-NEXT: addi a1, a1, 389
; RV64IM-NEXT: mul a1, a2, a1
; RV64IM-NEXT: srli a1, a1, 32
-; RV64IM-NEXT: add a1, a1, a0
-; RV64IM-NEXT: srliw a2, a1, 31
+; RV64IM-NEXT: addw a1, a1, a0
+; RV64IM-NEXT: srli a2, a1, 63
; RV64IM-NEXT: sraiw a1, a1, 6
; RV64IM-NEXT: add a1, a1, a2
; RV64IM-NEXT: li a2, 95
>From 8d5199d4d3478298592f8d9b4568ab2d2141b015 Mon Sep 17 00:00:00 2001
From: Usman Nadeem <mnadeem at qti.qualcomm.com>
Date: Fri, 7 Aug 2026 19:13:27 -0700
Subject: [PATCH 2/3] add test
Change-Id: Ib4180f7344296d3642f9cd3b928dd8604cb7a94f
---
llvm/test/CodeGen/ARM/signbit-to-lsb.ll | 105 ++++++++++++++++++++++++
1 file changed, 105 insertions(+)
create mode 100644 llvm/test/CodeGen/ARM/signbit-to-lsb.ll
diff --git a/llvm/test/CodeGen/ARM/signbit-to-lsb.ll b/llvm/test/CodeGen/ARM/signbit-to-lsb.ll
new file mode 100644
index 0000000000000..ccd4f3596886e
--- /dev/null
+++ b/llvm/test/CodeGen/ARM/signbit-to-lsb.ll
@@ -0,0 +1,105 @@
+; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py UTC_ARGS: --version 6
+; RUN: llc -mtriple=armv7a %s -o - | FileCheck %s --check-prefix=ARM
+; RUN: llc -mtriple=thumbv6m %s -o - | FileCheck %s --check-prefix=THUMB
+
+
+define i32 @test_sext_i16_to_i32(i16 %a) {
+; ARM-LABEL: test_sext_i16_to_i32:
+; ARM: @ %bb.0: @ %entry
+; ARM-NEXT: sxth r0, r0
+; ARM-NEXT: ubfx r0, r0, #20, #1
+; ARM-NEXT: bx lr
+;
+; THUMB-LABEL: test_sext_i16_to_i32:
+; THUMB: @ %bb.0: @ %entry
+; THUMB-NEXT: movs r1, #1
+; THUMB-NEXT: lsls r1, r1, #20
+; THUMB-NEXT: sxth r0, r0
+; THUMB-NEXT: ands r0, r1
+; THUMB-NEXT: lsrs r0, r0, #20
+; THUMB-NEXT: bx lr
+entry:
+ %sext = sext i16 %a to i32
+ %and = and i32 %sext, 1048576 ; 0000 0000 0001 0000 0000 0000 0000 0000
+ %shr = lshr i32 %and, 20
+ ret i32 %shr
+}
+
+; Mismatch in shift value.
+define i32 @neg_test_sext_i16_to_i32(i16 %a) {
+; ARM-LABEL: neg_test_sext_i16_to_i32:
+; ARM: @ %bb.0: @ %entry
+; ARM-NEXT: sxth r0, r0
+; ARM-NEXT: and r0, r0, #1048576
+; ARM-NEXT: lsr r0, r0, #19
+; ARM-NEXT: bx lr
+;
+; THUMB-LABEL: neg_test_sext_i16_to_i32:
+; THUMB: @ %bb.0: @ %entry
+; THUMB-NEXT: movs r1, #1
+; THUMB-NEXT: lsls r1, r1, #20
+; THUMB-NEXT: sxth r0, r0
+; THUMB-NEXT: ands r0, r1
+; THUMB-NEXT: lsrs r0, r0, #19
+; THUMB-NEXT: bx lr
+entry:
+ %sext = sext i16 %a to i32
+ %and = and i32 %sext, 1048576 ; 0000 0000 0001 0000 0000 0000 0000 0000
+ %shr = lshr i32 %and, 19
+ ret i32 %shr
+}
+
+; AND of non-sign bit.
+define i32 @neg1_test_sext_i16_to_i32(i16 %a) {
+; ARM-LABEL: neg1_test_sext_i16_to_i32:
+; ARM: @ %bb.0: @ %entry
+; ARM-NEXT: ubfx r0, r0, #4, #1
+; ARM-NEXT: bx lr
+;
+; THUMB-LABEL: neg1_test_sext_i16_to_i32:
+; THUMB: @ %bb.0: @ %entry
+; THUMB-NEXT: movs r1, #16
+; THUMB-NEXT: ands r1, r0
+; THUMB-NEXT: lsrs r0, r1, #4
+; THUMB-NEXT: bx lr
+entry:
+ %sext = sext i16 %a to i32
+ %and = and i32 %sext, 16 ; 00001 0000
+ %shr = lshr i32 %and, 4
+ ret i32 %shr
+}
+
+define i32 @test_i32(i32 %a) {
+; ARM-LABEL: test_i32:
+; ARM: @ %bb.0: @ %entry
+; ARM-NEXT: lsr r0, r0, #31
+; ARM-NEXT: bx lr
+;
+; THUMB-LABEL: test_i32:
+; THUMB: @ %bb.0: @ %entry
+; THUMB-NEXT: lsrs r0, r0, #31
+; THUMB-NEXT: bx lr
+entry:
+ %and = and i32 %a, 2147483648
+ %shr = lshr i32 %a, 31
+ ret i32 %shr
+}
+
+define i32 @neg_test_i32(i32 %a) {
+; ARM-LABEL: neg_test_i32:
+; ARM: @ %bb.0: @ %entry
+; ARM-NEXT: ubfx r0, r0, #20, #1
+; ARM-NEXT: bx lr
+;
+; THUMB-LABEL: neg_test_i32:
+; THUMB: @ %bb.0: @ %entry
+; THUMB-NEXT: movs r1, #1
+; THUMB-NEXT: lsls r1, r1, #20
+; THUMB-NEXT: ands r1, r0
+; THUMB-NEXT: lsrs r0, r1, #20
+; THUMB-NEXT: bx lr
+entry:
+ %and = and i32 %a, 1048576 ; 0000 0000 0001 0000 0000 0000 0000 0000
+ %shr = lshr i32 %and, 20
+ ret i32 %shr
+}
>From a0a192032329b08e8bc6337d0790a1632f5c1691 Mon Sep 17 00:00:00 2001
From: Usman Nadeem <mnadeem at qti.qualcomm.com>
Date: Fri, 7 Aug 2026 19:14:07 -0700
Subject: [PATCH 3/3] update test
Change-Id: I563b2af20cfba3cdb853bdf9b1061fdfba66128b
---
llvm/test/CodeGen/ARM/signbit-to-lsb.ll | 10 +++-------
1 file changed, 3 insertions(+), 7 deletions(-)
diff --git a/llvm/test/CodeGen/ARM/signbit-to-lsb.ll b/llvm/test/CodeGen/ARM/signbit-to-lsb.ll
index ccd4f3596886e..b0ebdb7386182 100644
--- a/llvm/test/CodeGen/ARM/signbit-to-lsb.ll
+++ b/llvm/test/CodeGen/ARM/signbit-to-lsb.ll
@@ -6,17 +6,13 @@
define i32 @test_sext_i16_to_i32(i16 %a) {
; ARM-LABEL: test_sext_i16_to_i32:
; ARM: @ %bb.0: @ %entry
-; ARM-NEXT: sxth r0, r0
-; ARM-NEXT: ubfx r0, r0, #20, #1
+; ARM-NEXT: ubfx r0, r0, #15, #1
; ARM-NEXT: bx lr
;
; THUMB-LABEL: test_sext_i16_to_i32:
; THUMB: @ %bb.0: @ %entry
-; THUMB-NEXT: movs r1, #1
-; THUMB-NEXT: lsls r1, r1, #20
-; THUMB-NEXT: sxth r0, r0
-; THUMB-NEXT: ands r0, r1
-; THUMB-NEXT: lsrs r0, r0, #20
+; THUMB-NEXT: lsls r0, r0, #16
+; THUMB-NEXT: lsrs r0, r0, #31
; THUMB-NEXT: bx lr
entry:
%sext = sext i16 %a to i32
More information about the llvm-commits
mailing list