tree-nrv.c File Reference

#include "config.h"
#include "system.h"
#include "coretypes.h"
#include "tm.h"
#include "tree.h"
#include "rtl.h"
#include "function.h"
#include "basic-block.h"
#include "expr.h"
#include "diagnostic.h"
#include "tree-flow.h"
#include "timevar.h"
#include "tree-dump.h"
#include "tree-pass.h"
#include "langhooks.h"

Include dependency graph for tree-nrv.c:

Go to the source code of this file.

Data Structures

struct  nrv_data

Functions

static tree finalize_nrv_r (tree *, int *, void *)
static tree finalize_nrv_r ()
static unsigned int tree_nrv ()
static bool dest_safe_for_nrv_p ()
static unsigned int execute_return_slot_opt ()

Variables

tree_opt_pass pass_nrv
tree_opt_pass pass_return_slot


Function Documentation

static bool dest_safe_for_nrv_p  )  [static]
 

Determine (pessimistically) whether DEST is available for NRV
   optimization, where DEST is expected to be the LHS of a modify
   expression where the RHS is a function returning an aggregate.

   We search for a base VAR_DECL and look to see if it, or any of its
   subvars are clobbered.  Note that we could do better, for example, by
   attempting to doing points-to analysis on INDIRECT_REFs.   

Definition at line 243 of file tree-nrv.c.

References get_subvars_for_var, is_call_clobbered(), subvar::next, TREE_CODE, TREE_OPERAND, and subvar::var.

Referenced by execute_return_slot_opt().

00244 {
00245   switch (TREE_CODE (dest))
00246     {
00247       case VAR_DECL:
00248         {
00249           subvar_t subvar;
00250           if (is_call_clobbered (dest))
00251             return false;
00252           for (subvar = get_subvars_for_var (dest);
00253                subvar;
00254                subvar = subvar->next)
00255             if (is_call_clobbered (subvar->var))
00256               return false;
00257           return true;
00258         }
00259       case ARRAY_REF:
00260       case COMPONENT_REF:
00261         return dest_safe_for_nrv_p (TREE_OPERAND (dest, 0));
00262       default:
00263         return false;
00264     }
00265 }

static unsigned int execute_return_slot_opt  )  [static]
 

Walk through the function looking for MODIFY_EXPRs with calls that
   return in memory on the RHS.  For each of these, determine whether it is
   safe to pass the address of the LHS as the return slot, and mark the
   call appropriately if so.

   The NRV shares the return slot with a local variable in the callee; this
   optimization shares the return slot with the target of the call within
   the caller.  If the NRV is performed (which we can't know in general),
   this optimization is safe if the address of the target has not
   escaped prior to the call.  If it has, modifications to the local
   variable will produce visible changes elsewhere, as in PR c++/19317.   

Definition at line 280 of file tree-nrv.c.

References aggregate_value_p(), bsi_end_p(), bsi_next(), bsi_start, bsi_stmt(), CALL_EXPR_RETURN_SLOT_OPT, dest_safe_for_nrv_p(), TREE_CODE, and TREE_OPERAND.

00281 {
00282   basic_block bb;
00283 
00284   FOR_EACH_BB (bb)
00285     {
00286       block_stmt_iterator i;
00287       for (i = bsi_start (bb); !bsi_end_p (i); bsi_next (&i))
00288         {
00289           tree stmt = bsi_stmt (i);
00290           tree call;
00291 
00292           if (TREE_CODE (stmt) == MODIFY_EXPR
00293               && (call = TREE_OPERAND (stmt, 1),
00294                   TREE_CODE (call) == CALL_EXPR)
00295               && !CALL_EXPR_RETURN_SLOT_OPT (call)
00296               && aggregate_value_p (call, call))
00297             /* Check if the location being assigned to is
00298                call-clobbered.  */
00299             CALL_EXPR_RETURN_SLOT_OPT (call) =
00300               dest_safe_for_nrv_p (TREE_OPERAND (stmt, 0)) ? 1 : 0;
00301         }
00302     }
00303   return 0;
00304 }

static tree finalize_nrv_r  )  [static]
 

Callback for the tree walker.

   If TP refers to a RETURN_EXPR, then set the expression being returned
   to nrv_data->result.

   If TP refers to nrv_data->var, then replace nrv_data->var with
   nrv_data->result.

   If we reach a node where we know all the subtrees are uninteresting,
   then set *WALK_SUBTREES to zero.   

Definition at line 76 of file tree-nrv.c.

References NULL_TREE, nrv_data::result, TYPE_P, and nrv_data::var.

00077 {
00078   struct nrv_data *dp = (struct nrv_data *)data;
00079 
00080   /* No need to walk into types.  */
00081   if (TYPE_P (*tp))
00082     *walk_subtrees = 0;
00083 
00084   /* Otherwise replace all occurrences of VAR with RESULT.  */
00085   else if (*tp == dp->var)
00086     *tp = dp->result;
00087 
00088   /* Keep iterating.  */
00089   return NULL_TREE;
00090 }

static tree finalize_nrv_r tree *  ,
int *  ,
void * 
[static]
 

static unsigned int tree_nrv  )  [static]
 

Main entry point for return value optimizations.

   If this function always returns the same local variable, and that
   local variable is an aggregate type, then replace the variable with
   the function's DECL_RESULT.

   This is the equivalent of the C++ named return value optimization
   applied to optimized trees in a language independent form.  If we
   ever encounter languages which prevent this kind of optimization,
   then we could either have the languages register the optimization or
   we could change the gating function to check the current language.   

Definition at line 105 of file tree-nrv.c.

