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 @@ -6216,8 +6216,53 @@ return SDValue(); } +// Transform (add (mul x, c0), c1) -> +// (add (mul (add x, c1/c0), c0), c1%c0). +// if c1/c0 and c1%c0 are simm12, while c1 is not. +// Or transform (add (mul x, c0), c1) -> +// (mul (add x, c1/c0), c0). +// if c1%c0 is zero, and c1/c0 is simm12 while c1 is not. +static SDValue transformAddImmMulImm(SDNode *N, SelectionDAG &DAG, + const RISCVSubtarget &Subtarget) { + // Skip for vector types and larger types. + EVT VT = N->getValueType(0); + if (VT.isVector() || VT.getSizeInBits() > Subtarget.getXLen()) + return SDValue(); + // The first operand node must be a MUL and has no other use. + SDValue N0 = N->getOperand(0); + if (!N0->hasOneUse() || N0->getOpcode() != ISD::MUL) + return SDValue(); + // Check if c0 and c1 match above conditions. + auto *N0C = dyn_cast(N0->getOperand(1)); + auto *N1C = dyn_cast(N->getOperand(1)); + if (!N0C || !N1C) + return SDValue(); + int64_t C0 = N0C->getSExtValue(); + int64_t C1 = N1C->getSExtValue(); + if (C0 == -1 || C0 == 0 || C0 == 1 || (C1 / C0) == 0 || isInt<12>(C1) || + !isInt<12>(C1 % C0) || !isInt<12>(C1 / C0)) + return SDValue(); + // Build new nodes (add (mul (add x, c1/c0), c0), c1%c0). + SDLoc DL(N); + SDValue New0 = DAG.getNode(ISD::ADD, DL, VT, N0->getOperand(0), + DAG.getConstant(C1 / C0, DL, VT)); + SDValue New1 = + DAG.getNode(ISD::MUL, DL, VT, New0, DAG.getConstant(C0, DL, VT)); + if ((C1 % C0) == 0) + return New1; + return DAG.getNode(ISD::ADD, DL, VT, New1, DAG.getConstant(C1 % C0, DL, VT)); +} + static SDValue performADDCombine(SDNode *N, SelectionDAG &DAG, const RISCVSubtarget &Subtarget) { + // Transform (add (mul x, c0), c1) -> + // (add (mul (add x, c1/c0), c0), c1%c0). + // if c1/c0 and c1%c0 are simm12, while c1 is not. + // Or transform (add (mul x, c0), c1) -> + // (mul (add x, c1/c0), c0). + // if c1%c0 is zero, and c1/c0 is simm12 while c1 is not. + if (SDValue V = transformAddImmMulImm(N, DAG, Subtarget)) + return V; // Fold (add (shl x, c0), (shl y, c1)) -> // (SLLI (SH*ADD x, y), c0), if c1-c0 equals to [1|2|3]. if (SDValue V = transformAddShlImm(N, DAG, Subtarget)) diff --git a/llvm/test/CodeGen/RISCV/addimm-mulimm.ll b/llvm/test/CodeGen/RISCV/addimm-mulimm.ll --- a/llvm/test/CodeGen/RISCV/addimm-mulimm.ll +++ b/llvm/test/CodeGen/RISCV/addimm-mulimm.ll @@ -342,20 +342,16 @@ define i32 @add_mul_combine_reject_e1(i32 %x) { ; RV32IMB-LABEL: add_mul_combine_reject_e1: ; RV32IMB: # %bb.0: +; RV32IMB-NEXT: addi a0, a0, 1971 ; RV32IMB-NEXT: addi a1, zero, 29 ; RV32IMB-NEXT: mul a0, a0, a1 -; RV32IMB-NEXT: lui a1, 14 -; RV32IMB-NEXT: addi a1, a1, -185 -; RV32IMB-NEXT: add a0, a0, a1 ; RV32IMB-NEXT: ret ; ; RV64IMB-LABEL: add_mul_combine_reject_e1: ; RV64IMB: # %bb.0: +; RV64IMB-NEXT: addiw a0, a0, 1971 ; RV64IMB-NEXT: addi a1, zero, 29 ; RV64IMB-NEXT: mulw a0, a0, a1 -; RV64IMB-NEXT: lui a1, 14 -; RV64IMB-NEXT: addiw a1, a1, -185 -; RV64IMB-NEXT: addw a0, a0, a1 ; RV64IMB-NEXT: ret %tmp0 = mul i32 %x, 29 %tmp1 = add i32 %tmp0, 57159 @@ -365,20 +361,16 @@ define signext i32 @add_mul_combine_reject_e2(i32 signext %x) { ; RV32IMB-LABEL: add_mul_combine_reject_e2: ; RV32IMB: # %bb.0: +; RV32IMB-NEXT: addi a0, a0, 1971 ; RV32IMB-NEXT: addi a1, zero, 29 ; RV32IMB-NEXT: mul a0, a0, a1 -; RV32IMB-NEXT: lui a1, 14 -; RV32IMB-NEXT: addi a1, a1, -185 -; RV32IMB-NEXT: add a0, a0, a1 ; RV32IMB-NEXT: ret ; ; RV64IMB-LABEL: add_mul_combine_reject_e2: ; RV64IMB: # %bb.0: +; RV64IMB-NEXT: addiw a0, a0, 1971 ; RV64IMB-NEXT: addi a1, zero, 29 ; RV64IMB-NEXT: mulw a0, a0, a1 -; RV64IMB-NEXT: lui a1, 14 -; RV64IMB-NEXT: addiw a1, a1, -185 -; RV64IMB-NEXT: addw a0, a0, a1 ; RV64IMB-NEXT: ret %tmp0 = mul i32 %x, 29 %tmp1 = add i32 %tmp0, 57159 @@ -402,11 +394,9 @@ ; ; RV64IMB-LABEL: add_mul_combine_reject_e3: ; RV64IMB: # %bb.0: +; RV64IMB-NEXT: addi a0, a0, 1971 ; RV64IMB-NEXT: addi a1, zero, 29 ; RV64IMB-NEXT: mul a0, a0, a1 -; RV64IMB-NEXT: lui a1, 14 -; RV64IMB-NEXT: addiw a1, a1, -185 -; RV64IMB-NEXT: add a0, a0, a1 ; RV64IMB-NEXT: ret %tmp0 = mul i64 %x, 29 %tmp1 = add i64 %tmp0, 57159 @@ -416,20 +406,18 @@ define i32 @add_mul_combine_reject_f1(i32 %x) { ; RV32IMB-LABEL: add_mul_combine_reject_f1: ; RV32IMB: # %bb.0: +; RV32IMB-NEXT: addi a0, a0, 1972 ; RV32IMB-NEXT: addi a1, zero, 29 ; RV32IMB-NEXT: mul a0, a0, a1 -; RV32IMB-NEXT: lui a1, 14 -; RV32IMB-NEXT: addi a1, a1, -145 -; RV32IMB-NEXT: add a0, a0, a1 +; RV32IMB-NEXT: addi a0, a0, 11 ; RV32IMB-NEXT: ret ; ; RV64IMB-LABEL: add_mul_combine_reject_f1: ; RV64IMB: # %bb.0: +; RV64IMB-NEXT: addiw a0, a0, 1972 ; RV64IMB-NEXT: addi a1, zero, 29 ; RV64IMB-NEXT: mulw a0, a0, a1 -; RV64IMB-NEXT: lui a1, 14 -; RV64IMB-NEXT: addiw a1, a1, -145 -; RV64IMB-NEXT: addw a0, a0, a1 +; RV64IMB-NEXT: addiw a0, a0, 11 ; RV64IMB-NEXT: ret %tmp0 = mul i32 %x, 29 %tmp1 = add i32 %tmp0, 57199 @@ -439,20 +427,18 @@ define signext i32 @add_mul_combine_reject_f2(i32 signext %x) { ; RV32IMB-LABEL: add_mul_combine_reject_f2: ; RV32IMB: # %bb.0: +; RV32IMB-NEXT: addi a0, a0, 1972 ; RV32IMB-NEXT: addi a1, zero, 29 ; RV32IMB-NEXT: mul a0, a0, a1 -; RV32IMB-NEXT: lui a1, 14 -; RV32IMB-NEXT: addi a1, a1, -145 -; RV32IMB-NEXT: add a0, a0, a1 +; RV32IMB-NEXT: addi a0, a0, 11 ; RV32IMB-NEXT: ret ; ; RV64IMB-LABEL: add_mul_combine_reject_f2: ; RV64IMB: # %bb.0: +; RV64IMB-NEXT: addiw a0, a0, 1972 ; RV64IMB-NEXT: addi a1, zero, 29 ; RV64IMB-NEXT: mulw a0, a0, a1 -; RV64IMB-NEXT: lui a1, 14 -; RV64IMB-NEXT: addiw a1, a1, -145 -; RV64IMB-NEXT: addw a0, a0, a1 +; RV64IMB-NEXT: addiw a0, a0, 11 ; RV64IMB-NEXT: ret %tmp0 = mul i32 %x, 29 %tmp1 = add i32 %tmp0, 57199 @@ -476,11 +462,10 @@ ; ; RV64IMB-LABEL: add_mul_combine_reject_f3: ; RV64IMB: # %bb.0: +; RV64IMB-NEXT: addi a0, a0, 1972 ; RV64IMB-NEXT: addi a1, zero, 29 ; RV64IMB-NEXT: mul a0, a0, a1 -; RV64IMB-NEXT: lui a1, 14 -; RV64IMB-NEXT: addiw a1, a1, -145 -; RV64IMB-NEXT: add a0, a0, a1 +; RV64IMB-NEXT: addi a0, a0, 11 ; RV64IMB-NEXT: ret %tmp0 = mul i64 %x, 29 %tmp1 = add i64 %tmp0, 57199 @@ -490,20 +475,18 @@ define i32 @add_mul_combine_reject_g1(i32 %x) { ; RV32IMB-LABEL: add_mul_combine_reject_g1: ; RV32IMB: # %bb.0: +; RV32IMB-NEXT: addi a0, a0, 100 ; RV32IMB-NEXT: sh3add a1, a0, a0 ; RV32IMB-NEXT: sh3add a0, a1, a0 -; RV32IMB-NEXT: lui a1, 2 -; RV32IMB-NEXT: addi a1, a1, -882 -; RV32IMB-NEXT: add a0, a0, a1 +; RV32IMB-NEXT: addi a0, a0, 10 ; RV32IMB-NEXT: ret ; ; RV64IMB-LABEL: add_mul_combine_reject_g1: ; RV64IMB: # %bb.0: +; RV64IMB-NEXT: addi a0, a0, 100 ; RV64IMB-NEXT: sh3add a1, a0, a0 ; RV64IMB-NEXT: sh3add a0, a1, a0 -; RV64IMB-NEXT: lui a1, 2 -; RV64IMB-NEXT: addiw a1, a1, -882 -; RV64IMB-NEXT: addw a0, a0, a1 +; RV64IMB-NEXT: addiw a0, a0, 10 ; RV64IMB-NEXT: ret %tmp0 = mul i32 %x, 73 %tmp1 = add i32 %tmp0, 7310 @@ -513,20 +496,18 @@ define signext i32 @add_mul_combine_reject_g2(i32 signext %x) { ; RV32IMB-LABEL: add_mul_combine_reject_g2: ; RV32IMB: # %bb.0: +; RV32IMB-NEXT: addi a0, a0, 100 ; RV32IMB-NEXT: sh3add a1, a0, a0 ; RV32IMB-NEXT: sh3add a0, a1, a0 -; RV32IMB-NEXT: lui a1, 2 -; RV32IMB-NEXT: addi a1, a1, -882 -; RV32IMB-NEXT: add a0, a0, a1 +; RV32IMB-NEXT: addi a0, a0, 10 ; RV32IMB-NEXT: ret ; ; RV64IMB-LABEL: add_mul_combine_reject_g2: ; RV64IMB: # %bb.0: +; RV64IMB-NEXT: addi a0, a0, 100 ; RV64IMB-NEXT: sh3add a1, a0, a0 ; RV64IMB-NEXT: sh3add a0, a1, a0 -; RV64IMB-NEXT: lui a1, 2 -; RV64IMB-NEXT: addiw a1, a1, -882 -; RV64IMB-NEXT: addw a0, a0, a1 +; RV64IMB-NEXT: addiw a0, a0, 10 ; RV64IMB-NEXT: ret %tmp0 = mul i32 %x, 73 %tmp1 = add i32 %tmp0, 7310 @@ -550,11 +531,10 @@ ; ; RV64IMB-LABEL: add_mul_combine_reject_g3: ; RV64IMB: # %bb.0: +; RV64IMB-NEXT: addi a0, a0, 100 ; RV64IMB-NEXT: sh3add a1, a0, a0 ; RV64IMB-NEXT: sh3add a0, a1, a0 -; RV64IMB-NEXT: lui a1, 2 -; RV64IMB-NEXT: addiw a1, a1, -882 -; RV64IMB-NEXT: add a0, a0, a1 +; RV64IMB-NEXT: addi a0, a0, 10 ; RV64IMB-NEXT: ret %tmp0 = mul i64 %x, 73 %tmp1 = add i64 %tmp0, 7310