re PR middle-end/23294 (fold does not fold a*C+a to a*(C+1) or a*C-a to a*(C-1))

2005-11-19  Richard Guenther  <rguenther@suse.de>

        PR middle-end/23294
	* fold-const.c (fold_plusminus_mult_expr): New function.
	(fold_binary): Use to canonicalize PLUS_EXPR and MINUS_EXPR
	cases, remove now unnecessary code.

	* gcc.dg/tree-ssa/pr23294.c: New testcase.

From-SVN: r107218
This commit is contained in:
Richard Guenther 2005-11-19 11:29:10 +00:00 committed by Richard Biener
parent 0e32f9bcd5
commit 0ed9a3e314
4 changed files with 167 additions and 133 deletions

View File

@ -1,3 +1,10 @@
2005-11-19 Richard Guenther <rguenther@suse.de>
PR middle-end/23294
* fold-const.c (fold_plusminus_mult_expr): New function.
(fold_binary): Use to canonicalize PLUS_EXPR and MINUS_EXPR
cases, remove now unnecessary code.
2005-11-19 Paolo Bonzini <bonzini@gcc.gnu.org> 2005-11-19 Paolo Bonzini <bonzini@gcc.gnu.org>
* gensupport.c (old_preds): Rename to std_preds, add special field. * gensupport.c (old_preds): Rename to std_preds, add special field.

View File

