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 @@ -934,7 +934,7 @@ setJumpIsExpensive(); setTargetDAGCombine({ISD::INTRINSIC_WO_CHAIN, ISD::ADD, ISD::SUB, ISD::AND, - ISD::OR, ISD::XOR}); + ISD::OR, ISD::XOR, ISD::SETCC}); if (Subtarget.is64Bit()) setTargetDAGCombine(ISD::SRA); @@ -8118,6 +8118,50 @@ return combineSelectAndUseCommutative(N, DAG, /*AllOnes*/ false); } +// Replace (seteq (i64 (and X, 0xffffffff)), C1) with +// (seteq (i64 (sext_inreg (X, i32)), C1')) where C1' is C1 sign extended from +// bit 31. Same for setne. C1' may be cheaper to materialize and the sext_inreg +// can become a sext.w instead of a shift pair. +static SDValue performSETCCCombine(SDNode *N, SelectionDAG &DAG, + const RISCVSubtarget &Subtarget) { + SDValue N0 = N->getOperand(0); + SDValue N1 = N->getOperand(1); + EVT VT = N->getValueType(0); + EVT OpVT = N0.getValueType(); + + if (OpVT != MVT::i64 || !Subtarget.is64Bit()) + return SDValue(); + + // RHS needs to be a constant. + auto *N1C = dyn_cast(N1); + if (!N1C) + return SDValue(); + + // LHS needs to be (and X, 0xffffffff). + if (N0.getOpcode() != ISD::AND || !N0.hasOneUse() || + !isa(N0.getOperand(1)) || + N0.getConstantOperandVal(1) != UINT64_C(0xffffffff)) + return SDValue(); + + // Looking for an equality compare. + ISD::CondCode Cond = cast(N->getOperand(2))->get(); + if (!isIntEqualitySetCC(Cond)) + return SDValue(); + + const APInt &C1 = cast(N1)->getAPIntValue(); + + SDLoc dl(N); + // If the constant is larger than 2^32 - 1 it is impossible for both sides + // to be equal. + if (C1.getActiveBits() > 32) + return DAG.getBoolConstant(Cond == ISD::SETNE, dl, VT, OpVT); + + SDValue SExtOp = DAG.getNode(ISD::SIGN_EXTEND_INREG, N, OpVT, + N0.getOperand(0), DAG.getValueType(MVT::i32)); + return DAG.getSetCC(dl, VT, SExtOp, DAG.getConstant(C1.trunc(32).sext(64), + dl, OpVT), Cond); +} + static SDValue performSIGN_EXTEND_INREGCombine(SDNode *N, SelectionDAG &DAG, const RISCVSubtarget &Subtarget) { @@ -8860,6 +8904,8 @@ case ISD::FMAXNUM: case ISD::FMINNUM: return combineBinOpToReduce(N, DAG); + case ISD::SETCC: + return performSETCCCombine(N, DAG, Subtarget); case ISD::SIGN_EXTEND_INREG: return performSIGN_EXTEND_INREGCombine(N, DAG, Subtarget); case ISD::ZERO_EXTEND: diff --git a/llvm/test/CodeGen/RISCV/i64-icmp.ll b/llvm/test/CodeGen/RISCV/i64-icmp.ll --- a/llvm/test/CodeGen/RISCV/i64-icmp.ll +++ b/llvm/test/CodeGen/RISCV/i64-icmp.ll @@ -689,8 +689,7 @@ define i64 @icmp_eq_zext_inreg_small_constant(i64 %a) nounwind { ; RV64I-LABEL: icmp_eq_zext_inreg_small_constant: ; RV64I: # %bb.0: -; RV64I-NEXT: slli a0, a0, 32 -; RV64I-NEXT: srli a0, a0, 32 +; RV64I-NEXT: sext.w a0, a0 ; RV64I-NEXT: addi a0, a0, -123 ; RV64I-NEXT: seqz a0, a0 ; RV64I-NEXT: ret @@ -703,12 +702,9 @@ define i64 @icmp_eq_zext_inreg_large_constant(i64 %a) nounwind { ; RV64I-LABEL: icmp_eq_zext_inreg_large_constant: ; RV64I: # %bb.0: -; RV64I-NEXT: slli a0, a0, 32 -; RV64I-NEXT: srli a0, a0, 32 -; RV64I-NEXT: lui a1, 138 -; RV64I-NEXT: addiw a1, a1, -1347 -; RV64I-NEXT: slli a1, a1, 12 -; RV64I-NEXT: addi a1, a1, -529 +; RV64I-NEXT: sext.w a0, a0 +; RV64I-NEXT: lui a1, 563901 +; RV64I-NEXT: addiw a1, a1, -529 ; RV64I-NEXT: xor a0, a0, a1 ; RV64I-NEXT: seqz a0, a0 ; RV64I-NEXT: ret @@ -721,8 +717,7 @@ define i64 @icmp_ne_zext_inreg_small_constant(i64 %a) nounwind { ; RV64I-LABEL: icmp_ne_zext_inreg_small_constant: ; RV64I: # %bb.0: -; RV64I-NEXT: slli a0, a0, 32 -; RV64I-NEXT: srli a0, a0, 32 +; RV64I-NEXT: sext.w a0, a0 ; RV64I-NEXT: snez a0, a0 ; RV64I-NEXT: ret %1 = and i64 %a, 4294967295 @@ -734,12 +729,8 @@ define i64 @icmp_ne_zext_inreg_large_constant(i64 %a) nounwind { ; RV64I-LABEL: icmp_ne_zext_inreg_large_constant: ; RV64I: # %bb.0: -; RV64I-NEXT: slli a0, a0, 32 -; RV64I-NEXT: srli a0, a0, 32 -; RV64I-NEXT: li a1, 1 -; RV64I-NEXT: slli a1, a1, 32 -; RV64I-NEXT: addi a1, a1, -2 -; RV64I-NEXT: xor a0, a0, a1 +; RV64I-NEXT: sext.w a0, a0 +; RV64I-NEXT: addi a0, a0, 2 ; RV64I-NEXT: snez a0, a0 ; RV64I-NEXT: ret %1 = and i64 %a, 4294967295