[llvm] [DAGCombiner] Fold extract of signbit + srl to srl. (PR #214913)

via llvm-commits llvm-commits at lists.llvm.org
Fri Aug 7 19:16:00 PDT 2026


llvmorg-github-actions[bot] wrote:


<!--LLVM PR SUMMARY COMMENT-->

@llvm/pr-subscribers-backend-arm

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