@ -6556,6 +6556,104 @@ fold_to_nonsharp_ineq_using_bound (tree ineq, tree bound)
return fold_build2 (GE_EXPR, type, a, y); return fold_build2 (GE_EXPR, type, a, y);
} }
/* Fold a sum or difference of at least one multiplication.
Returns the folded tree or NULL if no simplification could be made. */
static tree
fold_plusminus_mult_expr (enum tree_code code, tree type, tree arg0, tree arg1)
{
tree arg00, arg01, arg10, arg11;
tree alt0 = NULL_TREE, alt1 = NULL_TREE, same;
/* (A * C) +- (B * C) -> (A+-B) * C.
(A * C) +- A -> A * (C+-1).
We are most concerned about the case where C is a constant,
but other combinations show up during loop reduction. Since
it is not difficult, try all four possibilities. */
if (TREE_CODE (arg0) == MULT_EXPR)
{
arg00 = TREE_OPERAND (arg0, 0);
arg01 = TREE_OPERAND (arg0, 1);
}
else
{
arg00 = arg0;
if (!FLOAT_TYPE_P (type))
arg01 = build_int_cst (type, 1);
else
arg01 = build_real (type, dconst1);
}
if (TREE_CODE (arg1) == MULT_EXPR)
{
arg10 = TREE_OPERAND (arg1, 0);
arg11 = TREE_OPERAND (arg1, 1);
}
else
{
arg10 = arg1;
if (!FLOAT_TYPE_P (type))
arg11 = build_int_cst (type, 1);
else
arg11 = build_real (type, dconst1);
}
same = NULL_TREE;
if (operand_equal_p (arg01, arg11, 0))
same = arg01, alt0 = arg00, alt1 = arg10;
else if (operand_equal_p (arg00, arg10, 0))
same = arg00, alt0 = arg01, alt1 = arg11;
else if (operand_equal_p (arg00, arg11, 0))
same = arg00, alt0 = arg01, alt1 = arg10;
else if (operand_equal_p (arg01, arg10, 0))
same = arg01, alt0 = arg00, alt1 = arg11;
/* No identical multiplicands; see if we can find a common
power-of-two factor in non-power-of-two multiplies. This
can help in multi-dimensional array access. */
else if (host_integerp (arg01, 0)
&& host_integerp (arg11, 0))
{
HOST_WIDE_INT int01, int11, tmp;
bool swap = false;
tree maybe_same;
int01 = TREE_INT_CST_LOW (arg01);
int11 = TREE_INT_CST_LOW (arg11);
/* Move min of absolute values to int11. */
if ((int01 >= 0 ? int01 : -int01)
< (int11 >= 0 ? int11 : -int11))
{
tmp = int01, int01 = int11, int11 = tmp;
alt0 = arg00, arg00 = arg10, arg10 = alt0;
maybe_same = arg01;
swap = true;
}
else
maybe_same = arg11;
if (exact_log2 (int11) > 0 && int01 % int11 == 0)
{
alt0 = fold_build2 (MULT_EXPR, TREE_TYPE (arg00), arg00,
build_int_cst (TREE_TYPE (arg00),
int01 / int11));
alt1 = arg10;
same = maybe_same;
if (swap)
maybe_same = alt0, alt0 = alt1, alt1 = maybe_same;
}
}
if (same)
return fold_build2 (MULT_EXPR, type,
fold_build2 (code, type,
fold_convert (type, alt0),
fold_convert (type, alt1)),
fold_convert (type, same));
return NULL_TREE;
}
/* Fold a unary expression of code CODE and type TYPE with operand /* Fold a unary expression of code CODE and type TYPE with operand
OP0. Return the folded expression if folding is successful. OP0. Return the folded expression if folding is successful.
Otherwise, return NULL_TREE. */ Otherwise, return NULL_TREE. */
@ -7205,6 +7303,17 @@ fold_binary (enum tree_code code, tree type, tree op0, tree op1)
&& integer_onep (arg1)) && integer_onep (arg1))
return fold_build1 (NEGATE_EXPR, type, TREE_OPERAND (arg0, 0)); return fold_build1 (NEGATE_EXPR, type, TREE_OPERAND (arg0, 0));
/* Handle (A1 * C1) + (A2 * C2) with A1, A2 or C1, C2 being the
same or one. */
if ((TREE_CODE (arg0) == MULT_EXPR
|| TREE_CODE (arg1) == MULT_EXPR)
&& (!FLOAT_TYPE_P (type) || flag_unsafe_math_optimizations))
{
tree tem = fold_plusminus_mult_expr (code, type, arg0, arg1);
if (tem)
return tem;
}
if (! FLOAT_TYPE_P (type)) if (! FLOAT_TYPE_P (type))
{ {
if (integer_zerop (arg1)) if (integer_zerop (arg1))
@ -7266,70 +7375,6 @@ fold_binary (enum tree_code code, tree type, tree op0, tree op1)
parg1))); parg1)));
} }
if (TREE_CODE (arg0) == MULT_EXPR && TREE_CODE (arg1) == MULT_EXPR)
{
tree arg00, arg01, arg10, arg11;
tree alt0 = NULL_TREE, alt1 = NULL_TREE, same;
/* (A * C) + (B * C) -> (A+B) * C.
We are most concerned about the case where C is a constant,
but other combinations show up during loop reduction. Since
it is not difficult, try all four possibilities. */
arg00 = TREE_OPERAND (arg0, 0);
arg01 = TREE_OPERAND (arg0, 1);
arg10 = TREE_OPERAND (arg1, 0);
arg11 = TREE_OPERAND (arg1, 1);
same = NULL_TREE;
if (operand_equal_p (arg01, arg11, 0))
same = arg01, alt0 = arg00, alt1 = arg10;
else if (operand_equal_p (arg00, arg10, 0))
same = arg00, alt0 = arg01, alt1 = arg11;
else if (operand_equal_p (arg00, arg11, 0))
same = arg00, alt0 = arg01, alt1 = arg10;
else if (operand_equal_p (arg01, arg10, 0))
same = arg01, alt0 = arg00, alt1 = arg11;
/* No identical multiplicands; see if we can find a common
power-of-two factor in non-power-of-two multiplies. This
can help in multi-dimensional array access. */
else if (TREE_CODE (arg01) == INTEGER_CST
&& TREE_CODE (arg11) == INTEGER_CST
&& TREE_INT_CST_HIGH (arg01) == 0
&& TREE_INT_CST_HIGH (arg11) == 0)
{
HOST_WIDE_INT int01, int11, tmp;
int01 = TREE_INT_CST_LOW (arg01);
int11 = TREE_INT_CST_LOW (arg11);
/* Move min of absolute values to int11. */
if ((int01 >= 0 ? int01 : -int01)
< (int11 >= 0 ? int11 : -int11))
{
tmp = int01, int01 = int11, int11 = tmp;
alt0 = arg00, arg00 = arg10, arg10 = alt0;
alt0 = arg01, arg01 = arg11, arg11 = alt0;
}
if (exact_log2 (int11) > 0 && int01 % int11 == 0)
{
alt0 = fold_build2 (MULT_EXPR, type, arg00,
build_int_cst (NULL_TREE,
int01 / int11));
alt1 = arg10;
same = arg11;
}
}
if (same)
return fold_build2 (MULT_EXPR, type,
fold_build2 (PLUS_EXPR, type,
fold_convert (type, alt0),
fold_convert (type, alt1)),
fold_convert (type, same));
}
/* Try replacing &a[i1] + c * i2 with &a[i1 + i2], if c is step /* Try replacing &a[i1] + c * i2 with &a[i1 + i2], if c is step
of the array. Loop optimizer sometimes produce this type of of the array. Loop optimizer sometimes produce this type of
expressions. */ expressions. */
@ -7379,56 +7424,6 @@ fold_binary (enum tree_code code, tree type, tree op0, tree op1)
return fold_build2 (MULT_EXPR, type, arg0, return fold_build2 (MULT_EXPR, type, arg0,
build_real (type, dconst2)); build_real (type, dconst2));
/* Convert x*c+x into x*(c+1). */
if (flag_unsafe_math_optimizations
&& TREE_CODE (arg0) == MULT_EXPR
&& TREE_CODE (TREE_OPERAND (arg0, 1)) == REAL_CST
&& ! TREE_CONSTANT_OVERFLOW (TREE_OPERAND (arg0, 1))
&& operand_equal_p (TREE_OPERAND (arg0, 0), arg1, 0))
{
REAL_VALUE_TYPE c;
c = TREE_REAL_CST (TREE_OPERAND (arg0, 1));
real_arithmetic (&c, PLUS_EXPR, &c, &dconst1);
return fold_build2 (MULT_EXPR, type, arg1,
build_real (type, c));
}
/* Convert x+x*c into x*(c+1). */
if (flag_unsafe_math_optimizations
&& TREE_CODE (arg1) == MULT_EXPR
&& TREE_CODE (TREE_OPERAND (arg1, 1)) == REAL_CST
&& ! TREE_CONSTANT_OVERFLOW (TREE_OPERAND (arg1, 1))
&& operand_equal_p (TREE_OPERAND (arg1, 0), arg0, 0))
{
REAL_VALUE_TYPE c;
c = TREE_REAL_CST (TREE_OPERAND (arg1, 1));
real_arithmetic (&c, PLUS_EXPR, &c, &dconst1);
return fold_build2 (MULT_EXPR, type, arg0,
build_real (type, c));
}
/* Convert x*c1+x*c2 into x*(c1+c2). */
if (flag_unsafe_math_optimizations
&& TREE_CODE (arg0) == MULT_EXPR
&& TREE_CODE (arg1) == MULT_EXPR
&& TREE_CODE (TREE_OPERAND (arg0, 1)) == REAL_CST
&& ! TREE_CONSTANT_OVERFLOW (TREE_OPERAND (arg0, 1))
&& TREE_CODE (TREE_OPERAND (arg1, 1)) == REAL_CST
&& ! TREE_CONSTANT_OVERFLOW (TREE_OPERAND (arg1, 1))
&& operand_equal_p (TREE_OPERAND (arg0, 0),
TREE_OPERAND (arg1, 0), 0))
{
REAL_VALUE_TYPE c1, c2;
c1 = TREE_REAL_CST (TREE_OPERAND (arg0, 1));
c2 = TREE_REAL_CST (TREE_OPERAND (arg1, 1));
real_arithmetic (&c1, PLUS_EXPR, &c1, &c2);
return fold_build2 (MULT_EXPR, type,
TREE_OPERAND (arg0, 0),
build_real (type, c1));
}
/* Convert a + (b*c + d*e) into (a + b*c) + d*e. */ /* Convert a + (b*c + d*e) into (a + b*c) + d*e. */
if (flag_unsafe_math_optimizations if (flag_unsafe_math_optimizations
&& TREE_CODE (arg1) == PLUS_EXPR && TREE_CODE (arg1) == PLUS_EXPR
@ -7771,26 +7766,15 @@ fold_binary (enum tree_code code, tree type, tree op0, tree op1)
&& (tem = distribute_real_division (code, type, arg0, arg1))) && (tem = distribute_real_division (code, type, arg0, arg1)))
return tem; return tem;
if (TREE_CODE (arg0) == MULT_EXPR /* Handle (A1 * C1) - (A2 * C2) with A1, A2 or C1, C2 being the
&& TREE_CODE (arg1) == MULT_EXPR same or one. */
if ((TREE_CODE (arg0) == MULT_EXPR
|| TREE_CODE (arg1) == MULT_EXPR)
&& (!FLOAT_TYPE_P (type) || flag_unsafe_math_optimizations)) && (!FLOAT_TYPE_P (type) || flag_unsafe_math_optimizations))
{ {
/* (A * C) - (B * C) -> (A-B) * C. */ tree tem = fold_plusminus_mult_expr (code, type, arg0, arg1);
if (operand_equal_p (TREE_OPERAND (arg0, 1), if (tem)
TREE_OPERAND (arg1, 1), 0)) return tem;
return fold_build2 (MULT_EXPR, type,
fold_build2 (MINUS_EXPR, type,
TREE_OPERAND (arg0, 0),
TREE_OPERAND (arg1, 0)),
TREE_OPERAND (arg0, 1));
/* (A * C1) - (A * C2) -> A * (C1-C2). */
if (operand_equal_p (TREE_OPERAND (arg0, 0),
TREE_OPERAND (arg1, 0), 0))
return fold_build2 (MULT_EXPR, type,
TREE_OPERAND (arg0, 0),
fold_build2 (MINUS_EXPR, type,
TREE_OPERAND (arg0, 1),
TREE_OPERAND (arg1, 1)));
} }
goto associate; goto associate;

