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>
* 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);
}
/* 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
OP0. Return the folded expression if folding is successful.
Otherwise, return NULL_TREE. */
@ -7205,6 +7303,17 @@ fold_binary (enum tree_code code, tree type, tree op0, tree op1)
&& integer_onep (arg1))
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 (integer_zerop (arg1))
@ -7266,70 +7375,6 @@ fold_binary (enum tree_code code, tree type, tree op0, tree op1)
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
of the array. Loop optimizer sometimes produce this type of
expressions. */
@ -7379,56 +7424,6 @@ fold_binary (enum tree_code code, tree type, tree op0, tree op1)
return fold_build2 (MULT_EXPR, type, arg0,
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. */
if (flag_unsafe_math_optimizations
&& 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)))
return tem;
if (TREE_CODE (arg0) == MULT_EXPR
&& TREE_CODE (arg1) == MULT_EXPR
/* 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))
{
/* (A * C) - (B * C) -> (A-B) * C. */
if (operand_equal_p (TREE_OPERAND (arg0, 1),
TREE_OPERAND (arg1, 1), 0))
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)));
{
tree tem = fold_plusminus_mult_expr (code, type, arg0, arg1);
if (tem)
return tem;
}
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>
* 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" } } */