From 0b0275289961dd49315bcb3b8dfcae5687f23eaa Mon Sep 17 00:00:00 2001 From: Craig Topper Date: Mon, 18 Jul 2022 09:58:54 -0700 Subject: [PATCH] [RISCV] Optimize (seteq (i64 (and X, 0xffffffff)), C1) (and X, 0xffffffff) requires 2 shifts in the base ISA. Since we know the result is being used by a compare, we can use a sext_inreg instead of an AND if we also modify C1 to have 33 sign bits instead of 32 leading zeros. This can also improve the generated code for materializing C1. Reviewed By: reames Differential Revision: https://reviews.llvm.org/D129980 --- llvm/lib/Target/RISCV/RISCVISelLowering.cpp | 48 ++++++++++++++++++++++++++++- llvm/test/CodeGen/RISCV/i64-icmp.ll | 23 +++++--------- 2 files changed, 54 insertions(+), 17 deletions(-) diff --git a/llvm/lib/Target/RISCV/RISCVISelLowering.cpp b/llvm/lib/Target/RISCV/RISCVISelLowering.cpp index 04833f5..3fcc8c3 100644 --- a/llvm/lib/Target/RISCV/RISCVISelLowering.cpp +++ b/llvm/lib/Target/RISCV/RISCVISelLowering.cpp @@ -934,7 +934,7 @@ RISCVTargetLowering::RISCVTargetLowering(const TargetMachine &TM, 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 @@ static SDValue performXORCombine(SDNode *N, SelectionDAG &DAG) { 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 @@ SDValue RISCVTargetLowering::PerformDAGCombine(SDNode *N, 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 index 2e5b44e..503a4f1 100644 --- a/llvm/test/CodeGen/RISCV/i64-icmp.ll +++ b/llvm/test/CodeGen/RISCV/i64-icmp.ll @@ -689,8 +689,7 @@ define i64 @icmp_sle_constant_neg_2050(i64 %a) nounwind { 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_small_constant(i64 %a) nounwind { 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_eq_zext_inreg_large_constant(i64 %a) nounwind { 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_small_constant(i64 %a) nounwind { 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 -- 2.7.4