[llvm] [DAGCombiner] Fold extract of signbit + srl to srl. (PR #214913)
via llvm-commits
llvm-commits at lists.llvm.org
Fri Aug 7 19:15:59 PDT 2026
llvmorg-github-actions[bot] wrote:
<!--LLVM PR SUMMARY COMMENT-->
@llvm/pr-subscribers-llvm-selectiondag
Author: Usman Nadeem (UsmanNadeem)
<details>
<summary>Changes</summary>
Use `ComputeNumSignBits` info to check if we are extracting the sign bit. If so, we can just shift the MSB to the right.
---
Full diff: https://github.com/llvm/llvm-project/pull/214913.diff
11 Files Affected:
- (modified) llvm/lib/CodeGen/SelectionDAG/DAGCombiner.cpp (+12)
- (modified) llvm/test/CodeGen/ARM/sdiv-pow2-arm-size.ll (+1-2)
- (modified) llvm/test/CodeGen/ARM/sdiv-pow2-thumb-size.ll (+4-8)
- (added) llvm/test/CodeGen/ARM/signbit-to-lsb.ll (+101)
- (modified) llvm/test/CodeGen/LoongArch/bittest.ll (+1-1)
- (modified) llvm/test/CodeGen/RISCV/bittest.ll (+1-1)
- (modified) llvm/test/CodeGen/RISCV/div-by-constant.ll (+4-4)
- (modified) llvm/test/CodeGen/RISCV/rv64zbb-zbkb.ll (+3-3)
- (modified) llvm/test/CodeGen/RISCV/sdiv-pow2-cmov.ll (+4-4)
- (modified) llvm/test/CodeGen/RISCV/selectcc-to-shiftand.ll (+1-1)
- (modified) llvm/test/CodeGen/RISCV/srem-lkk.ll (+4-4)
``````````diff
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/ARM/signbit-to-lsb.ll b/llvm/test/CodeGen/ARM/signbit-to-lsb.ll
new file mode 100644
index 0000000000000..b0ebdb7386182
--- /dev/null
+++ b/llvm/test/CodeGen/ARM/signbit-to-lsb.ll
@@ -0,0 +1,101 @@
+; 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: ubfx r0, r0, #15, #1
+; ARM-NEXT: bx lr
+;
+; THUMB-LABEL: test_sext_i16_to_i32:
+; THUMB: @ %bb.0: @ %entry
+; THUMB-NEXT: lsls r0, r0, #16
+; THUMB-NEXT: lsrs r0, r0, #31
+; 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
+}
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
``````````
</details>
https://github.com/llvm/llvm-project/pull/214913
More information about the llvm-commits
mailing list