[RISCV] Optimize (add (mul r, c0), c1)

Optimize (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.

Optimize (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.

Reviewed By: craig.topper, asb

Differential Revision: https://reviews.llvm.org/D111141
This commit is contained in:
Ben Shi 2021-10-05 12:28:36 +00:00 committed by Ben Shi
parent 7c6f5950f0
commit e32cf690df
2 changed files with 73 additions and 79 deletions

View File

@ -6439,7 +6439,19 @@ static SDValue combineSelectAndUseCommutative(SDNode *N, SelectionDAG &DAG,
// 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 @@ static SDValue transformAddImmMulImm(SDNode *N, SelectionDAG &DAG,
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) ->

View File

@ -559,9 +559,9 @@ define i64 @add_mul_combine_infinite_loop(i64 %x) {
;
; 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 i64 @add_mul_combine_infinite_loop(i64 %x) {
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 i32 @mul3000_add8990_a(i32 %x) {
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 @@ define i64 @mul3000_add8990_c(i64 %x) {
;
; 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 i64 @mul3000_add8990_c(i64 %x) {
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 i32 @mul3000_sub8990_a(i32 %x) {
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 @@ define i64 @mul3000_sub8990_c(i64 %x) {
;
; 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 i64 @mul3000_sub8990_c(i64 %x) {
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 i32 @mulneg3000_add8990_a(i32 %x) {
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 @@ define i64 @mulneg3000_add8990_c(i64 %x) {
;
; 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 i64 @mulneg3000_add8990_c(i64 %x) {
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 i32 @mulneg3000_sub8990_a(i32 %x) {
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 @@ define i64 @mulneg3000_sub8990_c(i64 %x) {
;
; 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