1169689Skan/* Language independent return value optimizations 2169689Skan Copyright (C) 2004, 2005 Free Software Foundation, Inc. 3169689Skan 4169689SkanThis file is part of GCC. 5169689Skan 6169689SkanGCC is free software; you can redistribute it and/or modify 7169689Skanit under the terms of the GNU General Public License as published by 8169689Skanthe Free Software Foundation; either version 2, or (at your option) 9169689Skanany later version. 10169689Skan 11169689SkanGCC is distributed in the hope that it will be useful, 12169689Skanbut WITHOUT ANY WARRANTY; without even the implied warranty of 13169689SkanMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14169689SkanGNU General Public License for more details. 15169689Skan 16169689SkanYou should have received a copy of the GNU General Public License 17169689Skanalong with GCC; see the file COPYING. If not, write to 18169689Skanthe Free Software Foundation, 51 Franklin Street, Fifth Floor, 19169689SkanBoston, MA 02110-1301, USA. */ 20169689Skan 21169689Skan#include "config.h" 22169689Skan#include "system.h" 23169689Skan#include "coretypes.h" 24169689Skan#include "tm.h" 25169689Skan#include "tree.h" 26169689Skan#include "rtl.h" 27169689Skan#include "function.h" 28169689Skan#include "basic-block.h" 29169689Skan#include "expr.h" 30169689Skan#include "diagnostic.h" 31169689Skan#include "tree-flow.h" 32169689Skan#include "timevar.h" 33169689Skan#include "tree-dump.h" 34169689Skan#include "tree-pass.h" 35169689Skan#include "langhooks.h" 36169689Skan 37169689Skan/* This file implements return value optimizations for functions which 38169689Skan return aggregate types. 39169689Skan 40169689Skan Basically this pass searches the function for return statements which 41169689Skan return a local aggregate. When converted to RTL such statements will 42169689Skan generate a copy from the local aggregate to final return value destination 43169689Skan mandated by the target's ABI. 44169689Skan 45169689Skan That copy can often be avoided by directly constructing the return value 46169689Skan into the final destination mandated by the target's ABI. 47169689Skan 48169689Skan This is basically a generic equivalent to the C++ front-end's 49169689Skan Named Return Value optimization. */ 50169689Skan 51169689Skanstruct nrv_data 52169689Skan{ 53169689Skan /* This is the temporary (a VAR_DECL) which appears in all of 54169689Skan this function's RETURN_EXPR statements. */ 55169689Skan tree var; 56169689Skan 57169689Skan /* This is the function's RESULT_DECL. We will replace all occurrences 58169689Skan of VAR with RESULT_DECL when we apply this optimization. */ 59169689Skan tree result; 60169689Skan}; 61169689Skan 62169689Skanstatic tree finalize_nrv_r (tree *, int *, void *); 63169689Skan 64169689Skan/* Callback for the tree walker. 65169689Skan 66169689Skan If TP refers to a RETURN_EXPR, then set the expression being returned 67169689Skan to nrv_data->result. 68169689Skan 69169689Skan If TP refers to nrv_data->var, then replace nrv_data->var with 70169689Skan nrv_data->result. 71169689Skan 72169689Skan If we reach a node where we know all the subtrees are uninteresting, 73169689Skan then set *WALK_SUBTREES to zero. */ 74169689Skan 75169689Skanstatic tree 76169689Skanfinalize_nrv_r (tree *tp, int *walk_subtrees, void *data) 77169689Skan{ 78169689Skan struct nrv_data *dp = (struct nrv_data *)data; 79169689Skan 80169689Skan /* No need to walk into types. */ 81169689Skan if (TYPE_P (*tp)) 82169689Skan *walk_subtrees = 0; 83169689Skan 84169689Skan /* Otherwise replace all occurrences of VAR with RESULT. */ 85169689Skan else if (*tp == dp->var) 86169689Skan *tp = dp->result; 87169689Skan 88169689Skan /* Keep iterating. */ 89169689Skan return NULL_TREE; 90169689Skan} 91169689Skan 92169689Skan/* Main entry point for return value optimizations. 93169689Skan 94169689Skan If this function always returns the same local variable, and that 95169689Skan local variable is an aggregate type, then replace the variable with 96169689Skan the function's DECL_RESULT. 97169689Skan 98169689Skan This is the equivalent of the C++ named return value optimization 99169689Skan applied to optimized trees in a language independent form. If we 100169689Skan ever encounter languages which prevent this kind of optimization, 101169689Skan then we could either have the languages register the optimization or 102169689Skan we could change the gating function to check the current language. */ 103169689Skan 104169689Skanstatic unsigned int 105169689Skantree_nrv (void) 106169689Skan{ 107169689Skan tree result = DECL_RESULT (current_function_decl); 108169689Skan tree result_type = TREE_TYPE (result); 109169689Skan tree found = NULL; 110169689Skan basic_block bb; 111169689Skan block_stmt_iterator bsi; 112169689Skan struct nrv_data data; 113169689Skan 114169689Skan /* If this function does not return an aggregate type in memory, then 115169689Skan there is nothing to do. */ 116169689Skan if (!aggregate_value_p (result, current_function_decl)) 117169689Skan return 0; 118169689Skan 119169689Skan /* Look through each block for assignments to the RESULT_DECL. */ 120169689Skan FOR_EACH_BB (bb) 121169689Skan { 122169689Skan for (bsi = bsi_start (bb); !bsi_end_p (bsi); bsi_next (&bsi)) 123169689Skan { 124169689Skan tree stmt = bsi_stmt (bsi); 125169689Skan tree ret_expr; 126169689Skan 127169689Skan if (TREE_CODE (stmt) == RETURN_EXPR) 128169689Skan { 129169689Skan /* In a function with an aggregate return value, the 130169689Skan gimplifier has changed all non-empty RETURN_EXPRs to 131169689Skan return the RESULT_DECL. */ 132169689Skan ret_expr = TREE_OPERAND (stmt, 0); 133169689Skan if (ret_expr) 134169689Skan gcc_assert (ret_expr == result); 135169689Skan } 136169689Skan else if (TREE_CODE (stmt) == MODIFY_EXPR 137169689Skan && TREE_OPERAND (stmt, 0) == result) 138169689Skan { 139169689Skan ret_expr = TREE_OPERAND (stmt, 1); 140169689Skan 141169689Skan /* Now verify that this return statement uses the same value 142169689Skan as any previously encountered return statement. */ 143169689Skan if (found != NULL) 144169689Skan { 145169689Skan /* If we found a return statement using a different variable 146169689Skan than previous return statements, then we can not perform 147169689Skan NRV optimizations. */ 148169689Skan if (found != ret_expr) 149169689Skan return 0; 150169689Skan } 151169689Skan else 152169689Skan found = ret_expr; 153169689Skan 154169689Skan /* The returned value must be a local automatic variable of the 155169689Skan same type and alignment as the function's result. */ 156169689Skan if (TREE_CODE (found) != VAR_DECL 157169689Skan || TREE_THIS_VOLATILE (found) 158169689Skan || DECL_CONTEXT (found) != current_function_decl 159169689Skan || TREE_STATIC (found) 160169689Skan || TREE_ADDRESSABLE (found) 161169689Skan || DECL_ALIGN (found) > DECL_ALIGN (result) 162169689Skan || !lang_hooks.types_compatible_p (TREE_TYPE (found), 163169689Skan result_type)) 164169689Skan return 0; 165169689Skan } 166169689Skan else if (TREE_CODE (stmt) == MODIFY_EXPR) 167169689Skan { 168169689Skan tree addr = get_base_address (TREE_OPERAND (stmt, 0)); 169169689Skan /* If there's any MODIFY of component of RESULT, 170169689Skan then bail out. */ 171169689Skan if (addr && addr == result) 172169689Skan return 0; 173169689Skan } 174169689Skan } 175169689Skan } 176169689Skan 177169689Skan if (!found) 178169689Skan return 0; 179169689Skan 180169689Skan /* If dumping details, then note once and only the NRV replacement. */ 181169689Skan if (dump_file && (dump_flags & TDF_DETAILS)) 182169689Skan { 183169689Skan fprintf (dump_file, "NRV Replaced: "); 184169689Skan print_generic_expr (dump_file, found, dump_flags); 185169689Skan fprintf (dump_file, " with: "); 186169689Skan print_generic_expr (dump_file, result, dump_flags); 187169689Skan fprintf (dump_file, "\n"); 188169689Skan } 189169689Skan 190169689Skan /* At this point we know that all the return statements return the 191169689Skan same local which has suitable attributes for NRV. Copy debugging 192169689Skan information from FOUND to RESULT. */ 193169689Skan DECL_NAME (result) = DECL_NAME (found); 194169689Skan DECL_SOURCE_LOCATION (result) = DECL_SOURCE_LOCATION (found); 195169689Skan DECL_ABSTRACT_ORIGIN (result) = DECL_ABSTRACT_ORIGIN (found); 196169689Skan TREE_ADDRESSABLE (result) = TREE_ADDRESSABLE (found); 197169689Skan 198169689Skan /* Now walk through the function changing all references to VAR to be 199169689Skan RESULT. */ 200169689Skan data.var = found; 201169689Skan data.result = result; 202169689Skan FOR_EACH_BB (bb) 203169689Skan { 204169689Skan for (bsi = bsi_start (bb); !bsi_end_p (bsi); ) 205169689Skan { 206169689Skan tree *tp = bsi_stmt_ptr (bsi); 207169689Skan /* If this is a copy from VAR to RESULT, remove it. */ 208169689Skan if (TREE_CODE (*tp) == MODIFY_EXPR 209169689Skan && TREE_OPERAND (*tp, 0) == result 210169689Skan && TREE_OPERAND (*tp, 1) == found) 211169689Skan bsi_remove (&bsi, true); 212169689Skan else 213169689Skan { 214169689Skan walk_tree (tp, finalize_nrv_r, &data, 0); 215169689Skan bsi_next (&bsi); 216169689Skan } 217169689Skan } 218169689Skan } 219169689Skan 220169689Skan /* FOUND is no longer used. Ensure it gets removed. */ 221169689Skan var_ann (found)->used = 0; 222169689Skan return 0; 223169689Skan} 224169689Skan 225169689Skanstruct tree_opt_pass pass_nrv = 226169689Skan{ 227169689Skan "nrv", /* name */ 228169689Skan NULL, /* gate */ 229169689Skan tree_nrv, /* execute */ 230169689Skan NULL, /* sub */ 231169689Skan NULL, /* next */ 232169689Skan 0, /* static_pass_number */ 233169689Skan TV_TREE_NRV, /* tv_id */ 234169689Skan PROP_cfg, /* properties_required */ 235169689Skan 0, /* properties_provided */ 236169689Skan 0, /* properties_destroyed */ 237169689Skan 0, /* todo_flags_start */ 238169689Skan TODO_dump_func | TODO_ggc_collect, /* todo_flags_finish */ 239169689Skan 0 /* letter */ 240169689Skan}; 241169689Skan 242169689Skan/* Determine (pessimistically) whether DEST is available for NRV 243169689Skan optimization, where DEST is expected to be the LHS of a modify 244169689Skan expression where the RHS is a function returning an aggregate. 245169689Skan 246169689Skan We search for a base VAR_DECL and look to see if it, or any of its 247169689Skan subvars are clobbered. Note that we could do better, for example, by 248169689Skan attempting to doing points-to analysis on INDIRECT_REFs. */ 249169689Skan 250169689Skanstatic bool 251169689Skandest_safe_for_nrv_p (tree dest) 252169689Skan{ 253169689Skan switch (TREE_CODE (dest)) 254169689Skan { 255169689Skan case VAR_DECL: 256169689Skan { 257169689Skan subvar_t subvar; 258169689Skan if (is_call_clobbered (dest)) 259169689Skan return false; 260169689Skan for (subvar = get_subvars_for_var (dest); 261169689Skan subvar; 262169689Skan subvar = subvar->next) 263169689Skan if (is_call_clobbered (subvar->var)) 264169689Skan return false; 265169689Skan return true; 266169689Skan } 267169689Skan case ARRAY_REF: 268169689Skan case COMPONENT_REF: 269169689Skan return dest_safe_for_nrv_p (TREE_OPERAND (dest, 0)); 270169689Skan default: 271169689Skan return false; 272169689Skan } 273169689Skan} 274169689Skan 275169689Skan/* Walk through the function looking for MODIFY_EXPRs with calls that 276169689Skan return in memory on the RHS. For each of these, determine whether it is 277169689Skan safe to pass the address of the LHS as the return slot, and mark the 278169689Skan call appropriately if so. 279169689Skan 280169689Skan The NRV shares the return slot with a local variable in the callee; this 281169689Skan optimization shares the return slot with the target of the call within 282169689Skan the caller. If the NRV is performed (which we can't know in general), 283169689Skan this optimization is safe if the address of the target has not 284169689Skan escaped prior to the call. If it has, modifications to the local 285169689Skan variable will produce visible changes elsewhere, as in PR c++/19317. */ 286169689Skan 287169689Skanstatic unsigned int 288169689Skanexecute_return_slot_opt (void) 289169689Skan{ 290169689Skan basic_block bb; 291169689Skan 292169689Skan FOR_EACH_BB (bb) 293169689Skan { 294169689Skan block_stmt_iterator i; 295169689Skan for (i = bsi_start (bb); !bsi_end_p (i); bsi_next (&i)) 296169689Skan { 297169689Skan tree stmt = bsi_stmt (i); 298169689Skan tree call; 299169689Skan 300169689Skan if (TREE_CODE (stmt) == MODIFY_EXPR 301169689Skan && (call = TREE_OPERAND (stmt, 1), 302169689Skan TREE_CODE (call) == CALL_EXPR) 303169689Skan && !CALL_EXPR_RETURN_SLOT_OPT (call) 304169689Skan && aggregate_value_p (call, call)) 305169689Skan /* Check if the location being assigned to is 306169689Skan call-clobbered. */ 307169689Skan CALL_EXPR_RETURN_SLOT_OPT (call) = 308169689Skan dest_safe_for_nrv_p (TREE_OPERAND (stmt, 0)) ? 1 : 0; 309169689Skan } 310169689Skan } 311169689Skan return 0; 312169689Skan} 313169689Skan 314169689Skanstruct tree_opt_pass pass_return_slot = 315169689Skan{ 316169689Skan "retslot", /* name */ 317169689Skan NULL, /* gate */ 318169689Skan execute_return_slot_opt, /* execute */ 319169689Skan NULL, /* sub */ 320169689Skan NULL, /* next */ 321169689Skan 0, /* static_pass_number */ 322169689Skan 0, /* tv_id */ 323169689Skan PROP_ssa | PROP_alias, /* properties_required */ 324169689Skan 0, /* properties_provided */ 325169689Skan 0, /* properties_destroyed */ 326169689Skan 0, /* todo_flags_start */ 327169689Skan 0, /* todo_flags_finish */ 328169689Skan 0 /* letter */ 329169689Skan}; 330