[llvm] [LoongArch] Optimize conditional branches (PR #147885)
via llvm-commits
llvm-commits at lists.llvm.org
Fri Aug 1 02:01:07 PDT 2025
================
@@ -5020,6 +5052,145 @@ static SDValue performBITREV_WCombine(SDNode *N, SelectionDAG &DAG,
Src.getOperand(0));
}
+// 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();
+
+ // As far as arithmetic right shift always saves the sign,
+ // shift can be omitted.
+ // Fold setlt (sra X, N), 0 -> setlt X, 0 and
+ // setge (sra X, N), 0 -> setge X, 0
+ if (isNullConstant(RHS) && (CCVal == ISD::SETGE || CCVal == ISD::SETLT) &&
+ LHS.getOpcode() == ISD::SRA) {
+ LHS = LHS.getOperand(0);
+ return true;
+ }
+
+ if (!ISD::isIntEqualitySetCC(CCVal))
+ return false;
+
+ // Fold ((setlt X, Y), 0, ne) -> (X, Y, lt)
+ // Sometimes the setcc is introduced after br_cc/select_cc has been formed.
+ if (LHS.getOpcode() == ISD::SETCC && isNullConstant(RHS) &&
+ LHS.getOperand(0).getValueType() == Subtarget.getGRLenVT()) {
+ // If we're looking for eq 0 instead of ne 0, we need to invert the
+ // condition.
+ bool Invert = CCVal == ISD::SETEQ;
+ CCVal = cast<CondCodeSDNode>(LHS.getOperand(2))->get();
+ if (Invert)
+ CCVal = ISD::getSetCCInverse(CCVal, LHS.getValueType());
+
+ RHS = LHS.getOperand(1);
+ LHS = LHS.getOperand(0);
+ translateSetCCForBranch(DL, LHS, RHS, CCVal, DAG);
+
+ CC = DAG.getCondCode(CCVal);
+ return true;
+ }
+
+ // If XOR is reused and has an immediate that will fit in XORI,
+ // do not fold.
+ auto isXorImmediate = [](const SDValue &Op) -> bool {
+ if (const auto *XorCnst = dyn_cast<ConstantSDNode>(Op))
+ return isInt<12>(XorCnst->getSExtValue());
+ return false;
+ };
+ // Fold (X(i1) ^ 1) == 0 -> X != 0
+ auto singleBitOp = [&DAG](const SDValue &VarOp,
+ const SDValue &ConstOp) -> bool {
+ if (const auto *XorCnst = dyn_cast<ConstantSDNode>(ConstOp)) {
+ const APInt Mask = APInt::getBitsSetFrom(VarOp.getValueSizeInBits(), 1);
+ return (XorCnst->getSExtValue() == 1) &&
+ DAG.MaskedValueIsZero(VarOp, Mask);
+ }
+ return false;
+ };
+ auto onlyUsedBySelectOrBR = [](const SDValue &Op) -> bool {
+ for (const SDNode *UserNode : Op->users()) {
+ const unsigned Opcode = UserNode->getOpcode();
+ if (Opcode != LoongArchISD::SELECT_CC && Opcode != LoongArchISD::BR_CC)
+ return false;
+ }
+ return true;
+ };
+ auto isFoldableXorEq = [isXorImmediate, singleBitOp, onlyUsedBySelectOrBR](
+ const SDValue &LHS, const SDValue &RHS) -> bool {
+ return LHS.getOpcode() == ISD::XOR && isNullConstant(RHS) &&
+ (!isXorImmediate(LHS.getOperand(1)) ||
+ singleBitOp(LHS.getOperand(0), LHS.getOperand(1)) ||
+ onlyUsedBySelectOrBR(LHS));
+ };
+ // Fold ((xor X, Y), 0, eq/ne) -> (X, Y, eq/ne)
+ if (isFoldableXorEq(LHS, RHS)) {
+ RHS = LHS.getOperand(1);
+ LHS = LHS.getOperand(0);
+ return true;
+ }
+ // Fold ((sext (xor X, C)), 0, eq/ne) -> ((sext(X), C, eq/ne)
+ if (LHS.getOpcode() == ISD::SIGN_EXTEND_INREG) {
+ const SDValue LHS0 = LHS.getOperand(0);
+ if (isFoldableXorEq(LHS0, RHS) && isa<ConstantSDNode>(LHS0.getOperand(1))) {
+ // SEXT(XOR(X, Y)) -> XOR(SEXT(X), SEXT(Y)))
+ RHS = DAG.getNode(ISD::SIGN_EXTEND_INREG, DL, LHS.getValueType(),
+ LHS0.getOperand(1), LHS.getOperand(1));
+ LHS = DAG.getNode(ISD::SIGN_EXTEND_INREG, DL, LHS.getValueType(),
+ LHS0.getOperand(0), LHS.getOperand(1));
+ 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() &&
----------------
tangaac wrote:
We may need some tests for folding to `shl`.
https://github.com/llvm/llvm-project/pull/147885
More information about the llvm-commits
mailing list