#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 |
|
|
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 }
|
|
|
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 }
|
|
|
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 }
|
|
||||||||||||||||
|
|
|
|
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 }
|
|
|
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. |
|
|
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. |
1.4.6