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]

Re: simplify the argument of return_expr


On Mon, Jun 07, 2004 at 03:38:45PM -0400, Jason Merrill wrote:
> My mistake, the new box I was testing on is actually x86_64.

Testing the following on amd64-linux.  It cures the problem in
the .i file provided by Jason.


r~


	* gimple-low.c (struct lower_data): Replace the_return_label and
	one_return_stmt with return_statements.
	(lower_function_body): Process the entire list of return_statements.
	(lower_return_expr): Check source value before unifying return_exprs.
	* gimplify.c (gimplify_return_expr): Force the use of a temporary
	for !aggregate_value_p.
	* tree-gimple.c: Update RETURN_EXPR grammer.

Index: gimple-low.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/gimple-low.c,v
retrieving revision 2.3
diff -c -p -d -r2.3 gimple-low.c
*** gimple-low.c	7 Jun 2004 17:53:02 -0000	2.3
--- gimple-low.c	7 Jun 2004 21:26:51 -0000
*************** struct lower_data
*** 47,55 ****
    /* Block the current statement belongs to.  */
    tree block;
  
!   /* Label that unifies the return statements.  */
!   tree the_return_label;
!   tree one_return_stmt;
  };
  
  static void lower_stmt (tree_stmt_iterator *, struct lower_data *);
--- 47,55 ----
    /* Block the current statement belongs to.  */
    tree block;
  
!   /* A TREE_LIST of label and return statements to be moved to the end
!      of the function.  */
!   tree return_statements;
  };
  
  static void lower_stmt (tree_stmt_iterator *, struct lower_data *);
*************** lower_function_body (void)
*** 76,83 ****
    BLOCK_CHAIN (data.block) = NULL_TREE;
    TREE_ASM_WRITTEN (data.block) = 1;
  
!   data.the_return_label = NULL_TREE;
!   data.one_return_stmt = NULL_TREE;
  
    *body_p = alloc_stmt_list ();
    i = tsi_start (*body_p);
--- 76,82 ----
    BLOCK_CHAIN (data.block) = NULL_TREE;
    TREE_ASM_WRITTEN (data.block) = 1;
  
!   data.return_statements = NULL_TREE;
  
    *body_p = alloc_stmt_list ();
    i = tsi_start (*body_p);
*************** lower_function_body (void)
*** 86,98 ****
  
    /* If we lowered any return statements, emit the representative at the
       end of the function.  */
!   if (data.one_return_stmt)
      {
!       tree t;
!       t = build (LABEL_EXPR, void_type_node, data.the_return_label);
        i = tsi_last (*body_p);
!       tsi_link_after (&i, t, TSI_CONTINUE_LINKING);
!       tsi_link_after (&i, data.one_return_stmt, TSI_CONTINUE_LINKING);
      }
  
    if (data.block != DECL_INITIAL (current_function_decl))
--- 85,107 ----
  
    /* If we lowered any return statements, emit the representative at the
       end of the function.  */
!   if (data.return_statements)
      {
!       tree t, x;
        i = tsi_last (*body_p);
! 
!       for (t = data.return_statements; t ; t = TREE_CHAIN (t))
! 	{
! 	  x = build (LABEL_EXPR, void_type_node, TREE_PURPOSE (t));
!           tsi_link_after (&i, x, TSI_CONTINUE_LINKING);
! 
! 	  /* Remove the line number from the representative return statement.
! 	     It now fills in for many such returns.  Failure to remove this
! 	     will result in incorrect results for coverage analysis.  */
! 	  x = TREE_VALUE (t);
! 	  SET_EXPR_LOCUS (x, NULL);
!           tsi_link_after (&i, x, TSI_CONTINUE_LINKING);
!         }
      }
  
    if (data.block != DECL_INITIAL (current_function_decl))