View File

@ -1,3 +1,8 @@
2005-11-19 Richard Guenther <rguenther@suse.de>
PR middle-end/23294
* gcc.dg/tree-ssa/pr23294.c: New testcase.
2005-11-19 Hans-Peter Nilsson <hp@bitrange.com> 2005-11-19 Hans-Peter Nilsson <hp@bitrange.com>
* gcc.dg/fold-overflow-1.c: Adjust for float output for mmix-*-*. * gcc.dg/fold-overflow-1.c: Adjust for float output for mmix-*-*.

View File

@ -0,0 +1,38 @@
/* { dg-do compile } */
/* { dg-options "-O -fdump-tree-vars" } */
int f1(int a)
{
return a*6-a;
}
int f2(int a)
{
return a*4+a;
}
int f3(int a)
{
return 2*a + 3*a;
}
int f4(int a, int b)
{
return 2*a + 6*b;
}
int f5(int a, int b)
{
return 2*a - 6*b;
}
int f6(int a, int b)
{
return 6*a - 2*b;
}
/* { dg-final { scan-tree-dump-times "a \\\* 5" 3 "vars" } } */
/* { dg-final { scan-tree-dump "\\\(b \\\* 3 \\\+ a\\\) \\\* 2" "vars" } } */
/* { dg-final { scan-tree-dump "\\\(a - b \\\* 3\\\) \\\* 2" "vars" } } */
/* { dg-final { scan-tree-dump "\\\(a \\\* 3 - b\\\) \\\* 2" "vars" } } */
/* { dg-final { cleanup-tree-dump "vars" } } */