00001 /* Language independent return value optimizations 00002 Copyright (C) 2004, 2005 Free Software Foundation, Inc. 00003 00004 This file is part of GCC. 00005 00006 GCC is free software; you can redistribute it and/or modify 00007 it under the terms of the GNU General Public License as published by 00008 the Free Software Foundation; either version 2, or (at your option) 00009 any later version. 00010 00011 GCC is distributed in the hope that it will be useful, 00012 but WITHOUT ANY WARRANTY; without even the implied warranty of 00013 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 00014 GNU General Public License for more details. 00015 00016 You should have received a copy of the GNU General Public License 00017 along with GCC; see the file COPYING. If not, write to 00018 the Free Software Foundation, 59 Temple Place - Suite 330, 00019 Boston, MA 02111-1307, USA. */ 00020 00021 #include "config.h" 00022 #include "system.h" 00023 #include "coretypes.h" 00024 #include "tm.h" 00025 #include "tree.h" 00026 #include "rtl.h" 00027 #include "function.h" 00028 #include "basic-block.h" 00029 #include "expr.h" 00030 #include "diagnostic.h" 00031 #include "tree-flow.h" 00032 #include "timevar.h" 00033 #include "tree-dump.h" 00034 #include "tree-pass.h" 00035 #include "langhooks.h" 00036 00037 /* This file implements return value optimizations for functions which 00038 return aggregate types. 00039 00040 Basically this pass searches the function for return statements which 00041 return a local aggregate. When converted to RTL such statements will 00042 generate a copy from the local aggregate to final return value destination 00043 mandated by the target's ABI. 00044 00045 That copy can often be avoided by directly constructing the return value 00046 into the final destination mandated by the target's ABI. 00047 00048 This is basically a generic equivalent to the C++ front-end's 00049 Named Return Value optimization. */ 00050 00051 struct nrv_data 00052 { 00053 /* This is the temporary (a VAR_DECL) which appears in all of 00054 this function's RETURN_EXPR statements. */ 00055 tree var; 00056 00057 /* This is the function's RESULT_DECL. We will replace all occurrences 00058 of VAR with RESULT_DECL when we apply this optimization. */ 00059 tree result; 00060 }; 00061 00062 static tree finalize_nrv_r (tree *, int *, void *); 00063 00064 /* Callback for the tree walker. 00065 00066 If TP refers to a RETURN_EXPR, then set the expression being returned 00067 to nrv_data->result. 00068 00069 If TP refers to nrv_data->var, then replace nrv_data->var with 00070 nrv_data->result. 00071 00072 If we reach a node where we know all the subtrees are uninteresting, 00073 then set *WALK_SUBTREES to zero. */ 00074 00075 static tree 00076 finalize_nrv_r (tree *tp, int *walk_subtrees, void *data) 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 /* If this is a RETURN_EXPR, set the expression being returned to RESULT. */ 00085 else if (TREE_CODE (*tp) == RETURN_EXPR) 00086 TREE_OPERAND (*tp, 0) = dp->result; 00087 00088 /* Otherwise replace all occurrences of VAR with RESULT. */ 00089 else if (*tp == dp->var) 00090 *tp = dp->result; 00091 00092 /* Keep iterating. */ 00093 return NULL_TREE; 00094 } 00095 00096 /* Main entry point for return value optimizations. 00097 00098 If this function always returns the same local variable, and that 00099 local variable is an aggregate type, then replace the variable with 00100 the function's DECL_RESULT. 00101 00102 This is the equivalent of the C++ named return value optimization 00103 applied to optimized trees in a language independent form. If we 00104 ever encounter languages which prevent this kind of optimization, 00105 then we could either have the languages register the optimization or 00106 we could change the gating function to check the current language. */ 00107 00108 static void 00109 tree_nrv (void) 00110 { 00111 tree result = DECL_RESULT (current_function_decl); 00112 tree result_type = TREE_TYPE (result); 00113 tree found = NULL; 00114 basic_block bb; 00115 struct nrv_data data; 00116 00117 /* If this function does not return an aggregate type in memory, then 00118 there is nothing to do. */ 00119 if (!aggregate_value_p (result, current_function_decl)) 00120 return; 00121 00122 /* Look through each block for suitable return expressions. RETURN_EXPRs 00123 end basic blocks, so we only have to look at the last statement in 00124 each block. That makes this very fast. */ 00125 FOR_EACH_BB (bb) 00126 { 00127 tree stmt = last_stmt (bb); 00128 00129 if (stmt && TREE_CODE (stmt) == RETURN_EXPR) 00130 { 00131 tree ret_expr = TREE_OPERAND (stmt, 0); 00132 00133 /* This probably should not happen, but just to be safe do 00134 not perform NRV optimizations if only some of the return 00135 statement return a value. */ 00136 if (!ret_expr 00137 || TREE_CODE (ret_expr) != MODIFY_EXPR 00138 || TREE_CODE (TREE_OPERAND (ret_expr, 0)) != RESULT_DECL) 00139 return; 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 != TREE_OPERAND (ret_expr, 1)) 00149 return; 00150 } 00151 else 00152 found = TREE_OPERAND (ret_expr, 1); 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; 00165 } 00166 } 00167 00168 if (!found) 00169 return; 00170 00171 /* If dumping details, then note once and only the NRV replacement. */ 00172 if (dump_file && (dump_flags & TDF_DETAILS)) 00173 { 00174 fprintf (dump_file, "NRV Replaced: "); 00175 print_generic_expr (dump_file, found, dump_flags); 00176 fprintf (dump_file, " with: "); 00177 print_generic_expr (dump_file, result, dump_flags); 00178 fprintf (dump_file, "\n"); 00179 } 00180 00181 /* At this point we know that all the return statements return the 00182 same local which has suitable attributes for NRV. Copy debugging 00183 information from FOUND to RESULT. */ 00184 DECL_NAME (result) = DECL_NAME (found); 00185 DECL_SOURCE_LOCATION (result) = DECL_SOURCE_LOCATION (found); 00186 DECL_ABSTRACT_ORIGIN (result) = DECL_ABSTRACT_ORIGIN (found); 00187 TREE_ADDRESSABLE (result) = TREE_ADDRESSABLE (found); 00188 00189 /* Now walk through the function changing all references to VAR to be 00190 RESULT. */ 00191 data.var = found; 00192 data.result = result; 00193 FOR_EACH_BB (bb) 00194 { 00195 block_stmt_iterator bsi; 00196 00197 for (bsi = bsi_start (bb); !bsi_end_p (bsi); bsi_next (&bsi)) 00198 walk_tree (bsi_stmt_ptr (bsi), finalize_nrv_r, &data, 0); 00199 } 00200 00201 /* FOUND is no longer used. Ensure it gets removed. */ 00202 var_ann (found)->used = 0; 00203 } 00204 00205 struct tree_opt_pass pass_nrv = 00206 { 00207 "nrv", /* name */ 00208 NULL, /* gate */ 00209 tree_nrv, /* execute */ 00210 NULL, /* sub */ 00211 NULL, /* next */ 00212 0, /* static_pass_number */ 00213 TV_TREE_NRV, /* tv_id */ 00214 PROP_cfg, /* properties_required */ 00215 0, /* properties_provided */ 00216 0, /* properties_destroyed */ 00217 0, /* todo_flags_start */ 00218 TODO_dump_func | TODO_ggc_collect, /* todo_flags_finish */ 00219 0 /* letter */ 00220 };
1.5.6