References aggregate_value_p(), bsi_end_p(), bsi_next(), bsi_start, bsi_stmt(), current_function_decl, DECL_ALIGN, DECL_CONTEXT, DECL_RESULT, nrv_data::result, TREE_ADDRESSABLE, TREE_CODE, TREE_OPERAND, TREE_STATIC, TREE_THIS_VOLATILE, and TREE_TYPE.

00106 {
00107   tree result = DECL_RESULT (current_function_decl);
00108   tree result_type = TREE_TYPE (result);
00109   tree found = NULL;
00110   basic_block bb;
00111   block_stmt_iterator bsi;
00112   struct nrv_data data;
00113 
00114   /* If this function does not return an aggregate type in memory, then
00115      there is nothing to do.  */
00116   if (!aggregate_value_p (result, current_function_decl))
00117     return 0;
00118 
00119   /* Look through each block for assignments to the RESULT_DECL.  */
00120   FOR_EACH_BB (bb)
00121     {
00122       for (bsi = bsi_start (bb); !bsi_end_p (bsi); bsi_next (&bsi))
00123         {
00124           tree stmt = bsi_stmt (bsi);
00125           tree ret_expr;
00126 
00127           if (TREE_CODE (stmt) == RETURN_EXPR)
00128             {
00129               /* In a function with an aggregate return value, the
00130                  gimplifier has changed all non-empty RETURN_EXPRs to
00131                  return the RESULT_DECL.  */
00132               ret_expr = TREE_OPERAND (stmt, 0);
00133               if (ret_expr)
00134                 gcc_assert (ret_expr == result);
00135             }
00136           else if (TREE_CODE (stmt) == MODIFY_EXPR
00137                    && TREE_OPERAND (stmt, 0) == result)
00138             {
00139               ret_expr = TREE_OPERAND (stmt, 1);
00140 
00141               /* Now verify that this return statement uses the same value
00142                  as any previously encountered return statement.  */
00143               if (found != NULL)
00144                 {
00145                   /* If we found a return statement using a different variable
00146                      than previous return statements, then we can not perform
00147                      NRV optimizations.  */
00148                   if (found != ret_expr)
00149                     return 0;
00150                 }
00151               else
00152                 found = ret_expr;
00153 
00154               /* The returned value must be a local automatic variable of the
00155                  same type and alignment as the function's result.  */
00156               if (TREE_CODE (found) != VAR_DECL
00157                   || TREE_THIS_VOLATILE (found)
00158                   || DECL_CONTEXT (found) != current_function_decl
00159                   || TREE_STATIC (found)
00160                   || TREE_ADDRESSABLE (found)
00161                   || DECL_ALIGN (found) > DECL_ALIGN (result)
00162                   || !lang_hooks.types_compatible_p (TREE_TYPE (found), 
00163                                                      result_type))
00164                 return 0;
00165             }
00166         }
00167     }
00168 
00169   if (!found)
00170     return 0;
00171 
00172   /* If dumping details, then note once and only the NRV replacement.  */
00173   if (dump_file && (dump_flags & TDF_DETAILS))
00174     {
00175       fprintf (dump_file, "NRV Replaced: ");
00176       print_generic_expr (dump_file, found, dump_flags);
00177       fprintf (dump_file, "  with: ");
00178       print_generic_expr (dump_file, result, dump_flags);
00179       fprintf (dump_file, "\n");
00180     }
00181 
00182   /* At this point we know that all the return statements return the
00183      same local which has suitable attributes for NRV.   Copy debugging
00184      information from FOUND to RESULT.  */
00185   DECL_NAME (result) = DECL_NAME (found);
00186   DECL_SOURCE_LOCATION (result) = DECL_SOURCE_LOCATION (found);
00187   DECL_ABSTRACT_ORIGIN (result) = DECL_ABSTRACT_ORIGIN (found);
00188   TREE_ADDRESSABLE (result) = TREE_ADDRESSABLE (found);
00189 
00190   /* Now walk through the function changing all references to VAR to be
00191      RESULT.  */
00192   data.var = found;
00193   data.result = result;
00194   FOR_EACH_BB (bb)
00195     {
00196       for (bsi = bsi_start (bb); !bsi_end_p (bsi); )
00197         {
00198           tree *tp = bsi_stmt_ptr (bsi);
00199           /* If this is a copy from VAR to RESULT, remove it.  */
00200           if (TREE_CODE (*tp) == MODIFY_EXPR
00201               && TREE_OPERAND (*tp, 0) == result
00202               && TREE_OPERAND (*tp, 1) == found)
00203             bsi_remove (&bsi, true);
00204           else
00205             {
00206               walk_tree (tp, finalize_nrv_r, &data, 0);
00207               bsi_next (&bsi);
00208             }
00209         }
00210     }
00211 
00212   /* FOUND is no longer used.  Ensure it gets removed.  */
00213   var_ann (found)->used = 0;
00214   return 0;
00215 }


Variable Documentation

struct tree_opt_pass pass_nrv
 

Initial value:

 
{
  "nrv",                                
  NULL,                                 
  tree_nrv,                             
  NULL,                                 
  NULL,                                 
  0,                                    
  TV_TREE_NRV,                          
  PROP_cfg,                             
  0,                                    
  0,                                    
  0,                                    
  TODO_dump_func | TODO_ggc_collect,                    
  0                                     
}

Definition at line 217 of file tree-nrv.c.

struct tree_opt_pass pass_return_slot
 

Initial value:

 
{
  "retslot",                            
  NULL,                                 
  execute_return_slot_opt,              
  NULL,                                 
  NULL,                                 
  0,                                    
  0,                                    
  PROP_ssa | PROP_alias,                
  0,                                    
  0,                                    
  0,                                    
  0,                                    
  0                                     
}

Definition at line 306 of file tree-nrv.c.


Generated on Sun Sep 17 18:03:48 2006 for Tree SSA by  doxygen 1.4.6