diff --git a/llvm/lib/Target/RISCV/RISCVISelDAGToDAG.cpp b/llvm/lib/Target/RISCV/RISCVISelDAGToDAG.cpp --- a/llvm/lib/Target/RISCV/RISCVISelDAGToDAG.cpp +++ b/llvm/lib/Target/RISCV/RISCVISelDAGToDAG.cpp @@ -551,6 +551,39 @@ ReplaceNode(Node, CurDAG->getMachineNode(RISCV::ADDI, DL, VT, TFI, Imm)); return; } + case ISD::SRL: { + // Optimize (srl (and X, 0xffff), C) -> (srli (slli X, 16), 16 + C). + // Taking into account that the 0xffff may have had lower bits removed by + // SimplifyDemandedBits. + // This avoids materializing the 0xffff immediate. This pattern occurs when + // type legalizing i16 right shifts. + // FIXME: This could be extended to other AND masks. + auto *N1C = dyn_cast(Node->getOperand(1)); + if (N1C) { + uint64_t ShAmt = N1C->getZExtValue(); + SDValue N0 = Node->getOperand(0); + if (ShAmt < 16 && N0.getOpcode() == ISD::AND && N0.hasOneUse() && + isa(N0.getOperand(1))) { + uint64_t Mask = N0.getConstantOperandVal(1); + Mask |= maskTrailingOnes(ShAmt); + if (Mask == 0xffff) { + SDLoc DL(Node); + unsigned SLLOpc = Subtarget->is64Bit() ? RISCV::SLLIW : RISCV::SLLI; + unsigned SRLOpc = Subtarget->is64Bit() ? RISCV::SRLIW : RISCV::SRLI; + SDNode *SLLI = + CurDAG->getMachineNode(SLLOpc, DL, VT, N0->getOperand(0), + CurDAG->getTargetConstant(16, DL, VT)); + SDNode *SRLI = CurDAG->getMachineNode( + SRLOpc, DL, VT, SDValue(SLLI, 0), + CurDAG->getTargetConstant(16 + ShAmt, DL, VT)); + ReplaceNode(Node, SRLI); + return; + } + } + } + + break; + } case ISD::INTRINSIC_W_CHAIN: { unsigned IntNo = cast(Node->getOperand(1))->getZExtValue(); switch (IntNo) { diff --git a/llvm/test/CodeGen/RISCV/alu16.ll b/llvm/test/CodeGen/RISCV/alu16.ll --- a/llvm/test/CodeGen/RISCV/alu16.ll +++ b/llvm/test/CodeGen/RISCV/alu16.ll @@ -121,18 +121,14 @@ define i16 @srli(i16 %a) nounwind { ; RV32I-LABEL: srli: ; RV32I: # %bb.0: -; RV32I-NEXT: lui a1, 16 -; RV32I-NEXT: addi a1, a1, -64 -; RV32I-NEXT: and a0, a0, a1 -; RV32I-NEXT: srli a0, a0, 6 +; RV32I-NEXT: slli a0, a0, 16 +; RV32I-NEXT: srli a0, a0, 22 ; RV32I-NEXT: ret ; ; RV64I-LABEL: srli: ; RV64I: # %bb.0: -; RV64I-NEXT: lui a1, 16 -; RV64I-NEXT: addiw a1, a1, -64 -; RV64I-NEXT: and a0, a0, a1 -; RV64I-NEXT: srli a0, a0, 6 +; RV64I-NEXT: slliw a0, a0, 16 +; RV64I-NEXT: srliw a0, a0, 22 ; RV64I-NEXT: ret %1 = lshr i16 %a, 6 ret i16 %1 diff --git a/llvm/test/CodeGen/RISCV/bswap-ctlz-cttz-ctpop.ll b/llvm/test/CodeGen/RISCV/bswap-ctlz-cttz-ctpop.ll --- a/llvm/test/CodeGen/RISCV/bswap-ctlz-cttz-ctpop.ll +++ b/llvm/test/CodeGen/RISCV/bswap-ctlz-cttz-ctpop.ll @@ -17,22 +17,18 @@ define i16 @test_bswap_i16(i16 %a) nounwind { ; RV32I-LABEL: test_bswap_i16: ; RV32I: # %bb.0: -; RV32I-NEXT: lui a1, 16 -; RV32I-NEXT: addi a1, a1, -256 -; RV32I-NEXT: and a1, a0, a1 -; RV32I-NEXT: srli a1, a1, 8 -; RV32I-NEXT: slli a0, a0, 8 -; RV32I-NEXT: or a0, a0, a1 +; RV32I-NEXT: slli a1, a0, 8 +; RV32I-NEXT: slli a0, a0, 16 +; RV32I-NEXT: srli a0, a0, 24 +; RV32I-NEXT: or a0, a1, a0 ; RV32I-NEXT: ret ; ; RV64I-LABEL: test_bswap_i16: ; RV64I: # %bb.0: -; RV64I-NEXT: lui a1, 16 -; RV64I-NEXT: addiw a1, a1, -256 -; RV64I-NEXT: and a1, a0, a1 -; RV64I-NEXT: srli a1, a1, 8 -; RV64I-NEXT: slli a0, a0, 8 -; RV64I-NEXT: or a0, a0, a1 +; RV64I-NEXT: slli a1, a0, 8 +; RV64I-NEXT: slliw a0, a0, 16 +; RV64I-NEXT: srliw a0, a0, 24 +; RV64I-NEXT: or a0, a1, a0 ; RV64I-NEXT: ret %tmp = call i16 @llvm.bswap.i16(i16 %a) ret i16 %tmp