[llvm] [LoongArch] Perform SELECT_CC combine (PR #155994)
via llvm-commits
llvm-commits at lists.llvm.org
Fri Aug 29 02:14:25 PDT 2025
llvmbot wrote:
<!--LLVM PR SUMMARY COMMENT-->
@llvm/pr-subscribers-backend-loongarch
Author: hev (heiher)
<details>
<summary>Changes</summary>
Fold `((srl (and X, 1<<C), C), 0, eq/ne)` -> `((shl X, GRLen-1-C), 0, ge/lt)`
---
Full diff: https://github.com/llvm/llvm-project/pull/155994.diff
3 Files Affected:
- (modified) llvm/lib/Target/LoongArch/LoongArchISelLowering.cpp (+77-1)
- (modified) llvm/test/CodeGen/LoongArch/bittest.ll (+6-10)
- (modified) llvm/test/CodeGen/LoongArch/select-const.ll (+3-6)
``````````diff
diff --git a/llvm/lib/Target/LoongArch/LoongArchISelLowering.cpp b/llvm/lib/Target/LoongArch/LoongArchISelLowering.cpp
index 9854c731cd555..9b047971756ac 100644
--- a/llvm/lib/Target/LoongArch/LoongArchISelLowering.cpp
+++ b/llvm/lib/Target/LoongArch/LoongArchISelLowering.cpp
@@ -5256,7 +5256,7 @@ static SDValue performBITREV_WCombine(SDNode *N, SelectionDAG &DAG,
Src.getOperand(0));
}
-// Perform combines for BR_CC conditions.
+// Perform common combines for BR_CC and SELECT_CC conditions.
static bool combine_CC(SDValue &LHS, SDValue &RHS, SDValue &CC, const SDLoc &DL,
SelectionDAG &DAG, const LoongArchSubtarget &Subtarget) {
ISD::CondCode CCVal = cast<CondCodeSDNode>(CC)->get();
@@ -5293,6 +5293,29 @@ static bool combine_CC(SDValue &LHS, SDValue &RHS, SDValue &CC, const SDLoc &DL,
return true;
}
+ // Fold ((srl (and X, 1<<C), C), 0, eq/ne) -> ((shl X, GRLen-1-C), 0, ge/lt)
+ if (isNullConstant(RHS) && LHS.getOpcode() == ISD::SRL && LHS.hasOneUse() &&
+ LHS.getOperand(1).getOpcode() == ISD::Constant) {
+ SDValue LHS0 = LHS.getOperand(0);
+ if (LHS0.getOpcode() == ISD::AND &&
+ LHS0.getOperand(1).getOpcode() == ISD::Constant) {
+ uint64_t Mask = LHS0.getConstantOperandVal(1);
+ uint64_t ShAmt = LHS.getConstantOperandVal(1);
+ if (isPowerOf2_64(Mask) && Log2_64(Mask) == ShAmt) {
+ CCVal = CCVal == ISD::SETEQ ? ISD::SETGE : ISD::SETLT;
+ CC = DAG.getCondCode(CCVal);
+
+ ShAmt = LHS.getValueSizeInBits() - 1 - ShAmt;
+ LHS = LHS0.getOperand(0);
+ if (ShAmt != 0)
+ LHS =
+ DAG.getNode(ISD::SHL, DL, LHS.getValueType(), LHS0.getOperand(0),
+ DAG.getConstant(ShAmt, DL, LHS.getValueType()));
+ return true;
+ }
+ }
+ }
+
// (X, 1, setne) -> (X, 0, seteq) if we can prove X is 0/1.
// This can occur when legalizing some floating point comparisons.
APInt Mask = APInt::getBitsSetFrom(LHS.getValueSizeInBits(), 1);
@@ -5321,6 +5344,57 @@ static SDValue performBR_CCCombine(SDNode *N, SelectionDAG &DAG,
return SDValue();
}
+static SDValue performSELECT_CCCombine(SDNode *N, SelectionDAG &DAG,
+ TargetLowering::DAGCombinerInfo &DCI,
+ const LoongArchSubtarget &Subtarget) {
+ // Transform
+ SDValue LHS = N->getOperand(0);
+ SDValue RHS = N->getOperand(1);
+ SDValue CC = N->getOperand(2);
+ ISD::CondCode CCVal = cast<CondCodeSDNode>(CC)->get();
+ SDValue TrueV = N->getOperand(3);
+ SDValue FalseV = N->getOperand(4);
+ SDLoc DL(N);
+ EVT VT = N->getValueType(0);
+
+ // If the True and False values are the same, we don't need a select_cc.
+ if (TrueV == FalseV)
+ return TrueV;
+
+ // (select (x < 0), y, z) -> x >> (GRLEN - 1) & (y - z) + z
+ // (select (x >= 0), y, z) -> x >> (GRLEN - 1) & (z - y) + y
+ if (isa<ConstantSDNode>(TrueV) && isa<ConstantSDNode>(FalseV) &&
+ isNullConstant(RHS) &&
+ (CCVal == ISD::CondCode::SETLT || CCVal == ISD::CondCode::SETGE)) {
+ if (CCVal == ISD::CondCode::SETGE)
+ std::swap(TrueV, FalseV);
+
+ int64_t TrueSImm = cast<ConstantSDNode>(TrueV)->getSExtValue();
+ int64_t FalseSImm = cast<ConstantSDNode>(FalseV)->getSExtValue();
+ // Only handle simm12, if it is not in this range, it can be considered as
+ // register.
+ if (isInt<12>(TrueSImm) && isInt<12>(FalseSImm) &&
+ isInt<12>(TrueSImm - FalseSImm)) {
+ SDValue SRA =
+ DAG.getNode(ISD::SRA, DL, VT, LHS,
+ DAG.getConstant(Subtarget.getGRLen() - 1, DL, VT));
+ SDValue AND =
+ DAG.getNode(ISD::AND, DL, VT, SRA,
+ DAG.getSignedConstant(TrueSImm - FalseSImm, DL, VT));
+ return DAG.getNode(ISD::ADD, DL, VT, AND, FalseV);
+ }
+
+ if (CCVal == ISD::CondCode::SETGE)
+ std::swap(TrueV, FalseV);
+ }
+
+ if (combine_CC(LHS, RHS, CC, DL, DAG, Subtarget))
+ return DAG.getNode(LoongArchISD::SELECT_CC, DL, N->getValueType(0),
+ {LHS, RHS, CC, TrueV, FalseV});
+
+ return SDValue();
+}
+
template <unsigned N>
static SDValue legalizeIntrinsicImmArg(SDNode *Node, unsigned ImmOp,
SelectionDAG &DAG,
@@ -6015,6 +6089,8 @@ SDValue LoongArchTargetLowering::PerformDAGCombine(SDNode *N,
return performBITREV_WCombine(N, DAG, DCI, Subtarget);
case LoongArchISD::BR_CC:
return performBR_CCCombine(N, DAG, DCI, Subtarget);
+ case LoongArchISD::SELECT_CC:
+ return performSELECT_CCCombine(N, DAG, DCI, Subtarget);
case ISD::INTRINSIC_WO_CHAIN:
return performINTRINSIC_WO_CHAINCombine(N, DAG, DCI, Subtarget);
case LoongArchISD::MOVGR2FR_W_LA64:
diff --git a/llvm/test/CodeGen/LoongArch/bittest.ll b/llvm/test/CodeGen/LoongArch/bittest.ll
index 47671be5eeee1..9cf24dc5f65cc 100644
--- a/llvm/test/CodeGen/LoongArch/bittest.ll
+++ b/llvm/test/CodeGen/LoongArch/bittest.ll
@@ -358,10 +358,9 @@ define signext i32 @bit_10_z_select_i32(i32 signext %a, i32 signext %b, i32 sign
define signext i32 @bit_10_nz_select_i32(i32 signext %a, i32 signext %b, i32 signext %c) {
; LA32-LABEL: bit_10_nz_select_i32:
; LA32: # %bb.0:
-; LA32-NEXT: andi $a0, $a0, 1024
-; LA32-NEXT: srli.w $a3, $a0, 10
+; LA32-NEXT: slli.w $a3, $a0, 21
; LA32-NEXT: move $a0, $a1
-; LA32-NEXT: bne $a3, $zero, .LBB16_2
+; LA32-NEXT: bltz $a3, .LBB16_2
; LA32-NEXT: # %bb.1:
; LA32-NEXT: move $a0, $a2
; LA32-NEXT: .LBB16_2:
@@ -408,10 +407,9 @@ define signext i32 @bit_11_z_select_i32(i32 signext %a, i32 signext %b, i32 sign
define signext i32 @bit_11_nz_select_i32(i32 signext %a, i32 signext %b, i32 signext %c) {
; LA32-LABEL: bit_11_nz_select_i32:
; LA32: # %bb.0:
-; LA32-NEXT: andi $a0, $a0, 2048
-; LA32-NEXT: srli.w $a3, $a0, 11
+; LA32-NEXT: slli.w $a3, $a0, 20
; LA32-NEXT: move $a0, $a1
-; LA32-NEXT: bne $a3, $zero, .LBB18_2
+; LA32-NEXT: bltz $a3, .LBB18_2
; LA32-NEXT: # %bb.1:
; LA32-NEXT: move $a0, $a2
; LA32-NEXT: .LBB18_2:
@@ -459,11 +457,9 @@ define signext i32 @bit_20_z_select_i32(i32 signext %a, i32 signext %b, i32 sign
define signext i32 @bit_20_nz_select_i32(i32 signext %a, i32 signext %b, i32 signext %c) {
; LA32-LABEL: bit_20_nz_select_i32:
; LA32: # %bb.0:
-; LA32-NEXT: lu12i.w $a3, 256
-; LA32-NEXT: and $a0, $a0, $a3
-; LA32-NEXT: srli.w $a3, $a0, 20
+; LA32-NEXT: slli.w $a3, $a0, 11
; LA32-NEXT: move $a0, $a1
-; LA32-NEXT: bne $a3, $zero, .LBB20_2
+; LA32-NEXT: bltz $a3, .LBB20_2
; LA32-NEXT: # %bb.1:
; LA32-NEXT: move $a0, $a2
; LA32-NEXT: .LBB20_2:
diff --git a/llvm/test/CodeGen/LoongArch/select-const.ll b/llvm/test/CodeGen/LoongArch/select-const.ll
index 00a64b8664801..ec69f5187e4f6 100644
--- a/llvm/test/CodeGen/LoongArch/select-const.ll
+++ b/llvm/test/CodeGen/LoongArch/select-const.ll
@@ -305,12 +305,9 @@ define i32 @select_ne_10001_10002(i32 signext %a, i32 signext %b) {
define i32 @select_slt_zero_constant1_constant2(i32 signext %x) {
; LA32-LABEL: select_slt_zero_constant1_constant2:
; LA32: # %bb.0:
-; LA32-NEXT: move $a1, $a0
-; LA32-NEXT: ori $a0, $zero, 7
-; LA32-NEXT: bltz $a1, .LBB16_2
-; LA32-NEXT: # %bb.1:
-; LA32-NEXT: addi.w $a0, $zero, -3
-; LA32-NEXT: .LBB16_2:
+; LA32-NEXT: srai.w $a0, $a0, 31
+; LA32-NEXT: andi $a0, $a0, 10
+; LA32-NEXT: addi.w $a0, $a0, -3
; LA32-NEXT: ret
;
; LA64-LABEL: select_slt_zero_constant1_constant2:
``````````
</details>
https://github.com/llvm/llvm-project/pull/155994
More information about the llvm-commits
mailing list