diff --git a/llvm/lib/Target/RISCV/RISCVISelLowering.cpp b/llvm/lib/Target/RISCV/RISCVISelLowering.cpp index dfb003a9cb1c1..6a54ad812d6fe 100644 --- a/llvm/lib/Target/RISCV/RISCVISelLowering.cpp +++ b/llvm/lib/Target/RISCV/RISCVISelLowering.cpp @@ -9064,18 +9064,51 @@ SDValue RISCVTargetLowering::lowerSELECT(SDValue Op, SelectionDAG &DAG) const { if (isNullConstant(TrueV)) return DAG.getNode(RISCVISD::CZERO_NEZ, DL, VT, FalseV, CondV); + // Check to see if a given operation is a 'NOT', if so return the negated + // operand + auto getNotOperand = [](const SDValue &Op) -> std::optional { + using namespace llvm::SDPatternMatch; + SDValue Xor; + if (sd_match(Op, m_OneUse(m_Not(m_Value(Xor))))) { + return Xor; + } + return std::nullopt; + }; // (select c, (and f, x), f) -> (or (and f, x), (czero_nez f, c)) + // (select c, (and f, ~x), f) -> (andn f, (czero_eqz x, c)) if (TrueV.getOpcode() == ISD::AND && - (TrueV.getOperand(0) == FalseV || TrueV.getOperand(1) == FalseV)) + (TrueV.getOperand(0) == FalseV || TrueV.getOperand(1) == FalseV)) { + auto NotOperand = (TrueV.getOperand(0) == FalseV) + ? getNotOperand(TrueV.getOperand(1)) + : getNotOperand(TrueV.getOperand(0)); + if (NotOperand) { + SDValue CMOV = + DAG.getNode(RISCVISD::CZERO_EQZ, DL, VT, *NotOperand, CondV); + SDValue NOT = DAG.getNOT(DL, CMOV, VT); + return DAG.getNode(ISD::AND, DL, VT, FalseV, NOT); + } return DAG.getNode( ISD::OR, DL, VT, TrueV, DAG.getNode(RISCVISD::CZERO_NEZ, DL, VT, FalseV, CondV)); + } + // (select c, t, (and t, x)) -> (or (czero_eqz t, c), (and t, x)) + // (select c, t, (and t, ~x)) -> (andn t, (czero_nez x, c)) if (FalseV.getOpcode() == ISD::AND && - (FalseV.getOperand(0) == TrueV || FalseV.getOperand(1) == TrueV)) + (FalseV.getOperand(0) == TrueV || FalseV.getOperand(1) == TrueV)) { + auto NotOperand = (FalseV.getOperand(0) == TrueV) + ? getNotOperand(FalseV.getOperand(1)) + : getNotOperand(FalseV.getOperand(0)); + if (NotOperand) { + SDValue CMOV = + DAG.getNode(RISCVISD::CZERO_NEZ, DL, VT, *NotOperand, CondV); + SDValue NOT = DAG.getNOT(DL, CMOV, VT); + return DAG.getNode(ISD::AND, DL, VT, TrueV, NOT); + } return DAG.getNode( ISD::OR, DL, VT, FalseV, DAG.getNode(RISCVISD::CZERO_EQZ, DL, VT, TrueV, CondV)); + } // Try some other optimizations before falling back to generic lowering. if (SDValue V = combineSelectToBinOp(Op.getNode(), DAG, Subtarget)) diff --git a/llvm/test/CodeGen/RISCV/zicond-opts.ll b/llvm/test/CodeGen/RISCV/zicond-opts.ll index 35b06c4f4fb41..a16145d15db81 100644 --- a/llvm/test/CodeGen/RISCV/zicond-opts.ll +++ b/llvm/test/CodeGen/RISCV/zicond-opts.ll @@ -233,9 +233,8 @@ define i64 @test_inv_and_nez(i64 %f, i64 %x, i1 %cond) { ; RV64ZICOND-LABEL: test_inv_and_nez: ; RV64ZICOND: # %bb.0: ; RV64ZICOND-NEXT: andi a2, a2, 1 -; RV64ZICOND-NEXT: andn a1, a0, a1 -; RV64ZICOND-NEXT: czero.nez a0, a0, a2 -; RV64ZICOND-NEXT: or a0, a1, a0 +; RV64ZICOND-NEXT: czero.eqz a1, a1, a2 +; RV64ZICOND-NEXT: andn a0, a0, a1 ; RV64ZICOND-NEXT: ret %5 = xor i64 %x, -1 %6 = select i1 %cond, i64 %5, i64 -1 @@ -258,9 +257,8 @@ define i64 @test_inv_and_eqz(i64 %f, i64 %x, i1 %cond) { ; RV64ZICOND-LABEL: test_inv_and_eqz: ; RV64ZICOND: # %bb.0: ; RV64ZICOND-NEXT: andi a2, a2, 1 -; RV64ZICOND-NEXT: andn a1, a0, a1 -; RV64ZICOND-NEXT: czero.eqz a0, a0, a2 -; RV64ZICOND-NEXT: or a0, a1, a0 +; RV64ZICOND-NEXT: czero.nez a1, a1, a2 +; RV64ZICOND-NEXT: andn a0, a0, a1 ; RV64ZICOND-NEXT: ret %5 = xor i64 %x, -1 %6 = select i1 %cond, i64 -1, i64 %5