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 @@ -6439,7 +6439,19 @@ // 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. +// if c1/c0 and c1%c0 are simm12, while c1 is not. A special corner case +// that should be excluded is when c0*(c1/c0) is simm12, which will lead +// to an infinite loop in DAGCombine if transformed. +// Or transform (add (mul x, c0), c1) -> +// (add (mul (add x, c1/c0+1), c0), c1%c0-c0), +// if c1/c0+1 and c1%c0-c0 are simm12, while c1 is not. A special corner +// case that should be excluded is when c0*(c1/c0+1) is simm12, which will +// lead to an infinite loop in DAGCombine if transformed. +// Or transform (add (mul x, c0), c1) -> +// (add (mul (add x, c1/c0-1), c0), c1%c0+c0), +// if c1/c0-1 and c1%c0+c0 are simm12, while c1 is not. A special corner +// case that should be excluded is when c0*(c1/c0-1) is simm12, which will +// lead to an infinite loop in DAGCombine if transformed. // 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. @@ -6460,35 +6472,37 @@ 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)) + int64_t CA, CB; + if (C0 == -1 || C0 == 0 || C0 == 1 || isInt<12>(C1)) return SDValue(); - // If C0 * (C1 / C0) is a 12-bit integer, this transform will be reversed. - if (isInt<12>(C0 * (C1 / C0))) + // Search for proper CA (non-zero) and CB that both are simm12. + if ((C1 / C0) != 0 && isInt<12>(C1 / C0) && isInt<12>(C1 % C0) && + !isInt<12>(C0 * (C1 / C0))) { + CA = C1 / C0; + CB = C1 % C0; + } else if ((C1 / C0 + 1) != 0 && isInt<12>(C1 / C0 + 1) && + isInt<12>(C1 % C0 - C0) && !isInt<12>(C0 * (C1 / C0 + 1))) { + CA = C1 / C0 + 1; + CB = C1 % C0 - C0; + } else if ((C1 / C0 - 1) != 0 && isInt<12>(C1 / C0 - 1) && + isInt<12>(C1 % C0 + C0) && !isInt<12>(C0 * (C1 / C0 - 1))) { + CA = C1 / C0 - 1; + CB = C1 % C0 + C0; + } else 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)); + DAG.getConstant(CA, 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)); + return DAG.getNode(ISD::ADD, DL, VT, New1, DAG.getConstant(CB, 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)) return V; // fold (add (select lhs, rhs, cc, 0, y), x) -> 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 @@ -559,9 +559,9 @@ ; ; RV64IMB-LABEL: add_mul_combine_infinite_loop: ; RV64IMB: # %bb.0: +; RV64IMB-NEXT: addi a0, a0, 86 ; RV64IMB-NEXT: sh1add a0, a0, a0 -; RV64IMB-NEXT: lui a1, 1 -; RV64IMB-NEXT: addiw a1, a1, -2048 +; RV64IMB-NEXT: addi a1, zero, -16 ; RV64IMB-NEXT: sh3add a0, a0, a1 ; RV64IMB-NEXT: ret %tmp0 = mul i64 %x, 24 @@ -572,22 +572,20 @@ define i32 @mul3000_add8990_a(i32 %x) { ; RV32IMB-LABEL: mul3000_add8990_a: ; RV32IMB: # %bb.0: +; RV32IMB-NEXT: addi a0, a0, 3 ; RV32IMB-NEXT: lui a1, 1 ; RV32IMB-NEXT: addi a1, a1, -1096 ; RV32IMB-NEXT: mul a0, a0, a1 -; RV32IMB-NEXT: lui a1, 2 -; RV32IMB-NEXT: addi a1, a1, 798 -; RV32IMB-NEXT: add a0, a0, a1 +; RV32IMB-NEXT: addi a0, a0, -10 ; RV32IMB-NEXT: ret ; ; RV64IMB-LABEL: mul3000_add8990_a: ; RV64IMB: # %bb.0: +; RV64IMB-NEXT: addiw a0, a0, 3 ; RV64IMB-NEXT: lui a1, 1 ; RV64IMB-NEXT: addiw a1, a1, -1096 ; RV64IMB-NEXT: mulw a0, a0, a1 -; RV64IMB-NEXT: lui a1, 2 -; RV64IMB-NEXT: addiw a1, a1, 798 -; RV64IMB-NEXT: addw a0, a0, a1 +; RV64IMB-NEXT: addiw a0, a0, -10 ; RV64IMB-NEXT: ret %tmp0 = mul i32 %x, 3000 %tmp1 = add i32 %tmp0, 8990 @@ -597,22 +595,20 @@ define signext i32 @mul3000_add8990_b(i32 signext %x) { ; RV32IMB-LABEL: mul3000_add8990_b: ; RV32IMB: # %bb.0: +; RV32IMB-NEXT: addi a0, a0, 3 ; RV32IMB-NEXT: lui a1, 1 ; RV32IMB-NEXT: addi a1, a1, -1096 ; RV32IMB-NEXT: mul a0, a0, a1 -; RV32IMB-NEXT: lui a1, 2 -; RV32IMB-NEXT: addi a1, a1, 798 -; RV32IMB-NEXT: add a0, a0, a1 +; RV32IMB-NEXT: addi a0, a0, -10 ; RV32IMB-NEXT: ret ; ; RV64IMB-LABEL: mul3000_add8990_b: ; RV64IMB: # %bb.0: +; RV64IMB-NEXT: addiw a0, a0, 3 ; RV64IMB-NEXT: lui a1, 1 ; RV64IMB-NEXT: addiw a1, a1, -1096 ; RV64IMB-NEXT: mulw a0, a0, a1 -; RV64IMB-NEXT: lui a1, 2 -; RV64IMB-NEXT: addiw a1, a1, 798 -; RV64IMB-NEXT: addw a0, a0, a1 +; RV64IMB-NEXT: addiw a0, a0, -10 ; RV64IMB-NEXT: ret %tmp0 = mul i32 %x, 3000 %tmp1 = add i32 %tmp0, 8990 @@ -637,12 +633,11 @@ ; ; RV64IMB-LABEL: mul3000_add8990_c: ; RV64IMB: # %bb.0: +; RV64IMB-NEXT: addi a0, a0, 3 ; RV64IMB-NEXT: lui a1, 1 ; RV64IMB-NEXT: addiw a1, a1, -1096 ; RV64IMB-NEXT: mul a0, a0, a1 -; RV64IMB-NEXT: lui a1, 2 -; RV64IMB-NEXT: addiw a1, a1, 798 -; RV64IMB-NEXT: add a0, a0, a1 +; RV64IMB-NEXT: addi a0, a0, -10 ; RV64IMB-NEXT: ret %tmp0 = mul i64 %x, 3000 %tmp1 = add i64 %tmp0, 8990 @@ -652,22 +647,20 @@ define i32 @mul3000_sub8990_a(i32 %x) { ; RV32IMB-LABEL: mul3000_sub8990_a: ; RV32IMB: # %bb.0: +; RV32IMB-NEXT: addi a0, a0, -3 ; RV32IMB-NEXT: lui a1, 1 ; RV32IMB-NEXT: addi a1, a1, -1096 ; RV32IMB-NEXT: mul a0, a0, a1 -; RV32IMB-NEXT: lui a1, 1048574 -; RV32IMB-NEXT: addi a1, a1, -798 -; RV32IMB-NEXT: add a0, a0, a1 +; RV32IMB-NEXT: addi a0, a0, 10 ; RV32IMB-NEXT: ret ; ; RV64IMB-LABEL: mul3000_sub8990_a: ; RV64IMB: # %bb.0: +; RV64IMB-NEXT: addiw a0, a0, -3 ; RV64IMB-NEXT: lui a1, 1 ; RV64IMB-NEXT: addiw a1, a1, -1096 ; RV64IMB-NEXT: mulw a0, a0, a1 -; RV64IMB-NEXT: lui a1, 1048574 -; RV64IMB-NEXT: addiw a1, a1, -798 -; RV64IMB-NEXT: addw a0, a0, a1 +; RV64IMB-NEXT: addiw a0, a0, 10 ; RV64IMB-NEXT: ret %tmp0 = mul i32 %x, 3000 %tmp1 = add i32 %tmp0, -8990 @@ -677,22 +670,20 @@ define signext i32 @mul3000_sub8990_b(i32 signext %x) { ; RV32IMB-LABEL: mul3000_sub8990_b: ; RV32IMB: # %bb.0: +; RV32IMB-NEXT: addi a0, a0, -3 ; RV32IMB-NEXT: lui a1, 1 ; RV32IMB-NEXT: addi a1, a1, -1096 ; RV32IMB-NEXT: mul a0, a0, a1 -; RV32IMB-NEXT: lui a1, 1048574 -; RV32IMB-NEXT: addi a1, a1, -798 -; RV32IMB-NEXT: add a0, a0, a1 +; RV32IMB-NEXT: addi a0, a0, 10 ; RV32IMB-NEXT: ret ; ; RV64IMB-LABEL: mul3000_sub8990_b: ; RV64IMB: # %bb.0: +; RV64IMB-NEXT: addiw a0, a0, -3 ; RV64IMB-NEXT: lui a1, 1 ; RV64IMB-NEXT: addiw a1, a1, -1096 ; RV64IMB-NEXT: mulw a0, a0, a1 -; RV64IMB-NEXT: lui a1, 1048574 -; RV64IMB-NEXT: addiw a1, a1, -798 -; RV64IMB-NEXT: addw a0, a0, a1 +; RV64IMB-NEXT: addiw a0, a0, 10 ; RV64IMB-NEXT: ret %tmp0 = mul i32 %x, 3000 %tmp1 = add i32 %tmp0, -8990 @@ -718,12 +709,11 @@ ; ; RV64IMB-LABEL: mul3000_sub8990_c: ; RV64IMB: # %bb.0: +; RV64IMB-NEXT: addi a0, a0, -3 ; RV64IMB-NEXT: lui a1, 1 ; RV64IMB-NEXT: addiw a1, a1, -1096 ; RV64IMB-NEXT: mul a0, a0, a1 -; RV64IMB-NEXT: lui a1, 1048574 -; RV64IMB-NEXT: addiw a1, a1, -798 -; RV64IMB-NEXT: add a0, a0, a1 +; RV64IMB-NEXT: addi a0, a0, 10 ; RV64IMB-NEXT: ret %tmp0 = mul i64 %x, 3000 %tmp1 = add i64 %tmp0, -8990 @@ -733,22 +723,20 @@ define i32 @mulneg3000_add8990_a(i32 %x) { ; RV32IMB-LABEL: mulneg3000_add8990_a: ; RV32IMB: # %bb.0: +; RV32IMB-NEXT: addi a0, a0, -3 ; RV32IMB-NEXT: lui a1, 1048575 ; RV32IMB-NEXT: addi a1, a1, 1096 ; RV32IMB-NEXT: mul a0, a0, a1 -; RV32IMB-NEXT: lui a1, 2 -; RV32IMB-NEXT: addi a1, a1, 798 -; RV32IMB-NEXT: add a0, a0, a1 +; RV32IMB-NEXT: addi a0, a0, -10 ; RV32IMB-NEXT: ret ; ; RV64IMB-LABEL: mulneg3000_add8990_a: ; RV64IMB: # %bb.0: +; RV64IMB-NEXT: addiw a0, a0, -3 ; RV64IMB-NEXT: lui a1, 1048575 ; RV64IMB-NEXT: addiw a1, a1, 1096 ; RV64IMB-NEXT: mulw a0, a0, a1 -; RV64IMB-NEXT: lui a1, 2 -; RV64IMB-NEXT: addiw a1, a1, 798 -; RV64IMB-NEXT: addw a0, a0, a1 +; RV64IMB-NEXT: addiw a0, a0, -10 ; RV64IMB-NEXT: ret %tmp0 = mul i32 %x, -3000 %tmp1 = add i32 %tmp0, 8990 @@ -758,22 +746,20 @@ define signext i32 @mulneg3000_add8990_b(i32 signext %x) { ; RV32IMB-LABEL: mulneg3000_add8990_b: ; RV32IMB: # %bb.0: +; RV32IMB-NEXT: addi a0, a0, -3 ; RV32IMB-NEXT: lui a1, 1048575 ; RV32IMB-NEXT: addi a1, a1, 1096 ; RV32IMB-NEXT: mul a0, a0, a1 -; RV32IMB-NEXT: lui a1, 2 -; RV32IMB-NEXT: addi a1, a1, 798 -; RV32IMB-NEXT: add a0, a0, a1 +; RV32IMB-NEXT: addi a0, a0, -10 ; RV32IMB-NEXT: ret ; ; RV64IMB-LABEL: mulneg3000_add8990_b: ; RV64IMB: # %bb.0: +; RV64IMB-NEXT: addiw a0, a0, -3 ; RV64IMB-NEXT: lui a1, 1048575 ; RV64IMB-NEXT: addiw a1, a1, 1096 ; RV64IMB-NEXT: mulw a0, a0, a1 -; RV64IMB-NEXT: lui a1, 2 -; RV64IMB-NEXT: addiw a1, a1, 798 -; RV64IMB-NEXT: addw a0, a0, a1 +; RV64IMB-NEXT: addiw a0, a0, -10 ; RV64IMB-NEXT: ret %tmp0 = mul i32 %x, -3000 %tmp1 = add i32 %tmp0, 8990 @@ -799,12 +785,11 @@ ; ; RV64IMB-LABEL: mulneg3000_add8990_c: ; RV64IMB: # %bb.0: +; RV64IMB-NEXT: addi a0, a0, -3 ; RV64IMB-NEXT: lui a1, 1048575 ; RV64IMB-NEXT: addiw a1, a1, 1096 ; RV64IMB-NEXT: mul a0, a0, a1 -; RV64IMB-NEXT: lui a1, 2 -; RV64IMB-NEXT: addiw a1, a1, 798 -; RV64IMB-NEXT: add a0, a0, a1 +; RV64IMB-NEXT: addi a0, a0, -10 ; RV64IMB-NEXT: ret %tmp0 = mul i64 %x, -3000 %tmp1 = add i64 %tmp0, 8990 @@ -814,22 +799,20 @@ define i32 @mulneg3000_sub8990_a(i32 %x) { ; RV32IMB-LABEL: mulneg3000_sub8990_a: ; RV32IMB: # %bb.0: +; RV32IMB-NEXT: addi a0, a0, 3 ; RV32IMB-NEXT: lui a1, 1048575 ; RV32IMB-NEXT: addi a1, a1, 1096 ; RV32IMB-NEXT: mul a0, a0, a1 -; RV32IMB-NEXT: lui a1, 1048574 -; RV32IMB-NEXT: addi a1, a1, -798 -; RV32IMB-NEXT: add a0, a0, a1 +; RV32IMB-NEXT: addi a0, a0, 10 ; RV32IMB-NEXT: ret ; ; RV64IMB-LABEL: mulneg3000_sub8990_a: ; RV64IMB: # %bb.0: +; RV64IMB-NEXT: addiw a0, a0, 3 ; RV64IMB-NEXT: lui a1, 1048575 ; RV64IMB-NEXT: addiw a1, a1, 1096 ; RV64IMB-NEXT: mulw a0, a0, a1 -; RV64IMB-NEXT: lui a1, 1048574 -; RV64IMB-NEXT: addiw a1, a1, -798 -; RV64IMB-NEXT: addw a0, a0, a1 +; RV64IMB-NEXT: addiw a0, a0, 10 ; RV64IMB-NEXT: ret %tmp0 = mul i32 %x, -3000 %tmp1 = add i32 %tmp0, -8990 @@ -839,22 +822,20 @@ define signext i32 @mulneg3000_sub8990_b(i32 signext %x) { ; RV32IMB-LABEL: mulneg3000_sub8990_b: ; RV32IMB: # %bb.0: +; RV32IMB-NEXT: addi a0, a0, 3 ; RV32IMB-NEXT: lui a1, 1048575 ; RV32IMB-NEXT: addi a1, a1, 1096 ; RV32IMB-NEXT: mul a0, a0, a1 -; RV32IMB-NEXT: lui a1, 1048574 -; RV32IMB-NEXT: addi a1, a1, -798 -; RV32IMB-NEXT: add a0, a0, a1 +; RV32IMB-NEXT: addi a0, a0, 10 ; RV32IMB-NEXT: ret ; ; RV64IMB-LABEL: mulneg3000_sub8990_b: ; RV64IMB: # %bb.0: +; RV64IMB-NEXT: addiw a0, a0, 3 ; RV64IMB-NEXT: lui a1, 1048575 ; RV64IMB-NEXT: addiw a1, a1, 1096 ; RV64IMB-NEXT: mulw a0, a0, a1 -; RV64IMB-NEXT: lui a1, 1048574 -; RV64IMB-NEXT: addiw a1, a1, -798 -; RV64IMB-NEXT: addw a0, a0, a1 +; RV64IMB-NEXT: addiw a0, a0, 10 ; RV64IMB-NEXT: ret %tmp0 = mul i32 %x, -3000 %tmp1 = add i32 %tmp0, -8990 @@ -881,12 +862,11 @@ ; ; RV64IMB-LABEL: mulneg3000_sub8990_c: ; RV64IMB: # %bb.0: +; RV64IMB-NEXT: addi a0, a0, 3 ; RV64IMB-NEXT: lui a1, 1048575 ; RV64IMB-NEXT: addiw a1, a1, 1096 ; RV64IMB-NEXT: mul a0, a0, a1 -; RV64IMB-NEXT: lui a1, 1048574 -; RV64IMB-NEXT: addiw a1, a1, -798 -; RV64IMB-NEXT: add a0, a0, a1 +; RV64IMB-NEXT: addi a0, a0, 10 ; RV64IMB-NEXT: ret %tmp0 = mul i64 %x, -3000 %tmp1 = add i64 %tmp0, -8990