This is the mail archive of the
gcc-patches@gcc.gnu.org
mailing list for the GCC project.
[PATCH] Constant folding NEGATE_EXPR clean-ups.
- From: Roger Sayle <roger at eyesopen dot com>
- To: gcc-patches at gcc dot gnu dot org
- Date: Sun, 28 Sep 2003 19:52:32 -0600 (MDT)
- Subject: [PATCH] Constant folding NEGATE_EXPR clean-ups.
The following patch contains numerous clean-ups to fold-const.c.
The original intention was to move the remaining NEGATE_EXPR optimizations
into the preferred routines negate_expr_p and negate_expr.
Unfortunately, whilst I was fixing I got slightly carried away and made
two or three additional NEGATE_EXPR related changes. I had hoped these
additional changes wouldn't "hurt" the review, but the recent tree-ssa
merge problems have cast things in a slightly different light.
Interestingly, I've just discovered some of these changes mirror Jeff
Law's patch to factor code from "fold <NEGATE_EXPR>" into tree-ssa's
fold_negate_const :>
As described above the main thrust of the patch is to move the remaining
NEGATE_EXPR transformations into the preferred negate_expr_p/negate_expr.
This shares all of these optimizations, as originally intended for
negate_expr.
The first additional (semi-related) change was to add support for
negation of COMPLEX_CST; "-(x+iy)" is "(-x)+(-y)i", i.e. we just
negate both the real and imaginary parts.
The second additional (semi-related) change was that negate_expr_p
wasn't respecting Java's evaluation order semantics, converting
"-(f(x) - g(y))" into "g(y) - f(x)". Now that we have an appropriate
flag_evaluation_order flag, it seemed worthwhile to fix this.
I placed the required logic in a new function reorder_operands_p,
which in addition to flag_evaluation_order can also check whether
either operand is a constant, or that neither operands side-effect.
It turned out this function could immediately replace equivalent code
in fold's MINUS_EXPR case [that converts (-A) - B into (-B) - A].
Finally, as a follow-on to the new reorder_operands_p, it seemed
appropriate to also modify swap_operands_p with a similar check.
The best route seemed to be to add an additional Boolean argument
indicating whether the operands would be evaluated in reverse order
if swapped.
Its a good thing I stopped there. There were several additional
negation related optimizations/changes I wanted to make, but the
patch was already getting a bit large.
The following patch has been tested on i686-pc-linux-gnu with a
full "make bootstrap", all languages except treelang, and regression
tested with a top-level "make -k check" with no new failures.
Ok for mainline? I promise to help Jeff sync tree-ssa and mainline
fold-const.c, if that's a concern.
2003-09-28 Roger Sayle <roger@eyesopen.com>
* fold-const.c (negate_mathfn_p): New function to determine whether
a built-in mathematical function is sign preserving, f(-x) == -f(x).
Add support for BUILT_IN_ASIN, BUILT_IN_ASINF and BUILT_IN_ASINL.
(tree_swap_operands_p): Change API to take an additional argument
indicating that the swapped operands evaluate in reverse order.
Canonicalize VAR_DECLs and PARM_DECLs last if we can, i.e. neither
operand side-effects or we don't care about flag_evaluation_order.
(reorder_operands_p): New function to check whether its safe to
evaluate the given operands in reverse order.
(negate_expr_p): We can always negate integer constants unless
we honor -ftrapv and the signed type would overflow. Only allow
-(A-B) into B-A if reorder_operands_p says that its OK. Allow
negation of COMPLEX_CST if both real and imaginary parts can be
negated. Allow negation through floating point extensions and
sign-preserving built-in functions.
(negate_expr): Move the code to negate integers from "fold" to
here. Always negate integer constants unless we honor -ftrapv
and the signed type would overflow. Always negate real constants
unless we honor -ftrapping-math. Only convert -(A-B) into B-A
if allowed by reorder_operands_p. Add support for COMPLEX_CST.
Optimize negation through floating point extensions and
sign-preserving built-in functions (as defined by negate_mathfn_p).
(fold): Adjust calls to tree_swap_operands_p.
(fold <NEGATE_EXPR>): Move the remaining negation optimizations
to negate_expr_p/negate_expr.
(fold <MINUS_EXPR>): Use reorder_operands_p to check whether we're
allowed to convert (-A) - B into (-B) - A.
Index: fold-const.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/fold-const.c,v
retrieving revision 1.306
diff -c -3 -p -r1.306 fold-const.c
*** fold-const.c 25 Sep 2003 02:12:13 -0000 1.306
--- fold-const.c 28 Sep 2003 22:30:43 -0000
*************** Software Foundation, 59 Temple Place - S
*** 60,65 ****
--- 60,66 ----
static void encode (HOST_WIDE_INT *, unsigned HOST_WIDE_INT, HOST_WIDE_INT);
static void decode (HOST_WIDE_INT *, unsigned HOST_WIDE_INT *, HOST_WIDE_INT *);
+ static bool negate_mathfn_p (enum built_in_function);
static bool negate_expr_p (tree);
static tree negate_expr (tree);
static tree split_tree (tree, enum tree_code, tree *, tree *, tree *, int);
*************** static bool fold_real_zero_addition_p (t
*** 108,114 ****
static tree fold_mathfn_compare (enum built_in_function, enum tree_code,
tree, tree, tree);
static tree fold_inf_compare (enum tree_code, tree, tree, tree);
! static bool tree_swap_operands_p (tree, tree);
/* The following constants represent a bit based encoding of GCC's
comparison operators. This encoding simplifies transformations
--- 109,116 ----
static tree fold_mathfn_compare (enum built_in_function, enum tree_code,
tree, tree, tree);
static tree fold_inf_compare (enum tree_code, tree, tree, tree);
! static bool reorder_operands_p (tree, tree);
! static bool tree_swap_operands_p (tree, tree, bool);
/* The following constants represent a bit based encoding of GCC's
comparison operators. This encoding simplifies transformations
*************** div_and_round_double (enum tree_code cod
*** 803,808 ****
--- 805,839 ----
return overflow;
}
+ /* Return true if built-in mathematical function specified by CODE
+ preserves the sign of it argument, i.e. -f(x) == f(-x). */
+
+ static bool
+ negate_mathfn_p (enum built_in_function code)
+ {
+ switch (code)
+ {
+ case BUILT_IN_ASIN:
+ case BUILT_IN_ASINF:
+ case BUILT_IN_ASINL:
+ case BUILT_IN_ATAN:
+ case BUILT_IN_ATANF:
+ case BUILT_IN_ATANL:
+ case BUILT_IN_SIN:
+ case BUILT_IN_SINF:
+ case BUILT_IN_SINL:
+ case BUILT_IN_TAN:
+ case BUILT_IN_TANF:
+ case BUILT_IN_TANL:
+ return true;
+
+ default:
+ break;
+ }
+ return false;
+ }
+
+
/* Determine whether an expression T can be cheaply negated using
the function negate_expr. */
*************** negate_expr_p (tree t)
*** 822,829 ****
switch (TREE_CODE (t))
{
case INTEGER_CST:
! if (TREE_UNSIGNED (type))
! return false;
/* Check that -CST will not overflow type. */
prec = TYPE_PRECISION (type);
--- 853,860 ----
switch (TREE_CODE (t))
{
case INTEGER_CST:
! if (TREE_UNSIGNED (type) || ! flag_trapv)
! return true;
/* Check that -CST will not overflow type. */
prec = TYPE_PRECISION (type);
*************** negate_expr_p (tree t)
*** 844,852 ****
case NEGATE_EXPR:
return true;
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;
case MULT_EXPR:
if (TREE_UNSIGNED (TREE_TYPE (t)))
--- 875,889 ----
case NEGATE_EXPR:
return true;
+ case COMPLEX_CST:
+ return negate_expr_p (TREE_REALPART (t))
+ && negate_expr_p (TREE_IMAGPART (t));
+
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)
! && reorder_operands_p (TREE_OPERAND (t, 0),
! TREE_OPERAND (t, 1));
case MULT_EXPR:
if (TREE_UNSIGNED (TREE_TYPE (t)))
*************** negate_expr_p (tree t)
*** 860,865 ****
--- 897,918 ----
|| negate_expr_p (TREE_OPERAND (t, 0));
break;
+ case NOP_EXPR:
+ /* Negate -((double)float) as (double)(-float). */
+ if (TREE_CODE (type) == REAL_TYPE)
+ {
+ tree tem = strip_float_extensions (t);
+ if (tem != t)
+ return negate_expr_p (tem);
+ }
+ break;
+
+ case CALL_EXPR:
+ /* Negate -f(x) as f(-x). */
+ if (negate_mathfn_p (builtin_mathfn_code (t)))
+ return negate_expr_p (TREE_VALUE (TREE_OPERAND (t, 1)));
+ break;
+
default:
break;
}
*************** negate_expr (tree t)
*** 884,908 ****
switch (TREE_CODE (t))
{
case INTEGER_CST:
! if (! TREE_UNSIGNED (type)
! && 0 != (tem = fold (build1 (NEGATE_EXPR, type, t)))
! && ! TREE_OVERFLOW (tem))
return tem;
break;
case REAL_CST:
tem = build_real (type, REAL_VALUE_NEGATE (TREE_REAL_CST (t)));
/* Two's complement FP formats, such as c4x, may overflow. */
! if (! TREE_OVERFLOW (tem))
return convert (type, tem);
break;
case NEGATE_EXPR:
return convert (type, TREE_OPERAND (t, 0));
case MINUS_EXPR:
/* - (A - B) -> B - A */
! if (! FLOAT_TYPE_P (type) || flag_unsafe_math_optimizations)
return convert (type,
fold (build (MINUS_EXPR, TREE_TYPE (t),
TREE_OPERAND (t, 1),
--- 937,989 ----
switch (TREE_CODE (t))
{
case INTEGER_CST:
! {
! unsigned HOST_WIDE_INT low;
! HOST_WIDE_INT high;
! int overflow = neg_double (TREE_INT_CST_LOW (t),
! TREE_INT_CST_HIGH (t),
! &low, &high);
! tem = build_int_2 (low, high);
! TREE_TYPE (tem) = type;
! TREE_OVERFLOW (tem)
! = (TREE_OVERFLOW (t)
! | force_fit_type (tem, overflow && !TREE_UNSIGNED (type)));
! TREE_CONSTANT_OVERFLOW (tem)
! = TREE_OVERFLOW (tem) | TREE_CONSTANT_OVERFLOW (t);
! }
! if (! TREE_OVERFLOW (tem)
! || TREE_UNSIGNED (type)
! || ! flag_trapv)
return tem;
break;
case REAL_CST:
tem = build_real (type, REAL_VALUE_NEGATE (TREE_REAL_CST (t)));
/* Two's complement FP formats, such as c4x, may overflow. */
! if (! TREE_OVERFLOW (tem) || ! flag_trapping_math)
return convert (type, tem);
break;
+ case COMPLEX_CST:
+ {
+ tree rpart = negate_expr (TREE_REALPART (t));
+ tree ipart = negate_expr (TREE_IMAGPART (t));
+
+ if ((TREE_CODE (rpart) == REAL_CST
+ && TREE_CODE (ipart) == REAL_CST)
+ || (TREE_CODE (rpart) == INTEGER_CST
+ && TREE_CODE (ipart) == INTEGER_CST))
+ return build_complex (type, rpart, ipart);
+ }
+ break;
+
case NEGATE_EXPR:
return convert (type, TREE_OPERAND (t, 0));
case MINUS_EXPR:
/* - (A - B) -> B - A */
! if ((! FLOAT_TYPE_P (type) || flag_unsafe_math_optimizations)
! && reorder_operands_p (TREE_OPERAND (t, 0), TREE_OPERAND (t, 1)))
return convert (type,
fold (build (MINUS_EXPR, TREE_TYPE (t),
TREE_OPERAND (t, 1),
*************** negate_expr (tree t)
*** 933,938 ****
--- 1014,1043 ----
}
break;
+ case NOP_EXPR:
+ /* Convert -((double)float) into (double)(-float). */
+ if (TREE_CODE (type) == REAL_TYPE)
+ {
+ tem = strip_float_extensions (t);
+ if (tem != t && negate_expr_p (tem))
+ return convert (type, negate_expr (tem));
+ }
+ break;
+
+ case CALL_EXPR:
+ /* Negate -f(x) as f(-x). */
+ if (negate_mathfn_p (builtin_mathfn_code (t))
+ && negate_expr_p (TREE_VALUE (TREE_OPERAND (t, 1))))
+ {
+ tree fndecl, arg, arglist;
+
+ fndecl = get_callee_fndecl (t);
+ arg = negate_expr (TREE_VALUE (TREE_OPERAND (t, 1)));
+ arglist = build_tree_list (NULL_TREE, arg);
+ return build_function_call_expr (fndecl, arglist);
+ }
+ break;
+
default:
break;
}
*************** fold_single_bit_test (enum tree_code cod
*** 4977,4988 ****
return NULL_TREE;
}
/* Test whether it is preferable two swap two operands, ARG0 and
ARG1, for example because ARG0 is an integer constant and ARG1
! isn't. */
static bool
! tree_swap_operands_p (tree arg0, tree arg1)
{
STRIP_SIGN_NOPS (arg0);
STRIP_SIGN_NOPS (arg1);
--- 5082,5108 ----
return NULL_TREE;
}
+ /* Check whether we are allowed to reorder operands arg0 and arg1,
+ such that the evaluation of arg1 occurs before arg0. */
+
+ static bool
+ reorder_operands_p (tree arg0, tree arg1)
+ {
+ if (! flag_evaluation_order)
+ return true;
+ if (TREE_CONSTANT (arg0) || TREE_CONSTANT (arg1))
+ return true;
+ return ! TREE_SIDE_EFFECTS (arg0)
+ && ! TREE_SIDE_EFFECTS (arg1);
+ }
+
/* Test whether it is preferable two swap two operands, ARG0 and
ARG1, for example because ARG0 is an integer constant and ARG1
! isn't. If REORDER is true, only recommend swapping if we can
! evaluate the operands in reverse order. */
static bool
! tree_swap_operands_p (tree arg0, tree arg1, bool reorder)
{
STRIP_SIGN_NOPS (arg0);
STRIP_SIGN_NOPS (arg1);
*************** tree_swap_operands_p (tree arg0, tree ar
*** 5007,5012 ****
--- 5127,5141 ----
if (TREE_CONSTANT (arg0))
return 1;
+ if (reorder && flag_evaluation_order
+ && (TREE_SIDE_EFFECTS (arg0) || TREE_SIDE_EFFECTS (arg1)))
+ return 0;
+
+ if (DECL_P (arg1))
+ return 0;
+ if (DECL_P (arg0))
+ return 1;
+
return 0;
}
*************** fold (tree expr)
*** 5121,5127 ****
if ((code == PLUS_EXPR || code == MULT_EXPR || code == MIN_EXPR
|| code == MAX_EXPR || code == BIT_IOR_EXPR || code == BIT_XOR_EXPR
|| code == BIT_AND_EXPR)
! && tree_swap_operands_p (arg0, arg1))
return fold (build (code, type, arg1, arg0));
/* Now WINS is set as described above,
--- 5250,5256 ----
if ((code == PLUS_EXPR || code == MULT_EXPR || code == MIN_EXPR
|| code == MAX_EXPR || code == BIT_IOR_EXPR || code == BIT_XOR_EXPR
|| code == BIT_AND_EXPR)
! && tree_swap_operands_p (arg0, arg1, true))
return fold (build (code, type, arg1, arg0));
/* Now WINS is set as described above,
*************** fold (tree expr)
*** 5460,5530 ****
return t;
case NEGATE_EXPR:
! if (wins)
! {
! if (TREE_CODE (arg0) == INTEGER_CST)
! {
! unsigned HOST_WIDE_INT low;
! HOST_WIDE_INT high;
! int overflow = neg_double (TREE_INT_CST_LOW (arg0),
! TREE_INT_CST_HIGH (arg0),
! &low, &high);
! t = build_int_2 (low, high);
! TREE_TYPE (t) = type;
! TREE_OVERFLOW (t)
! = (TREE_OVERFLOW (arg0)
! | force_fit_type (t, overflow && !TREE_UNSIGNED (type)));
! TREE_CONSTANT_OVERFLOW (t)
! = TREE_OVERFLOW (t) | TREE_CONSTANT_OVERFLOW (arg0);
! }
! else if (TREE_CODE (arg0) == REAL_CST)
! t = build_real (type, REAL_VALUE_NEGATE (TREE_REAL_CST (arg0)));
! }
! else if (TREE_CODE (arg0) == NEGATE_EXPR)
! return TREE_OPERAND (arg0, 0);
! /* Convert -((double)float) into (double)(-float). */
! else if (TREE_CODE (arg0) == NOP_EXPR
! && TREE_CODE (type) == REAL_TYPE)
! {
! tree targ0 = strip_float_extensions (arg0);
! if (targ0 != arg0)
! return convert (type, build1 (NEGATE_EXPR, TREE_TYPE (targ0), targ0));
!
! }
!
! /* Convert - (a - b) to (b - a) for non-floating-point. */
! else if (TREE_CODE (arg0) == MINUS_EXPR
! && (! FLOAT_TYPE_P (type) || flag_unsafe_math_optimizations))
! return build (MINUS_EXPR, type, TREE_OPERAND (arg0, 1),
! TREE_OPERAND (arg0, 0));
!
! /* Convert -f(x) into f(-x) where f is sin, tan or atan. */
! switch (builtin_mathfn_code (arg0))
! {
! case BUILT_IN_SIN:
! case BUILT_IN_SINF:
! case BUILT_IN_SINL:
! case BUILT_IN_TAN:
! case BUILT_IN_TANF:
! case BUILT_IN_TANL:
! case BUILT_IN_ATAN:
! case BUILT_IN_ATANF:
! case BUILT_IN_ATANL:
! if (negate_expr_p (TREE_VALUE (TREE_OPERAND (arg0, 1))))
! {
! tree fndecl, arg, arglist;
!
! fndecl = get_callee_fndecl (arg0);
! arg = TREE_VALUE (TREE_OPERAND (arg0, 1));
! arg = fold (build1 (NEGATE_EXPR, type, arg));
! arglist = build_tree_list (NULL_TREE, arg);
! return build_function_call_expr (fndecl, arglist);
! }
! break;
!
! default:
! break;
! }
return t;
case ABS_EXPR:
--- 5589,5596 ----
return t;
case NEGATE_EXPR:
! if (negate_expr_p (arg0))
! return negate_expr (arg0);
return t;
case ABS_EXPR:
*************** fold (tree expr)
*** 5977,5984 ****
&& (FLOAT_TYPE_P (type)
|| (INTEGRAL_TYPE_P (type) && flag_wrapv && !flag_trapv))
&& negate_expr_p (arg1)
! && (! TREE_SIDE_EFFECTS (arg0) || TREE_CONSTANT (arg1))
! && (! TREE_SIDE_EFFECTS (arg1) || TREE_CONSTANT (arg0)))
return fold (build (MINUS_EXPR, type, negate_expr (arg1),
TREE_OPERAND (arg0, 0)));
--- 6043,6049 ----
&& (FLOAT_TYPE_P (type)
|| (INTEGRAL_TYPE_P (type) && flag_wrapv && !flag_trapv))
&& negate_expr_p (arg1)
! && reorder_operands_p (arg0, arg1))
return fold (build (MINUS_EXPR, type, negate_expr (arg1),
TREE_OPERAND (arg0, 0)));
*************** fold (tree expr)
*** 6870,6876 ****
case LE_EXPR:
case GE_EXPR:
/* If one arg is a real or integer constant, put it last. */
! if (tree_swap_operands_p (arg0, arg1))
return fold (build (swap_tree_comparison (code), type, arg1, arg0));
if (FLOAT_TYPE_P (TREE_TYPE (arg0)))
--- 6935,6941 ----
case LE_EXPR:
case GE_EXPR:
/* If one arg is a real or integer constant, put it last. */
! if (tree_swap_operands_p (arg0, arg1, true))
return fold (build (swap_tree_comparison (code), type, arg1, arg0));
if (FLOAT_TYPE_P (TREE_TYPE (arg0)))
*************** fold (tree expr)
*** 7984,7990 ****
/* If the second operand is simpler than the third, swap them
since that produces better jump optimization results. */
! if (tree_swap_operands_p (TREE_OPERAND (t, 1), TREE_OPERAND (t, 2)))
{
/* See if this can be inverted. If it can't, possibly because
it was a floating-point inequality comparison, don't do
--- 8049,8056 ----
/* If the second operand is simpler than the third, swap them
since that produces better jump optimization results. */
! if (tree_swap_operands_p (TREE_OPERAND (t, 1),
! TREE_OPERAND (t, 2), false))
{
/* See if this can be inverted. If it can't, possibly because
it was a floating-point inequality comparison, don't do
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