This is the mail archive of the
gcc-patches@gcc.gnu.org
mailing list for the GCC project.
[PATCH] Constant folding MINUS_EXPR improvements
- From: Roger Sayle <roger at eyesopen dot com>
- To: gcc-patches at gcc dot gnu dot org
- Date: Sun, 1 Feb 2004 20:38:58 -0700 (MST)
- Subject: [PATCH] Constant folding MINUS_EXPR improvements
The following patch implements several small improvements to GCC's
constant folding of subtraction.
The first is that we now constant fold -(A+B) into either (-A)-B or
(-B)-A, if either A or B is easily negated respectively, and in the
latter that we're allowed to reorder the evaluations of A and B.
Consider, the function
int foo(int a, int b, int c)
{
return - (a + (b - c));
}
Without this patch, GCC currently implements this function using an
addition, a subtraction and a negation. Both Microsoft Visual C/C++
and GCC with this patch implement it using only two subtractions, as
"(c - b) - a".
Other improvements include moving the optimization of "(A*C) - (B*C) ->
(A-B)*C" out of the integer-only optimizations, and also enabling it for
floating point calculations, with flag_unsafe_math_optimizations. I also
took the opportunity of adding the related "A*C1 - A*C2 -> A*(C1-C2)".
Finally, I've added "A - B -> A + (-B)" for floating point types, or
when we know integer arithmetic overflow doesn't trap and wraps around.
The following patch has been tested on i686-pc-linux-gnu with a complete
"make bootstrap", all languages except treelang, and regression tested
with a top-level "make -k check" with no new failures.
Ok for mainline?
2004-02-01 Roger Sayle <roger@eyesopen.com>
* fold-const.c (negate_expr_p, negate_expr): Optimize -(A+B) into
either (-A)-B or (-B)-A, if A or B is easily negated respectively.
(fold) <MINUS_EXPR>: Optimize (A*C) - (B*C) -> (A-B)*C for both
integer types and floating point with unsafe_math_optimizations.
Add similar optimization for (A*C1) - (A*C2) -> A*(C1-C2).
Optimize A - B as A + (-B), if B is easily negated.
Index: fold-const.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/fold-const.c,v
retrieving revision 1.325
diff -c -3 -p -r1.325 fold-const.c
*** fold-const.c 23 Jan 2004 16:52:07 -0000 1.325
--- fold-const.c 1 Feb 2004 21:09:40 -0000
*************** negate_expr_p (tree t)
*** 879,884 ****
--- 879,895 ----
return negate_expr_p (TREE_REALPART (t))
&& negate_expr_p (TREE_IMAGPART (t));
+ case PLUS_EXPR:
+ if (FLOAT_TYPE_P (type) && !flag_unsafe_math_optimizations)
+ return false;
+ /* -(A + B) -> (-B) - A. */
+ if (negate_expr_p (TREE_OPERAND (t, 1))
+ && reorder_operands_p (TREE_OPERAND (t, 0),
+ TREE_OPERAND (t, 1)))
+ return true;
+ /* -(A + B) -> (-A) - B. */
+ return negate_expr_p (TREE_OPERAND (t, 0));
+
case MINUS_EXPR:
/* We can't turn -(A-B) into B-A when we honor signed zeros. */
return (! FLOAT_TYPE_P (type) || flag_unsafe_math_optimizations)
*************** negate_expr (tree t)
*** 980,985 ****
--- 991,1016 ----
case NEGATE_EXPR:
return convert (type, TREE_OPERAND (t, 0));
+ case PLUS_EXPR:
+ if (! FLOAT_TYPE_P (type) || flag_unsafe_math_optimizations)
+ {
+ /* -(A + B) -> (-B) - A. */
+ if (negate_expr_p (TREE_OPERAND (t, 1))
+ && reorder_operands_p (TREE_OPERAND (t, 0),
+ TREE_OPERAND (t, 1)))
+ return convert (type,
+ fold (build (MINUS_EXPR, TREE_TYPE (t),
+ negate_expr (TREE_OPERAND (t, 1)),
+ TREE_OPERAND (t, 0))));
+ /* -(A + B) -> (-A) - B. */
+ if (negate_expr_p (TREE_OPERAND (t, 0)))
+ return convert (type,
+ fold (build (MINUS_EXPR, TREE_TYPE (t),
+ negate_expr (TREE_OPERAND (t, 0)),
+ TREE_OPERAND (t, 1))));
+ }
+ break;
+
case MINUS_EXPR:
/* - (A - B) -> B - A */
if ((! FLOAT_TYPE_P (type) || flag_unsafe_math_optimizations)
*************** fold (tree expr)
*** 6097,6115 ****
if (integer_zerop (arg1))
return non_lvalue (convert (type, arg0));
- /* (A * C) - (B * C) -> (A-B) * C. Since we are most concerned
- about the case where C is a constant, just try one of the
- four possibilities. */
-
- if (TREE_CODE (arg0) == MULT_EXPR && TREE_CODE (arg1) == MULT_EXPR
- && operand_equal_p (TREE_OPERAND (arg0, 1),
- TREE_OPERAND (arg1, 1), 0))
- return fold (build (MULT_EXPR, type,
- fold (build (MINUS_EXPR, type,
- TREE_OPERAND (arg0, 0),
- TREE_OPERAND (arg1, 0))),
- TREE_OPERAND (arg0, 1)));
-
/* Fold A - (A & B) into ~B & A. */
if (!TREE_SIDE_EFFECTS (arg0)
&& TREE_CODE (arg1) == BIT_AND_EXPR)
--- 6128,6133 ----
*************** fold (tree expr)
*** 6165,6170 ****
--- 6183,6216 ----
if ((! FLOAT_TYPE_P (type) || flag_unsafe_math_optimizations)
&& operand_equal_p (arg0, arg1, 0))
return convert (type, integer_zero_node);
+
+ /* A - B -> A + (-B) if B is easily negatable. */
+ if (!wins && negate_expr_p (arg1)
+ && (FLOAT_TYPE_P (type)
+ || (INTEGRAL_TYPE_P (type) && flag_wrapv && !flag_trapv)))
+ return fold (build (PLUS_EXPR, type, arg0, negate_expr (arg1)));
+
+ if (TREE_CODE (arg0) == MULT_EXPR
+ && TREE_CODE (arg1) == MULT_EXPR
+ && (INTEGRAL_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 (build (MULT_EXPR, type,
+ fold (build (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 (build (MULT_EXPR, type,
+ TREE_OPERAND (arg0, 0),
+ fold (build (MINUS_EXPR, type,
+ TREE_OPERAND (arg0, 1),
+ TREE_OPERAND (arg1, 1)))));
+ }
goto associate;
Roger
--
Roger Sayle, E-mail: roger@eyesopen.com
OpenEye Scientific Software, WWW: http://www.eyesopen.com/
Suite 1107, 3600 Cerrillos Road, Tel: (+1) 505-473-7385
Santa Fe, New Mexico, 87507. Fax: (+1) 505-473-0833