This is the mail archive of the
gcc-patches@gcc.gnu.org
mailing list for the GCC project.
[ast-optimizer-branch] PATCH to &&, ++ and return
- From: Jason Merrill <jason at redhat dot com>
- To: gcc-patches at gcc dot gnu dot org
- Date: Mon, 10 Jun 2002 06:28:30 +0100
- Subject: [ast-optimizer-branch] PATCH to &&, ++ and return
The bottom ChangeLog bits are infrastructure for the upper three, which are
independent of one another, but I'm checking them in together because I'm
lazy.
get_initialized_tmp_var creates a new initialized temp, so callers don't
have to deal with building up, simplifying and adding a MODIFY_EXPR.
simplify_expr_common now takes a NULL post_p argument; in this case, if the
expression being simplified has post-effects, the result will be copied
to a temp and the post-effects emitted before returning. This is used in
simplify_return_stmt here, and will be used in the loop nodes in a later
patch.
I've changed simplify_return_stmt to accept an RHS, while the grammar says
it should only accept a VAL. The reason for this is to avoid an extra temp
on code like
struct A f ();
struct A g ()
{
return f ();
}
Here, if we require a VAL, we need to copy the returned struct into our
stack frame before returning it. This can be slow, depending on the size
of A. And a return statement is already represented with a MODIFY_EXPR,
anyway...
I've fixed simplify_self_mod_expr so that an expression like (*f())++ only
calls f once. This fixes gcc.dg/20020426-2.c.
I've fixed simplify_boolean_expr so that the temp used to keep track of the
current state has the appropriate boolean type (int, in C); previously it
would get the type of the && expression, which could be an arbitrary type.
In gcc.c-torture/compile/980706-1.c there is a && expression which ends up
having long long type. I've also reduced the number of comparisons we
build; we know that T is a boolean value, we don't need to keep comparing
it to zero.
Booted and tested i686-pc-linux-gnu. Also fixes gcc.dg/uninit-A.c, though
that may be transient.
2002-06-10 Jason Merrill <jason@redhat.com>
* c-simplify.c (simplify_boolean_expr): Avoid redundant tests.
Give the temp the appropriate type for a boolean value, and
reconvert at the end.
* c-simplify.c (simplify_self_mod_expr): Don't duplicate side-effects.
* c-simplify.c (simplify_return_stmt): Accept a SIMPLE rhs.
Just hand off to simplify_expr.
* c-simplify.c (get_initialized_tmp_var): New fn.
(simplify_expr_common): Use it. Handle post-effects internally if
POST_P is NULL.
(is_simple_tmp_var): Rename from simple_tmp_var_p.
* tree-simple.h: Adjust.
*** c-simplify.c.~1~ Sun Jun 9 18:34:10 2002
--- c-simplify.c Mon Jun 10 04:38:33 2002
*************** Software Foundation, 59 Temple Place - S
*** 34,39 ****
--- 34,40 ----
#include "tree-simple.h"
#include "tree-inline.h"
#include "diagnostic.h"
+ #include "langhooks.h"
/** The simplification pass converts the language-dependent trees
(ld-trees) emitted by the parser into language-independent trees
*************** simplify_return_stmt (stmt, pre_p)
*** 906,912 ****
if (!VOID_TYPE_P (TREE_TYPE (TREE_TYPE (current_function_decl)))
&& RETURN_EXPR (stmt))
{
! tree expr, tmp, ret_expr, post;
/* A return expression is represented by a MODIFY_EXPR node that
assigns the return value into a RESULT_DECL. */
--- 907,913 ----
if (!VOID_TYPE_P (TREE_TYPE (TREE_TYPE (current_function_decl)))
&& RETURN_EXPR (stmt))
{
! tree ret_expr;
/* A return expression is represented by a MODIFY_EXPR node that
assigns the return value into a RESULT_DECL. */
*************** simplify_return_stmt (stmt, pre_p)
*** 915,938 ****
ret_expr = TREE_OPERAND (RETURN_EXPR (stmt), 1);
! if (is_simple_val (ret_expr))
return;
! /* Create the assignment 'T = ret_expr'. */
! tmp = create_tmp_var (TREE_TYPE (ret_expr));
! expr = build_modify_expr (tmp, NOP_EXPR, ret_expr);
!
! /* Simplify it. */
! post = NULL_TREE;
! walk_tree (&expr, mostly_copy_tree_r, NULL, NULL);
! simplify_expr (&expr, pre_p, &post, is_simple_expr, stmt);
!
! /* Emit the expression and its post side-effects into PRE_P. */
! add_tree (expr, pre_p);
! add_tree (post, pre_p);
!
! /* Replace the return value with the new temporary. */
! TREE_OPERAND (RETURN_EXPR (stmt), 1) = tmp;
}
}
--- 916,930 ----
ret_expr = TREE_OPERAND (RETURN_EXPR (stmt), 1);
! /* The grammar calls for a simple VAL here, but the RETURN_STMT
! already uses a MODIFY_EXPR, and using a full RHS allows us to
! optimize returning a call to a function of struct type. */
! if (is_simple_rhs (ret_expr))
return;
! walk_tree (&ret_expr, mostly_copy_tree_r, NULL, NULL);
! simplify_expr (&ret_expr, pre_p, NULL, is_simple_rhs, stmt);
! TREE_OPERAND (RETURN_EXPR (stmt), 1) = ret_expr;
}
}
*************** simplify_return_stmt (stmt, pre_p)
*** 949,955 ****
EXPR should be stored.
POST_P points to the list where side effects that must happen after
! EXPR should be stored.
SIMPLE_TEST_F points to a function that takes a tree T and
returns nonzero if T is in the SIMPLE form requested by the
--- 941,949 ----
EXPR should be stored.
POST_P points to the list where side effects that must happen after
! EXPR should be stored, or NULL if there is no suitable list. In
! that case, we copy the result to a temporary, emit the
! post-effects, and then return the temporary.
SIMPLE_TEST_F points to a function that takes a tree T and
returns nonzero if T is in the SIMPLE form requested by the
*************** simplify_expr_common (expr_p, pre_p, pos
*** 982,987 ****
--- 976,982 ----
int fallback_rvalue = (fallback & 1);
int fallback_lvalue = (fallback & 2);
tree tmp;
+ tree internal_post = NULL_TREE;
if (simple_test_f == NULL)
abort ();
*************** simplify_expr_common (expr_p, pre_p, pos
*** 989,994 ****
--- 984,993 ----
if ((*simple_test_f) (*expr_p))
return;
+ /* Set up our internal postqueue if needed. */
+ if (post_p == NULL)
+ post_p = &internal_post;
+
/* First deal with the special cases. */
switch (TREE_CODE (*expr_p))
{
*************** simplify_expr_common (expr_p, pre_p, pos
*** 1155,1168 ****
}
}
! /* If it's sufficiently simple already, we're done. */
! if ((*simple_test_f) (*expr_p))
return;
/* Otherwise, we need to create a new temporary for the simplified
expression. */
! if (fallback_lvalue && is_simple_varname (*expr_p))
{
/* An lvalue will do. Take the address of the expression, store it
in a temporary, and replace the expression with an INDIRECT_REF of
--- 1154,1171 ----
}
}
! /* If it's sufficiently simple already, we're done. Unless we are
! handling some post-effects internally; if that's the case, we need to
! copy into a temp before adding the post-effects to the tree. */
! if ((*simple_test_f) (*expr_p) && !internal_post)
return;
/* Otherwise, we need to create a new temporary for the simplified
expression. */
! if (fallback_lvalue && is_simple_varname (*expr_p)
! /* We can't return an lvalue if we have an internal postqueue. */
! && !internal_post)
{
/* An lvalue will do. Take the address of the expression, store it
in a temporary, and replace the expression with an INDIRECT_REF of
*************** simplify_expr_common (expr_p, pre_p, pos
*** 1178,1190 ****
/* An rvalue will do. Assign the simplified expression into a new
temporary TMP and replace the original expression with TMP. */
! tmp = create_tmp_var (TREE_TYPE (*expr_p));
! add_tree (build_modify_expr (tmp, NOP_EXPR, *expr_p), pre_p);
! *expr_p = tmp;
}
else
{
fprintf (stderr, "simplification failed:\n");
debug_tree (*expr_p);
abort ();
}
--- 1181,1192 ----
/* An rvalue will do. Assign the simplified expression into a new
temporary TMP and replace the original expression with TMP. */
! *expr_p = get_initialized_tmp_var (*expr_p, pre_p, stmt);
}
else
{
fprintf (stderr, "simplification failed:\n");
+ debug_c_tree (*expr_p);
debug_tree (*expr_p);
abort ();
}
*************** simplify_expr_common (expr_p, pre_p, pos
*** 1192,1197 ****
--- 1194,1202 ----
/* Make sure the temporary matches our predicate. */
if (!(*simple_test_f) (*expr_p))
abort ();
+
+ if (internal_post)
+ add_tree (internal_post, pre_p);
}
static void
*************** simplify_self_mod_expr (expr_p, pre_p, p
*** 1339,1366 ****
&& code != PREDECREMENT_EXPR)
abort ();
! /* Simplify the LHS into a SIMPLE lvalue. We need to deep copy the first
! operand because it will be simplified twice. Once to convert it into
! a SIMPLE lvalue and the second time when we simplify the resulting
! binary expression on the RHS of the assignment.
!
! ??? This duplicates side-effects. FIXME! */
lvalue = TREE_OPERAND (*expr_p, 0);
- walk_tree (&lvalue, copy_tree_r, NULL, NULL);
simplify_lvalue_expr (&lvalue, pre_p, post_p, is_simple_modify_expr_lhs,
stmt);
! /* Determine whether we need to create a PLUS or a MINUS operation. */
! lhs = TREE_OPERAND (*expr_p, 0);
rhs = TREE_OPERAND (*expr_p, 1);
if (code == PREINCREMENT_EXPR || code == POSTINCREMENT_EXPR)
t1 = build (PLUS_EXPR, TREE_TYPE (*expr_p), lhs, rhs);
else
t1 = build (MINUS_EXPR, TREE_TYPE (*expr_p), lhs, rhs);
! /* If LHS is not a SIMPLE identifier, the resulting binary expression
! will not be in simple form. */
! simplify_expr (&t1, pre_p, post_p, is_simple_binary_expr, stmt);
/* Determine whether the new assignment should go before or after
the simplified expression. */
--- 1344,1369 ----
&& code != PREDECREMENT_EXPR)
abort ();
! /* Simplify the LHS into a SIMPLE lvalue. */
lvalue = TREE_OPERAND (*expr_p, 0);
simplify_lvalue_expr (&lvalue, pre_p, post_p, is_simple_modify_expr_lhs,
stmt);
! /* Extract the operands to the arithmetic operation, including an rvalue
! version of our LHS. */
! lhs = lvalue;
! simplify_expr (&lhs, pre_p, post_p, is_simple_id, stmt);
rhs = TREE_OPERAND (*expr_p, 1);
+ simplify_expr (&rhs, pre_p, post_p, is_simple_val, stmt);
+
+ /* Determine whether we need to create a PLUS or a MINUS operation. */
if (code == PREINCREMENT_EXPR || code == POSTINCREMENT_EXPR)
t1 = build (PLUS_EXPR, TREE_TYPE (*expr_p), lhs, rhs);
else
t1 = build (MINUS_EXPR, TREE_TYPE (*expr_p), lhs, rhs);
! if (!is_simple_binary_expr (t1))
! abort ();
/* Determine whether the new assignment should go before or after
the simplified expression. */
*************** simplify_boolean_expr (expr_p, pre_p, st
*** 1629,1646 ****
tree stmt;
{
enum tree_code code;
! tree t, lhs, rhs, if_body, if_cond, mod_expr, if_stmt;
code = TREE_CODE (*expr_p);
if (code != TRUTH_ANDIF_EXPR && code != TRUTH_ORIF_EXPR)
abort ();
! lhs = TREE_OPERAND (*expr_p, 0);
! rhs = TREE_OPERAND (*expr_p, 1);
/* Build 'T = a' */
! t = create_tmp_var (TREE_TYPE (*expr_p));
! mod_expr = build_modify_expr (t, NOP_EXPR, lhs);
/* Build the body for the if() statement that conditionally evaluates the
RHS of the expression. Note that we first build the assignment
--- 1632,1650 ----
tree stmt;
{
enum tree_code code;
! tree t, lhs, rhs, if_body, if_cond, if_stmt;
code = TREE_CODE (*expr_p);
if (code != TRUTH_ANDIF_EXPR && code != TRUTH_ORIF_EXPR)
abort ();
! /* First, make sure that our operands are truthvalues. This should
! already be the case, but let's be conservative. */
! lhs = (*lang_hooks.truthvalue_conversion) (TREE_OPERAND (*expr_p, 0));
! rhs = (*lang_hooks.truthvalue_conversion) (TREE_OPERAND (*expr_p, 1));
/* Build 'T = a' */
! t = get_initialized_tmp_var (lhs, pre_p, stmt);
/* Build the body for the if() statement that conditionally evaluates the
RHS of the expression. Note that we first build the assignment
*************** simplify_boolean_expr (expr_p, pre_p, st
*** 1658,1666 ****
resulting if() statement is simplified, the side effects for the LHS
of 'a && b' will be inserted before the evaluation of 'b'. */
if (code == TRUTH_ANDIF_EXPR)
! if_cond = build (NE_EXPR, TREE_TYPE (*expr_p), mod_expr, integer_zero_node);
else
! if_cond = build (EQ_EXPR, TREE_TYPE (*expr_p), mod_expr, integer_zero_node);
if_stmt = build_stmt (IF_STMT, if_cond, if_body, NULL_TREE);
STMT_LINENO (if_stmt) = STMT_LINENO (stmt);
--- 1662,1670 ----
resulting if() statement is simplified, the side effects for the LHS
of 'a && b' will be inserted before the evaluation of 'b'. */
if (code == TRUTH_ANDIF_EXPR)
! if_cond = t;
else
! if_cond = build (EQ_EXPR, TREE_TYPE (t), t, integer_zero_node);
if_stmt = build_stmt (IF_STMT, if_cond, if_body, NULL_TREE);
STMT_LINENO (if_stmt) = STMT_LINENO (stmt);
*************** simplify_boolean_expr (expr_p, pre_p, st
*** 1669,1676 ****
simplify_if_stmt (if_stmt, pre_p);
add_tree (if_stmt, pre_p);
! /* Re-write the original expression to evaluate 'T != 0'. */
! *expr_p = build (NE_EXPR, TREE_TYPE (*expr_p), t, integer_zero_node);
}
/* }}} */
--- 1673,1687 ----
simplify_if_stmt (if_stmt, pre_p);
add_tree (if_stmt, pre_p);
! /* If we're not actually looking for a boolean result, convert now. */
! if (TREE_TYPE (t) != TREE_TYPE (*expr_p))
! {
! t = convert (TREE_TYPE (*expr_p), t);
! simplify_expr (&t, pre_p, NULL, is_simple_id, stmt);
! }
!
! /* Re-write the original expression to use T. */
! *expr_p = t;
}
/* }}} */
*************** create_tmp_var (type)
*** 2113,2124 ****
/* }}} */
! /** {{{ simple_tmp_var_p ()
Returns true if T is a SIMPLE temporary variable, false otherwise. */
bool
! simple_tmp_var_p (t)
tree t;
{
/* FIXME this could trigger for other local artificials, too. */
--- 2124,2156 ----
/* }}} */
! /* Returns a new temporary variable, initialized with VAL. PRE_P and STMT
! are as in simplify_expr.*/
!
! tree
! get_initialized_tmp_var (val, pre_p, stmt)
! tree val;
! tree *pre_p;
! tree stmt;
! {
! tree t, mod;
! tree post = NULL_TREE;
!
! simplify_expr (&val, pre_p, &post, is_simple_rhs, stmt);
! t = create_tmp_var (TREE_TYPE (val));
! mod = build_modify_expr (t, NOP_EXPR, val);
! add_tree (mod, pre_p);
! add_tree (post, pre_p);
!
! return t;
! }
!
! /** {{{ is_simple_tmp_var ()
Returns true if T is a SIMPLE temporary variable, false otherwise. */
bool
! is_simple_tmp_var (t)
tree t;
{
/* FIXME this could trigger for other local artificials, too. */
*** tree-simple.h.~1~ Sun Jun 9 18:32:54 2002
--- tree-simple.h Mon Jun 10 04:38:33 2002
*************** Boston, MA 02111-1307, USA. */
*** 26,32 ****
extern void insert_before_continue_end PARAMS ((tree, tree, int));
extern void tree_build_scope PARAMS ((tree *));
extern tree create_tmp_var PARAMS ((tree));
! extern bool simple_tmp_var_p PARAMS ((tree));
extern tree declare_tmp_vars PARAMS ((tree, tree));
extern tree deep_copy_list PARAMS ((tree));
extern tree deep_copy_node PARAMS ((tree));
--- 26,33 ----
extern void insert_before_continue_end PARAMS ((tree, tree, int));
extern void tree_build_scope PARAMS ((tree *));
extern tree create_tmp_var PARAMS ((tree));
! extern bool is_simple_tmp_var PARAMS ((tree));
! extern tree get_initialized_tmp_var PARAMS ((tree, tree *, tree));
extern tree declare_tmp_vars PARAMS ((tree, tree));
extern tree deep_copy_list PARAMS ((tree));
extern tree deep_copy_node PARAMS ((tree));