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 @@ -8564,12 +8564,6 @@ return Opcode; } -// Combine (sra (shl X, 32), 32 - C) -> (shl (sext_inreg X, i32), C) -// FIXME: Should this be a generic combine? There's a similar combine on X86. -// -// Also try these folds where an add or sub is in the middle. -// (sra (add (shl X, 32), C1), 32 - C) -> (shl (sext_inreg (add X, C1), C) -// (sra (sub C1, (shl X, 32)), 32 - C) -> (shl (sext_inreg (sub C1, X), C) static SDValue performSRACombine(SDNode *N, SelectionDAG &DAG, const RISCVSubtarget &Subtarget) { assert(N->getOpcode() == ISD::SRA && "Unexpected opcode"); @@ -8577,12 +8571,40 @@ if (N->getValueType(0) != MVT::i64 || !Subtarget.is64Bit()) return SDValue(); - auto *ShAmtC = dyn_cast(N->getOperand(1)); - if (!ShAmtC || ShAmtC->getZExtValue() > 32) + if (!isa(N->getOperand(1))) + return SDValue(); + uint64_t ShAmt = N->getConstantOperandVal(1); + if (ShAmt > 32) return SDValue(); SDValue N0 = N->getOperand(0); + // Combine (sra (sext_inreg (shl X, C1), i32), C2) -> + // (sra (shl X, C1+32), C2+32) so it gets selected as SLLI+SRAI instead of + // SLLIW+SRAIW. SLLI+SRAI have compressed forms. + if (ShAmt < 32 && + N0.getOpcode() == ISD::SIGN_EXTEND_INREG && N0.hasOneUse() && + cast(N0.getOperand(1))->getVT() == MVT::i32 && + N0.getOperand(0).getOpcode() == ISD::SHL && N0.getOperand(0).hasOneUse() && + isa(N0.getOperand(0).getOperand(1))) { + uint64_t LShAmt = N0.getOperand(0).getConstantOperandVal(1); + if (LShAmt < 32) { + SDLoc ShlDL(N0.getOperand(0)); + SDValue Shl = DAG.getNode(ISD::SHL, ShlDL, MVT::i64, + N0.getOperand(0).getOperand(0), + DAG.getConstant(LShAmt + 32, ShlDL, MVT::i64)); + SDLoc DL(N); + return DAG.getNode(ISD::SRA, DL, MVT::i64, Shl, + DAG.getConstant(ShAmt + 32, DL, MVT::i64)); + } + } + + // Combine (sra (shl X, 32), 32 - C) -> (shl (sext_inreg X, i32), C) + // FIXME: Should this be a generic combine? There's a similar combine on X86. + // + // Also try these folds where an add or sub is in the middle. + // (sra (add (shl X, 32), C1), 32 - C) -> (shl (sext_inreg (add X, C1), C) + // (sra (sub C1, (shl X, 32)), 32 - C) -> (shl (sext_inreg (sub C1, X), C) SDValue Shl; ConstantSDNode *AddC = nullptr; @@ -8628,12 +8650,12 @@ SDValue SExt = DAG.getNode(ISD::SIGN_EXTEND_INREG, DL, MVT::i64, In, DAG.getValueType(MVT::i32)); - if (ShAmtC->getZExtValue() == 32) + if (ShAmt == 32) return SExt; return DAG.getNode( ISD::SHL, DL, MVT::i64, SExt, - DAG.getConstant(32 - ShAmtC->getZExtValue(), DL, MVT::i64)); + DAG.getConstant(32 - ShAmt, DL, MVT::i64)); } SDValue RISCVTargetLowering::PerformDAGCombine(SDNode *N, diff --git a/llvm/test/CodeGen/RISCV/rv64i-shift-sext.ll b/llvm/test/CodeGen/RISCV/rv64i-shift-sext.ll --- a/llvm/test/CodeGen/RISCV/rv64i-shift-sext.ll +++ b/llvm/test/CodeGen/RISCV/rv64i-shift-sext.ll @@ -159,13 +159,12 @@ ret i64 %5 } -; TODO: We should use slli+srai to enable the possibility of compressed -; instructions. +; Make sure we use slli+srai to enable the possibility of compressed define i32 @test12(i32 signext %0) { ; RV64I-LABEL: test12: ; RV64I: # %bb.0: -; RV64I-NEXT: slliw a0, a0, 17 -; RV64I-NEXT: sraiw a0, a0, 15 +; RV64I-NEXT: slli a0, a0, 49 +; RV64I-NEXT: srai a0, a0, 47 ; RV64I-NEXT: ret %2 = shl i32 %0, 17 %3 = ashr i32 %2, 15