*************** lower_cond_expr (tree_stmt_iterator *tsi
*** 392,407 ****
  static void
  lower_return_expr (tree_stmt_iterator *tsi, struct lower_data *data)
  {
!   tree stmt, label = data->the_return_label;
  
!   if (!label)
      {
!       data->the_return_label = label = create_artificial_label ();
!       data->one_return_stmt = tsi_stmt (*tsi);
      }
  
!   stmt = build (GOTO_EXPR, void_type_node, label);
!   tsi_link_before (tsi, stmt, TSI_SAME_STMT);
    tsi_delink (tsi);
  }
  
--- 401,437 ----
  static void
  lower_return_expr (tree_stmt_iterator *tsi, struct lower_data *data)
  {
!   tree stmt = tsi_stmt (*tsi);
!   tree value, t, label;
  
!   /* Extract the value being returned.  */
!   value = TREE_OPERAND (stmt, 0);
!   if (value && TREE_CODE (value) == MODIFY_EXPR)
!     value = TREE_OPERAND (value, 1);
! 
!   /* Match this up with an existing return statement that's been created.  */
!   for (t = data->return_statements; t ; t = TREE_CHAIN (t))
      {
!       tree tvalue = TREE_OPERAND (TREE_VALUE (t), 0);
!       if (tvalue && TREE_CODE (tvalue) == MODIFY_EXPR)
! 	tvalue = TREE_OPERAND (tvalue, 1);
! 
!       if (value == tvalue)
! 	{
! 	  label = TREE_PURPOSE (t);
! 	  goto found;
! 	}
      }
  
!   /* Not found.  Create a new label and record the return statement.  */
!   label = create_artificial_label ();
!   data->return_statements = tree_cons (label, stmt, data->return_statements);
! 
!   /* Generate a goto statement and remove the return statement.  */
!  found:
!   t = build (GOTO_EXPR, void_type_node, label);
!   SET_EXPR_LOCUS (t, EXPR_LOCUS (stmt));
!   tsi_link_before (tsi, t, TSI_SAME_STMT);
    tsi_delink (tsi);
  }
  
Index: gimplify.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/gimplify.c,v
retrieving revision 2.11
diff -c -p -d -r2.11 gimplify.c
*** gimplify.c	7 Jun 2004 17:53:02 -0000	2.11
--- gimplify.c	7 Jun 2004 21:26:51 -0000
*************** static struct gimplify_ctx
*** 54,59 ****
--- 54,60 ----
    tree conditional_cleanups;
    int conditions;
    tree exit_label;
+   tree return_temp;
    varray_type case_labels;
    /* The formal temporary table.  Should this be persistent?  */
    htab_t temp_htab;
*************** static enum gimplify_status
*** 876,882 ****
  gimplify_return_expr (tree stmt, tree *pre_p)
  {
    tree ret_expr = TREE_OPERAND (stmt, 0);
!   tree result;
  
    if (!ret_expr || TREE_CODE (ret_expr) == RESULT_DECL)
      return GS_ALL_DONE;
--- 877,883 ----
  gimplify_return_expr (tree stmt, tree *pre_p)
  {
    tree ret_expr = TREE_OPERAND (stmt, 0);
!   tree result_decl, result;
  
    if (!ret_expr || TREE_CODE (ret_expr) == RESULT_DECL)
      return GS_ALL_DONE;
*************** gimplify_return_expr (tree stmt, tree *p
*** 885,908 ****
      return GS_ERROR;
  
    if (VOID_TYPE_P (TREE_TYPE (TREE_TYPE (current_function_decl))))
!     result = NULL_TREE;
    else
      {
!       result = TREE_OPERAND (ret_expr, 0);
  #ifdef ENABLE_CHECKING
        if ((TREE_CODE (ret_expr) != MODIFY_EXPR
  	   && TREE_CODE (ret_expr) != INIT_EXPR)
! 	  || TREE_CODE (result) != RESULT_DECL)
  	abort ();
  #endif
      }
  
!   /* We need to pass the full MODIFY_EXPR down so that special handling
!      can replace it with something else.  */
    gimplify_stmt (&TREE_OPERAND (stmt, 0));
    append_to_statement_list (TREE_OPERAND (stmt, 0), pre_p);
  
!   TREE_OPERAND (stmt, 0) = result;
  
    return GS_ALL_DONE;
  }
--- 886,936 ----
      return GS_ERROR;
  
    if (VOID_TYPE_P (TREE_TYPE (TREE_TYPE (current_function_decl))))
!     result_decl = NULL_TREE;
    else
      {
!       result_decl = TREE_OPERAND (ret_expr, 0);
  #ifdef ENABLE_CHECKING
        if ((TREE_CODE (ret_expr) != MODIFY_EXPR
  	   && TREE_CODE (ret_expr) != INIT_EXPR)
! 	  || TREE_CODE (result_decl) != RESULT_DECL)
  	abort ();
  #endif
      }
  
!   /* If aggregate_value_p is true, then we can return the bare RESULT_DECL.
!      Recall that aggregate_value_p is FALSE for any aggregate type that is
!      returned in registers.  If we're returning values in registers, then
!      we don't want to extend the lifetime of the RESULT_DECL, particularly
!      across another call.  In addition, for those aggregates for which 
!      hard_function_value generates a PARALLEL, we'll abort during normal
!      expansion of structure assignments; there's special code in expand_return
!      to handle this case that does not exist in expand_expr.  */
!   if (!result_decl
!       || aggregate_value_p (result_decl, TREE_TYPE (current_function_decl)))
!     result = result_decl;
!   else if (gimplify_ctxp->return_temp)
!     result = gimplify_ctxp->return_temp;
!   else
!     {
!       result = create_tmp_var (TREE_TYPE (result_decl), NULL);
!       gimplify_ctxp->return_temp = result;
!     }
! 
!   /* Smash the lhs of the MODIFY_EXPR to the temporary we plan to use.
!      Then gimplify the whole thing.  */
!   if (result != result_decl)
!     TREE_OPERAND (ret_expr, 0) = result;
    gimplify_stmt (&TREE_OPERAND (stmt, 0));
    append_to_statement_list (TREE_OPERAND (stmt, 0), pre_p);
  
!   /* If we didn't use a temporary, then the result is just the result_decl.
!      Otherwise we need a simple copy.  This should already be gimple.  */
!   if (result == result_decl)
!     ret_expr = result;
!   else
!     ret_expr = build (MODIFY_EXPR, TREE_TYPE (result), result_decl, result);
!   TREE_OPERAND (stmt, 0) = ret_expr;
  
    return GS_ALL_DONE;
  }
Index: tree-gimple.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/tree-gimple.c,v
retrieving revision 2.4
diff -c -p -d -r2.4 tree-gimple.c
*** tree-gimple.c	7 Jun 2004 17:53:02 -0000	2.4
--- tree-gimple.c	7 Jun 2004 21:26:51 -0000
*************** Boston, MA 02111-1307, USA.  */
*** 79,85 ****
         GOTO_EXPR
           op0 -> LABEL_DECL | '*' ID
       | RETURN_EXPR
!          op0 -> RESULT_DECL | NULL_TREE
       | THROW_EXPR?  do we need/want such a thing for opts, perhaps
           to generate an ERT_THROW region?  I think so.
  	 Hmm...this would only work at the GIMPLE level, where we know that
--- 79,87 ----
         GOTO_EXPR
           op0 -> LABEL_DECL | '*' ID
       | RETURN_EXPR
!          op0 -> NULL_TREE
! 	      | RESULT_DECL
! 	      | MODIFY_EXPR -> RESULT_DECL, varname
       | THROW_EXPR?  do we need/want such a thing for opts, perhaps
           to generate an ERT_THROW region?  I think so.
  	 Hmm...this would only work at the GIMPLE level, where we know that


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