diff --git a/llvm/lib/Target/RISCV/RISCVISelLowering.cpp b/llvm/lib/Target/RISCV/RISCVISelLowering.cpp --- a/llvm/lib/Target/RISCV/RISCVISelLowering.cpp +++ b/llvm/lib/Target/RISCV/RISCVISelLowering.cpp @@ -858,6 +858,8 @@ // We can use any register for comparisons setHasMultipleConditionRegisters(); + setTargetDAGCombine(ISD::ADD); + setTargetDAGCombine(ISD::SUB); setTargetDAGCombine(ISD::AND); setTargetDAGCombine(ISD::OR); setTargetDAGCombine(ISD::XOR); @@ -5769,17 +5771,27 @@ // Combine a constant select operand into its use: // -// (and (select_cc lhs, rhs, cc, -1, c), x) -// -> (select_cc lhs, rhs, cc, x, (and, x, c)) [AllOnes=1] -// (or (select_cc lhs, rhs, cc, 0, c), x) -// -> (select_cc lhs, rhs, cc, x, (or, x, c)) [AllOnes=0] -// (xor (select_cc lhs, rhs, cc, 0, c), x) -// -> (select_cc lhs, rhs, cc, x, (xor, x, c)) [AllOnes=0] -static SDValue combineSelectCCAndUse(SDNode *N, SDValue Slct, SDValue OtherOp, - SelectionDAG &DAG, bool AllOnes) { +// (and (select cond, -1, c), x) +// -> (select cond, x, (and x, c)) [AllOnes=1] +// (or (select cond, 0, c), x) +// -> (select cond, x, (or x, c)) [AllOnes=0] +// (xor (select cond, 0, c), x) +// -> (select cond, x, (xor x, c)) [AllOnes=0] +// (add (select cond, 0, c), x) +// -> (select cond, x, (add x, c)) [AllOnes=0] +// (sub x, (select cond, 0, c)) +// -> (select cond, x, (sub x, c)) [AllOnes=0] +static SDValue combineSelectAndUse(SDNode *N, SDValue Slct, SDValue OtherOp, + SelectionDAG &DAG, bool AllOnes) { EVT VT = N->getValueType(0); - if (Slct.getOpcode() != RISCVISD::SELECT_CC || !Slct.hasOneUse()) + // Skip vectors. + if (VT.isVector()) + return SDValue(); + + if ((Slct.getOpcode() != ISD::SELECT && + Slct.getOpcode() != RISCVISD::SELECT_CC) || + !Slct.hasOneUse()) return SDValue(); auto isZeroOrAllOnes = [](SDValue N, bool AllOnes) { @@ -5787,8 +5799,9 @@ }; bool SwapSelectOps; - SDValue TrueVal = Slct.getOperand(3); - SDValue FalseVal = Slct.getOperand(4); + unsigned OpOffset = Slct.getOpcode() == RISCVISD::SELECT_CC ? 2 : 0; + SDValue TrueVal = Slct.getOperand(1 + OpOffset); + SDValue FalseVal = Slct.getOperand(2 + OpOffset); SDValue NonConstantVal; if (isZeroOrAllOnes(TrueVal, AllOnes)) { SwapSelectOps = false; @@ -5802,40 +5815,53 @@ // Slct is now know to be the desired identity constant when CC is true. TrueVal = OtherOp; FalseVal = DAG.getNode(N->getOpcode(), SDLoc(N), VT, OtherOp, NonConstantVal); - // Unless SwapSelectOps says CC should be false. + // Unless SwapSelectOps says the condition should be false. if (SwapSelectOps) std::swap(TrueVal, FalseVal); - return DAG.getNode(RISCVISD::SELECT_CC, SDLoc(N), VT, - {Slct.getOperand(0), Slct.getOperand(1), - Slct.getOperand(2), TrueVal, FalseVal}); + if (Slct.getOpcode() == RISCVISD::SELECT_CC) + return DAG.getNode(RISCVISD::SELECT_CC, SDLoc(N), VT, + {Slct.getOperand(0), Slct.getOperand(1), + Slct.getOperand(2), TrueVal, FalseVal}); + + return DAG.getNode(ISD::SELECT, SDLoc(N), VT, + {Slct.getOperand(0), TrueVal, FalseVal}); } // Attempt combineSelectAndUse on each operand of a commutative operator N. -static SDValue combineSelectCCAndUseCommutative(SDNode *N, SelectionDAG &DAG, - bool AllOnes) { +static SDValue combineSelectAndUseCommutative(SDNode *N, SelectionDAG &DAG, + bool AllOnes) { SDValue N0 = N->getOperand(0); SDValue N1 = N->getOperand(1); - if (SDValue Result = combineSelectCCAndUse(N, N0, N1, DAG, AllOnes)) + if (SDValue Result = combineSelectAndUse(N, N0, N1, DAG, AllOnes)) return Result; - if (SDValue Result = combineSelectCCAndUse(N, N1, N0, DAG, AllOnes)) + if (SDValue Result = combineSelectAndUse(N, N1, N0, DAG, AllOnes)) return Result; return SDValue(); } -static SDValue performANDCombine(SDNode *N, - TargetLowering::DAGCombinerInfo &DCI, - const RISCVSubtarget &Subtarget) { - SelectionDAG &DAG = DCI.DAG; +static SDValue performADDCombine(SDNode *N, SelectionDAG &DAG) { + // fold (add (select lhs, rhs, cc, 0, y), x) -> + // (select lhs, rhs, cc, x, (add x, y)) + return combineSelectAndUseCommutative(N, DAG, /*AllOnes*/ false); +} - // fold (and (select_cc lhs, rhs, cc, -1, y), x) -> +static SDValue performSUBCombine(SDNode *N, SelectionDAG &DAG) { + // fold (sub x, (select lhs, rhs, cc, 0, y)) -> + // (select lhs, rhs, cc, x, (sub x, y)) + SDValue N0 = N->getOperand(0); + SDValue N1 = N->getOperand(1); + return combineSelectAndUse(N, N1, N0, DAG, /*AllOnes*/ false); +} + +static SDValue performANDCombine(SDNode *N, SelectionDAG &DAG) { + // fold (and (select lhs, rhs, cc, -1, y), x) -> // (select lhs, rhs, cc, x, (and x, y)) - return combineSelectCCAndUseCommutative(N, DAG, true); + return combineSelectAndUseCommutative(N, DAG, /*AllOnes*/ true); } -static SDValue performORCombine(SDNode *N, TargetLowering::DAGCombinerInfo &DCI, +static SDValue performORCombine(SDNode *N, SelectionDAG &DAG, const RISCVSubtarget &Subtarget) { - SelectionDAG &DAG = DCI.DAG; if (Subtarget.hasStdExtZbp()) { if (auto GREV = combineORToGREV(SDValue(N, 0), DAG, Subtarget)) return GREV; @@ -5845,19 +5871,15 @@ return SHFL; } - // fold (or (select_cc lhs, rhs, cc, 0, y), x) -> - // (select lhs, rhs, cc, x, (or x, y)) - return combineSelectCCAndUseCommutative(N, DAG, false); + // fold (or (select cond, 0, y), x) -> + // (select cond, x, (or x, y)) + return combineSelectAndUseCommutative(N, DAG, /*AllOnes*/ false); } -static SDValue performXORCombine(SDNode *N, - TargetLowering::DAGCombinerInfo &DCI, - const RISCVSubtarget &Subtarget) { - SelectionDAG &DAG = DCI.DAG; - - // fold (xor (select_cc lhs, rhs, cc, 0, y), x) -> - // (select lhs, rhs, cc, x, (xor x, y)) - return combineSelectCCAndUseCommutative(N, DAG, false); +static SDValue performXORCombine(SDNode *N, SelectionDAG &DAG) { + // fold (xor (select cond, 0, y), x) -> + // (select cond, x, (xor x, y)) + return combineSelectAndUseCommutative(N, DAG, /*AllOnes*/ false); } // Attempt to turn ANY_EXTEND into SIGN_EXTEND if the input to the ANY_EXTEND @@ -6167,12 +6189,16 @@ return DAG.getNode(ISD::AND, DL, VT, NewFMV, DAG.getConstant(~SignBit, DL, VT)); } + case ISD::ADD: + return performADDCombine(N, DAG); + case ISD::SUB: + return performSUBCombine(N, DAG); case ISD::AND: - return performANDCombine(N, DCI, Subtarget); + return performANDCombine(N, DAG); case ISD::OR: - return performORCombine(N, DCI, Subtarget); + return performORCombine(N, DAG, Subtarget); case ISD::XOR: - return performXORCombine(N, DCI, Subtarget); + return performXORCombine(N, DAG); case ISD::ANY_EXTEND: return performANY_EXTENDCombine(N, DCI, Subtarget); case ISD::ZERO_EXTEND: diff --git a/llvm/test/CodeGen/RISCV/rv32zbs.ll b/llvm/test/CodeGen/RISCV/rv32zbs.ll --- a/llvm/test/CodeGen/RISCV/rv32zbs.ll +++ b/llvm/test/CodeGen/RISCV/rv32zbs.ll @@ -75,16 +75,15 @@ ; ; RV32IB-LABEL: sbclr_i64: ; RV32IB: # %bb.0: -; RV32IB-NEXT: andi a3, a2, 63 -; RV32IB-NEXT: addi a3, a3, -32 -; RV32IB-NEXT: bset a4, zero, a3 -; RV32IB-NEXT: slti a5, a3, 0 -; RV32IB-NEXT: cmov a4, a5, zero, a4 -; RV32IB-NEXT: bset a2, zero, a2 -; RV32IB-NEXT: srai a3, a3, 31 -; RV32IB-NEXT: and a2, a3, a2 -; RV32IB-NEXT: andn a1, a1, a4 -; RV32IB-NEXT: andn a0, a0, a2 +; RV32IB-NEXT: bset a3, zero, a2 +; RV32IB-NEXT: andi a2, a2, 63 +; RV32IB-NEXT: addi a2, a2, -32 +; RV32IB-NEXT: srai a4, a2, 31 +; RV32IB-NEXT: and a3, a4, a3 +; RV32IB-NEXT: slti a4, a2, 0 +; RV32IB-NEXT: bclr a2, a1, a2 +; RV32IB-NEXT: cmov a1, a4, a1, a2 +; RV32IB-NEXT: andn a0, a0, a3 ; RV32IB-NEXT: ret ; ; RV32IBS-LABEL: sbclr_i64: diff --git a/llvm/test/CodeGen/RISCV/select-binop-identity.ll b/llvm/test/CodeGen/RISCV/select-binop-identity.ll --- a/llvm/test/CodeGen/RISCV/select-binop-identity.ll +++ b/llvm/test/CodeGen/RISCV/select-binop-identity.ll @@ -157,22 +157,20 @@ define signext i32 @add_select_all_zeros_i32(i1 zeroext %c, i32 signext %x, i32 signext %y) { ; RV32I-LABEL: add_select_all_zeros_i32: ; RV32I: # %bb.0: -; RV32I-NEXT: mv a3, zero ; RV32I-NEXT: bnez a0, .LBB6_2 ; RV32I-NEXT: # %bb.1: -; RV32I-NEXT: mv a3, a1 +; RV32I-NEXT: add a2, a2, a1 ; RV32I-NEXT: .LBB6_2: -; RV32I-NEXT: add a0, a2, a3 +; RV32I-NEXT: mv a0, a2 ; RV32I-NEXT: ret ; ; RV64I-LABEL: add_select_all_zeros_i32: ; RV64I: # %bb.0: -; RV64I-NEXT: mv a3, zero ; RV64I-NEXT: bnez a0, .LBB6_2 ; RV64I-NEXT: # %bb.1: -; RV64I-NEXT: mv a3, a1 +; RV64I-NEXT: addw a2, a2, a1 ; RV64I-NEXT: .LBB6_2: -; RV64I-NEXT: addw a0, a2, a3 +; RV64I-NEXT: mv a0, a2 ; RV64I-NEXT: ret %a = select i1 %c, i32 0, i32 %x %b = add i32 %y, %a @@ -182,24 +180,25 @@ define i64 @add_select_all_zeros_i64(i1 zeroext %c, i64 %x, i64 %y) { ; RV32I-LABEL: add_select_all_zeros_i64: ; RV32I: # %bb.0: -; RV32I-NEXT: bnez a0, .LBB7_2 +; RV32I-NEXT: beqz a0, .LBB7_2 ; RV32I-NEXT: # %bb.1: -; RV32I-NEXT: mv a2, zero -; RV32I-NEXT: mv a1, zero +; RV32I-NEXT: add a0, a4, a2 +; RV32I-NEXT: add a1, a3, a1 +; RV32I-NEXT: sltu a2, a1, a3 +; RV32I-NEXT: add a4, a0, a2 +; RV32I-NEXT: mv a3, a1 ; RV32I-NEXT: .LBB7_2: -; RV32I-NEXT: add a0, a1, a3 -; RV32I-NEXT: sltu a1, a0, a1 -; RV32I-NEXT: add a2, a2, a4 -; RV32I-NEXT: add a1, a2, a1 +; RV32I-NEXT: mv a0, a3 +; RV32I-NEXT: mv a1, a4 ; RV32I-NEXT: ret ; ; RV64I-LABEL: add_select_all_zeros_i64: ; RV64I: # %bb.0: -; RV64I-NEXT: bnez a0, .LBB7_2 +; RV64I-NEXT: beqz a0, .LBB7_2 ; RV64I-NEXT: # %bb.1: -; RV64I-NEXT: mv a1, zero +; RV64I-NEXT: add a2, a2, a1 ; RV64I-NEXT: .LBB7_2: -; RV64I-NEXT: add a0, a1, a2 +; RV64I-NEXT: mv a0, a2 ; RV64I-NEXT: ret %a = select i1 %c, i64 %x, i64 0 %b = add i64 %a, %y @@ -209,22 +208,20 @@ define signext i32 @sub_select_all_zeros_i32(i1 zeroext %c, i32 signext %x, i32 signext %y) { ; RV32I-LABEL: sub_select_all_zeros_i32: ; RV32I: # %bb.0: -; RV32I-NEXT: mv a3, zero ; RV32I-NEXT: bnez a0, .LBB8_2 ; RV32I-NEXT: # %bb.1: -; RV32I-NEXT: mv a3, a1 +; RV32I-NEXT: sub a2, a2, a1 ; RV32I-NEXT: .LBB8_2: -; RV32I-NEXT: sub a0, a2, a3 +; RV32I-NEXT: mv a0, a2 ; RV32I-NEXT: ret ; ; RV64I-LABEL: sub_select_all_zeros_i32: ; RV64I: # %bb.0: -; RV64I-NEXT: mv a3, zero ; RV64I-NEXT: bnez a0, .LBB8_2 ; RV64I-NEXT: # %bb.1: -; RV64I-NEXT: mv a3, a1 +; RV64I-NEXT: subw a2, a2, a1 ; RV64I-NEXT: .LBB8_2: -; RV64I-NEXT: subw a0, a2, a3 +; RV64I-NEXT: mv a0, a2 ; RV64I-NEXT: ret %a = select i1 %c, i32 0, i32 %x %b = sub i32 %y, %a @@ -234,25 +231,24 @@ define i64 @sub_select_all_zeros_i64(i1 zeroext %c, i64 %x, i64 %y) { ; RV32I-LABEL: sub_select_all_zeros_i64: ; RV32I: # %bb.0: -; RV32I-NEXT: bnez a0, .LBB9_2 +; RV32I-NEXT: beqz a0, .LBB9_2 ; RV32I-NEXT: # %bb.1: -; RV32I-NEXT: mv a2, zero -; RV32I-NEXT: mv a1, zero -; RV32I-NEXT: .LBB9_2: ; RV32I-NEXT: sltu a0, a3, a1 ; RV32I-NEXT: sub a2, a4, a2 -; RV32I-NEXT: sub a2, a2, a0 -; RV32I-NEXT: sub a0, a3, a1 -; RV32I-NEXT: mv a1, a2 +; RV32I-NEXT: sub a4, a2, a0 +; RV32I-NEXT: sub a3, a3, a1 +; RV32I-NEXT: .LBB9_2: +; RV32I-NEXT: mv a0, a3 +; RV32I-NEXT: mv a1, a4 ; RV32I-NEXT: ret ; ; RV64I-LABEL: sub_select_all_zeros_i64: ; RV64I: # %bb.0: -; RV64I-NEXT: bnez a0, .LBB9_2 +; RV64I-NEXT: beqz a0, .LBB9_2 ; RV64I-NEXT: # %bb.1: -; RV64I-NEXT: mv a1, zero +; RV64I-NEXT: sub a2, a2, a1 ; RV64I-NEXT: .LBB9_2: -; RV64I-NEXT: sub a0, a2, a1 +; RV64I-NEXT: mv a0, a2 ; RV64I-NEXT: ret %a = select i1 %c, i64 %x, i64 0 %b = sub i64 %y, %a