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 @@ -7922,7 +7922,27 @@ return combineSelectAndUse(N, N1, N0, DAG, /*AllOnes*/ false); } -static SDValue performANDCombine(SDNode *N, SelectionDAG &DAG) { +static SDValue performANDCombine(SDNode *N, SelectionDAG &DAG, + const RISCVSubtarget &Subtarget) { + SDValue N0 = N->getOperand(0); + // Pre-promote (i32 (and (srl X, Y), 1)) on RV64 with Zbs without zero + // extending X. This is safe since we only need the LSB after the shift and + // shift amounts larger than 31 would produce poison. If we wait until + // type legalization, we'll create RISCVISD::SRLW and we can't recover it + // to use a BEXT instruction. + if (Subtarget.is64Bit() && Subtarget.hasStdExtZbs() && + N->getValueType(0) == MVT::i32 && isOneConstant(N->getOperand(1)) && + N0.getOpcode() == ISD::SRL && !isa(N0.getOperand(1)) && + N0.hasOneUse()) { + SDLoc DL(N); + SDValue Op0 = DAG.getNode(ISD::ANY_EXTEND, DL, MVT::i64, N0.getOperand(0)); + SDValue Op1 = DAG.getNode(ISD::ZERO_EXTEND, DL, MVT::i64, N0.getOperand(1)); + SDValue Srl = DAG.getNode(ISD::SRL, DL, MVT::i64, Op0, Op1); + SDValue And = DAG.getNode(ISD::AND, DL, MVT::i64, Srl, + DAG.getConstant(1, DL, MVT::i64)); + return DAG.getNode(ISD::TRUNCATE, DL, MVT::i32, And); + } + // fold (and (select lhs, rhs, cc, -1, y), x) -> // (select lhs, rhs, cc, x, (and x, y)) return combineSelectAndUseCommutative(N, DAG, /*AllOnes*/ true); @@ -8564,7 +8584,7 @@ case ISD::SUB: return performSUBCombine(N, DAG); case ISD::AND: - return performANDCombine(N, DAG); + return performANDCombine(N, DAG, Subtarget); case ISD::OR: return performORCombine(N, DAG, Subtarget); case ISD::XOR: diff --git a/llvm/test/CodeGen/RISCV/rv64zbs.ll b/llvm/test/CodeGen/RISCV/rv64zbs.ll --- a/llvm/test/CodeGen/RISCV/rv64zbs.ll +++ b/llvm/test/CodeGen/RISCV/rv64zbs.ll @@ -347,8 +347,8 @@ ; ; RV64ZBS-LABEL: bext_i32: ; RV64ZBS: # %bb.0: -; RV64ZBS-NEXT: srlw a0, a0, a1 -; RV64ZBS-NEXT: andi a0, a0, 1 +; RV64ZBS-NEXT: andi a1, a1, 31 +; RV64ZBS-NEXT: bext a0, a0, a1 ; RV64ZBS-NEXT: ret %and = and i32 %b, 31 %shr = lshr i32 %a, %and @@ -365,8 +365,7 @@ ; ; RV64ZBS-LABEL: bext_i32_no_mask: ; RV64ZBS: # %bb.0: -; RV64ZBS-NEXT: srlw a0, a0, a1 -; RV64ZBS-NEXT: andi a0, a0, 1 +; RV64ZBS-NEXT: bext a0, a0, a1 ; RV64ZBS-NEXT: ret %shr = lshr i32 %a, %b %and1 = and i32 %shr, 1