Index: llvm/lib/Target/RISCV/RISCVISelDAGToDAG.cpp =================================================================== --- llvm/lib/Target/RISCV/RISCVISelDAGToDAG.cpp +++ llvm/lib/Target/RISCV/RISCVISelDAGToDAG.cpp @@ -74,6 +74,49 @@ EVT VT = Node->getValueType(0); switch (Opcode) { + // Optimize the node (mul r, imm) to below pattern if possible. + // (mul r, imm) -> (add (shl r, log2(imm-1)), r) + // (mul r, imm) -> (sub (shl r, log2(imm+1)), r) + case ISD::MUL: { + // The second operand must be an immediate. + if (auto *ConstOp = dyn_cast(Node->getOperand(1))) { + uint32_t Shift = 0; + unsigned Opc; + if (!Subtarget->is64Bit()) { // Calculate Opc/Shift for riscv32. + uint32_t Imm = ConstOp->getZExtValue(); + if (isPowerOf2_32(Imm + 1)) { + Opc = RISCV::SUB; + Shift = Log2_32(Imm + 1); + } else if (isPowerOf2_32(Imm - 1)) { + Opc = RISCV::ADD; + Shift = Log2_32(Imm - 1); + } + } else { // Calculate Opc/Shift for riscv64. + uint64_t Imm = ConstOp->getZExtValue(); + if (isPowerOf2_64(Imm + 1)) { + Opc = RISCV::SUB; + Shift = Log2_64(Imm + 1); + } else if (isPowerOf2_64(Imm - 1)) { + Opc = RISCV::ADD; + Shift = Log2_64(Imm - 1); + } + } + // Build the optimized DAG if applicable. + if (Shift > 0) { + SDLoc DL(Node); + EVT VT = Node->getValueType(0); + SDValue ShiftOp = CurDAG->getTargetConstant(Shift, DL, VT); + auto *NodeShl = CurDAG->getMachineNode(RISCV::SLLI, DL, VT, + Node->getOperand(0), ShiftOp); + auto *NodeAddSub = CurDAG->getMachineNode(Opc, DL, VT, + SDValue(NodeShl, 0), + Node->getOperand(0)); + ReplaceNode(Node, NodeAddSub); + return; + } + } + break; + } case ISD::Constant: { auto ConstNode = cast(Node); if (VT == XLenVT && ConstNode->isNullValue()) { Index: llvm/test/CodeGen/RISCV/mul.ll =================================================================== --- llvm/test/CodeGen/RISCV/mul.ll +++ llvm/test/CodeGen/RISCV/mul.ll @@ -89,8 +89,8 @@ ; ; RV32IM-LABEL: mul_constant: ; RV32IM: # %bb.0: -; RV32IM-NEXT: addi a1, zero, 5 -; RV32IM-NEXT: mul a0, a0, a1 +; RV32IM-NEXT: slli a1, a0, 2 +; RV32IM-NEXT: add a0, a1, a0 ; RV32IM-NEXT: ret ; ; RV64I-LABEL: mul_constant: @@ -189,10 +189,12 @@ ; RV32IM-LABEL: mul64_constant: ; RV32IM: # %bb.0: ; RV32IM-NEXT: addi a2, zero, 5 -; RV32IM-NEXT: mul a1, a1, a2 -; RV32IM-NEXT: mulhu a3, a0, a2 +; RV32IM-NEXT: mulhu a2, a0, a2 +; RV32IM-NEXT: slli a3, a1, 2 ; RV32IM-NEXT: add a1, a3, a1 -; RV32IM-NEXT: mul a0, a0, a2 +; RV32IM-NEXT: add a1, a2, a1 +; RV32IM-NEXT: slli a2, a0, 2 +; RV32IM-NEXT: add a0, a2, a0 ; RV32IM-NEXT: ret ; ; RV64I-LABEL: mul64_constant: @@ -207,8 +209,8 @@ ; ; RV64IM-LABEL: mul64_constant: ; RV64IM: # %bb.0: -; RV64IM-NEXT: addi a1, zero, 5 -; RV64IM-NEXT: mul a0, a0, a1 +; RV64IM-NEXT: slli a1, a0, 2 +; RV64IM-NEXT: add a0, a1, a0 ; RV64IM-NEXT: ret %1 = mul i64 %a, 5 ret i64 %1 @@ -301,3 +303,77 @@ %5 = trunc i64 %4 to i32 ret i32 %5 } + +define i32 @muli32_65(i32 %a) nounwind { +; RV32IM-LABEL: muli32_65: +; RV32IM: # %bb.0: +; RV32IM-NEXT: slli a1, a0, 6 +; RV32IM-NEXT: add a0, a1, a0 +; RV32IM-NEXT: ret +; +; RV64IM-LABEL: muli32_65: +; RV64IM: # %bb.0: +; RV64IM-NEXT: slli a1, a0, 6 +; RV64IM-NEXT: add a0, a1, a0 +; RV64IM-NEXT: ret + %1 = mul i32 %a, 65 + ret i32 %1 +} + +define i32 @muli32_63(i32 %a) nounwind { +; RV32IM-LABEL: muli32_63: +; RV32IM: # %bb.0: +; RV32IM-NEXT: slli a1, a0, 6 +; RV32IM-NEXT: sub a0, a1, a0 +; RV32IM-NEXT: ret +; +; RV64IM-LABEL: muli32_63: +; RV64IM: # %bb.0: +; RV64IM-NEXT: slli a1, a0, 6 +; RV64IM-NEXT: sub a0, a1, a0 +; RV64IM-NEXT: ret + %1 = mul i32 %a, 63 + ret i32 %1 +} + +define i64 @muli64_65(i64 %a) nounwind { +; RV32IM-LABEL: muli64_65: +; RV32IM: # %bb.0: +; RV32IM-NEXT: addi a2, zero, 65 +; RV32IM-NEXT: mulhu a2, a0, a2 +; RV32IM-NEXT: slli a3, a1, 6 +; RV32IM-NEXT: add a1, a3, a1 +; RV32IM-NEXT: add a1, a2, a1 +; RV32IM-NEXT: slli a2, a0, 6 +; RV32IM-NEXT: add a0, a2, a0 +; RV32IM-NEXT: ret +; +; RV64IM-LABEL: muli64_65: +; RV64IM: # %bb.0: +; RV64IM-NEXT: slli a1, a0, 6 +; RV64IM-NEXT: add a0, a1, a0 +; RV64IM-NEXT: ret + %1 = mul i64 %a, 65 + ret i64 %1 +} + +define i64 @muli64_63(i64 %a) nounwind { +; RV32IM-LABEL: muli64_63: +; RV32IM: # %bb.0: +; RV32IM-NEXT: addi a2, zero, 63 +; RV32IM-NEXT: mulhu a2, a0, a2 +; RV32IM-NEXT: slli a3, a1, 6 +; RV32IM-NEXT: sub a1, a3, a1 +; RV32IM-NEXT: add a1, a2, a1 +; RV32IM-NEXT: slli a2, a0, 6 +; RV32IM-NEXT: sub a0, a2, a0 +; RV32IM-NEXT: ret +; +; RV64IM-LABEL: muli64_63: +; RV64IM: # %bb.0: +; RV64IM-NEXT: slli a1, a0, 6 +; RV64IM-NEXT: sub a0, a1, a0 +; RV64IM-NEXT: ret + %1 = mul i64 %a, 63 + ret i64 %1 +}