This is the mail archive of the gcc-patches@gcc.gnu.org mailing list for the GCC project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

[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));

Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]