[llvm-branch-commits] [llvm] [LoongArch] Compute known bits and sign bits for BSTRINS/BSTRPICK (PR #233738)
via llvm-branch-commits
llvm-branch-commits at lists.llvm.org
Tue Oct 20 01:18:01 PDT 2026
llvmorg-github-actions[bot] wrote:
<!--LLVM PR SUMMARY COMMENT-->
@llvm/pr-subscribers-backend-loongarch
Author: hev (heiher)
<details>
<summary>Changes</summary>
BSTRINS and BSTRPICK are formed early by DAG combines, so the generic known-bits and sign-bits analyses see them as opaque target nodes. When such a value is live out of a block, its LiveOutInfo is lost and PHIs merging it can no longer prove that the value is already sign- or zero-extended, leaving redundant addi.w/bstrpick.d behind.
This is common in Rust code decoding UTF-8, e.g. `str::chars().rev()`, where the multi-byte path assembles the code point with bstrins.d and is merged with the ASCII byte loaded by ld.b before an i32 compare.
rustc-perf svg-parse-1 on LA664: instructions -2.4%, cycles -1.7%.
---
Full diff: https://github.com/llvm/llvm-project/pull/233738.diff
3 Files Affected:
- (modified) llvm/lib/Target/LoongArch/LoongArchISelLowering.cpp (+41)
- (modified) llvm/lib/Target/LoongArch/LoongArchISelLowering.h (+4)
- (modified) llvm/test/CodeGen/LoongArch/bstrins-bstrpick-known-bits.ll (+1-5)
``````````diff
diff --git a/llvm/lib/Target/LoongArch/LoongArchISelLowering.cpp b/llvm/lib/Target/LoongArch/LoongArchISelLowering.cpp
index 1d01e76a5ebd2..687212daa08fc 100644
--- a/llvm/lib/Target/LoongArch/LoongArchISelLowering.cpp
+++ b/llvm/lib/Target/LoongArch/LoongArchISelLowering.cpp
@@ -11940,7 +11940,48 @@ void LoongArchTargetLowering::computeKnownBitsForTargetNode(
Known.Zero.setBitsFrom(VTBits);
break;
}
+ case LoongArchISD::BSTRINS: {
+ // BSTRINS X, Y, msb, lsb: replace X[msb:lsb] with Y[msb-lsb:0].
+ unsigned Msb = Op.getConstantOperandVal(2);
+ unsigned Lsb = Op.getConstantOperandVal(3);
+ Known = DAG.computeKnownBits(Op.getOperand(0), Depth + 1);
+ KnownBits Known2 = DAG.computeKnownBits(Op.getOperand(1), Depth + 1);
+ Known.insertBits(Known2.trunc(Msb - Lsb + 1), Lsb);
+ break;
+ }
+ case LoongArchISD::BSTRPICK: {
+ // BSTRPICK X, msb, lsb: zero-extend X[msb:lsb].
+ unsigned BitWidth = Known.getBitWidth();
+ unsigned Msb = Op.getConstantOperandVal(1);
+ unsigned Lsb = Op.getConstantOperandVal(2);
+ Known = DAG.computeKnownBits(Op.getOperand(0), Depth + 1);
+ Known = Known.extractBits(Msb - Lsb + 1, Lsb).zext(BitWidth);
+ break;
+ }
+ }
+}
+
+unsigned LoongArchTargetLowering::ComputeNumSignBitsForTargetNode(
+ SDValue Op, const APInt &DemandedElts, const SelectionDAG &DAG,
+ unsigned Depth) const {
+ switch (Op.getOpcode()) {
+ default:
+ break;
+ case LoongArchISD::BSTRINS: {
+ unsigned BitWidth = Op.getScalarValueSizeInBits();
+ unsigned Msb = Op.getConstantOperandVal(2);
+ unsigned Lsb = Op.getConstantOperandVal(3);
+ // The bits above msb come from X.
+ if (Msb != BitWidth - 1) {
+ unsigned Tmp = DAG.ComputeNumSignBits(Op.getOperand(0), Depth + 1);
+ return std::min(Tmp, BitWidth - 1 - Msb);
+ }
+ // The high bits come from Y shifted left by lsb.
+ unsigned Tmp = DAG.ComputeNumSignBits(Op.getOperand(1), Depth + 1);
+ return Tmp > Lsb ? Tmp - Lsb : 1;
+ }
}
+ return 1;
}
bool LoongArchTargetLowering::SimplifyDemandedBitsForTargetNode(
diff --git a/llvm/lib/Target/LoongArch/LoongArchISelLowering.h b/llvm/lib/Target/LoongArch/LoongArchISelLowering.h
index 7c3ae7d6aac14..926fb8296507e 100644
--- a/llvm/lib/Target/LoongArch/LoongArchISelLowering.h
+++ b/llvm/lib/Target/LoongArch/LoongArchISelLowering.h
@@ -164,6 +164,10 @@ class LoongArchTargetLowering : public TargetLowering {
const APInt &DemandedElts,
const SelectionDAG &DAG,
unsigned Depth) const override;
+ unsigned ComputeNumSignBitsForTargetNode(SDValue Op,
+ const APInt &DemandedElts,
+ const SelectionDAG &DAG,
+ unsigned Depth) const override;
bool SimplifyDemandedBitsForTargetNode(SDValue Op, const APInt &DemandedBits,
const APInt &DemandedElts,
KnownBits &Known,
diff --git a/llvm/test/CodeGen/LoongArch/bstrins-bstrpick-known-bits.ll b/llvm/test/CodeGen/LoongArch/bstrins-bstrpick-known-bits.ll
index 6800b48e272f0..bdca1f01eeb21 100644
--- a/llvm/test/CodeGen/LoongArch/bstrins-bstrpick-known-bits.ll
+++ b/llvm/test/CodeGen/LoongArch/bstrins-bstrpick-known-bits.ll
@@ -19,7 +19,6 @@ define i32 @utf8_rev_col(ptr %begin, ptr %end) nounwind {
; CHECK-NEXT: # %bb.2: # %one
; CHECK-NEXT: # in Loop: Header=BB0_1 Depth=1
; CHECK-NEXT: addi.d $a1, $a1, -1
-; CHECK-NEXT: addi.w $a4, $a4, 0
; CHECK-NEXT: bne $a4, $a3, .LBB0_4
; CHECK-NEXT: b .LBB0_5
; CHECK-NEXT: .p2align 4, , 16
@@ -29,7 +28,6 @@ define i32 @utf8_rev_col(ptr %begin, ptr %end) nounwind {
; CHECK-NEXT: addi.d $a1, $a1, -2
; CHECK-NEXT: andi $a5, $a5, 31
; CHECK-NEXT: bstrins.d $a4, $a5, 63, 6
-; CHECK-NEXT: addi.w $a4, $a4, 0
; CHECK-NEXT: beq $a4, $a3, .LBB0_5
; CHECK-NEXT: .LBB0_4: # %latch
; CHECK-NEXT: # in Loop: Header=BB0_1 Depth=1
@@ -90,8 +88,7 @@ define i32 @bstrins_low_sext(i1 %c, i32 signext %x, i64 %y, i32 signext %z) noun
; CHECK-NEXT: bstrins.d $a1, $a0, 7, 0
; CHECK-NEXT: move $a3, $a1
; CHECK-NEXT: .LBB1_2: # %b
-; CHECK-NEXT: addi.w $a0, $a3, 0
-; CHECK-NEXT: addi.d $a0, $a0, -10
+; CHECK-NEXT: addi.d $a0, $a3, -10
; CHECK-NEXT: sltui $a0, $a0, 1
; CHECK-NEXT: ret
entry:
@@ -122,7 +119,6 @@ define i64 @bstrpick_zext(i1 %c, i64 %x, i64 %y) nounwind {
; CHECK-NEXT: # %bb.1: # %a
; CHECK-NEXT: bstrpick.d $a0, $a1, 23, 8
; CHECK-NEXT: .LBB2_2: # %b
-; CHECK-NEXT: bstrpick.d $a0, $a0, 31, 0
; CHECK-NEXT: ret
entry:
br i1 %c, label %a, label %b
``````````
</details>
https://github.com/llvm/llvm-project/pull/233738
More information about the llvm-branch-commits
mailing list