1 /* Control and data flow functions for trees.
2 Copyright 2001, 2002, 2003, 2004 Free Software Foundation, Inc.
4 This file is part of GCC.
6 GCC is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 2, or (at your option)
11 GCC is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 GNU General Public License for more details.
16 You should have received a copy of the GNU General Public License
17 along with GCC; see the file COPYING. If not, write to
18 the Free Software Foundation, 59 Temple Place - Suite 330,
19 Boston, MA 02111-1307, USA. */
23 #include "coretypes.h"
26 #include "tree-inline.h"
28 #include "langhooks.h"
36 /* Called to move the SAVE_EXPRs for parameter declarations in a
37 nested function into the nested function. DATA is really the
38 nested FUNCTION_DECL. */
41 set_save_expr_context (tree
*tp
,
45 if (TREE_CODE (*tp
) == SAVE_EXPR
&& !SAVE_EXPR_CONTEXT (*tp
))
46 SAVE_EXPR_CONTEXT (*tp
) = (tree
) data
;
47 /* Do not walk back into the SAVE_EXPR_CONTEXT; that will cause
49 else if (DECL_P (*tp
))
55 /* Clear out the DECL_RTL for the non-static local variables in BLOCK and
56 its sub-blocks. DATA is the decl of the function being processed. */
59 clear_decl_rtl (tree
*tp
, int *walk_subtrees ATTRIBUTE_UNUSED
, void *data
)
61 bool nonstatic_p
, local_p
;
64 switch (TREE_CODE (t
))
67 nonstatic_p
= !TREE_STATIC (t
) && !DECL_EXTERNAL (t
);
68 local_p
= decl_function_context (t
) == data
;
74 local_p
= decl_function_context (t
) == data
;
78 nonstatic_p
= local_p
= true;
82 nonstatic_p
= local_p
= false;
86 if (nonstatic_p
&& local_p
)
87 SET_DECL_RTL (t
, NULL
);
92 /* For functions-as-trees languages, this performs all optimization and
93 compilation for FNDECL. */
96 tree_rest_of_compilation (tree fndecl
, bool nested_p
)
99 struct cgraph_node
*node
, *saved_node
= NULL
;
101 timevar_push (TV_EXPAND
);
103 if (flag_unit_at_a_time
&& !cgraph_global_info_ready
)
106 /* Initialize the RTL code for the function. */
107 current_function_decl
= fndecl
;
108 saved_loc
= input_location
;
109 input_location
= DECL_SOURCE_LOCATION (fndecl
);
110 init_function_start (fndecl
);
112 /* This function is being processed in whole-function mode. */
113 cfun
->x_whole_function_mode_p
= 1;
115 /* Even though we're inside a function body, we still don't want to
116 call expand_expr to calculate the size of a variable-sized array.
117 We haven't necessarily assigned RTL to all variables yet, so it's
118 not safe to try to expand expressions involving them. */
119 immediate_size_expand
= 0;
120 cfun
->x_dont_save_pending_sizes_p
= 1;
122 node
= cgraph_node (fndecl
);
124 /* We might need the body of this function so that we can expand
125 it inline somewhere else. This means not lowering some constructs
126 such as exception handling. */
127 if (cgraph_preserve_function_body_p (fndecl
))
129 if (!flag_unit_at_a_time
)
131 struct cgraph_edge
*e
;
133 saved_node
= cgraph_clone_node (node
);
134 for (e
= saved_node
->callees
; e
; e
= e
->next_callee
)
135 if (!e
->inline_failed
)
136 cgraph_clone_inlined_nodes (e
, true);
138 cfun
->saved_tree
= save_body (fndecl
, &cfun
->saved_args
);
141 if (flag_inline_trees
)
143 struct cgraph_edge
*e
;
144 for (e
= node
->callees
; e
; e
= e
->next_callee
)
145 if (!e
->inline_failed
|| warn_inline
)
149 timevar_push (TV_INTEGRATION
);
150 optimize_inline_calls (fndecl
);
151 timevar_pop (TV_INTEGRATION
);
155 /* If the function has a variably modified type, there may be
156 SAVE_EXPRs in the parameter types. Their context must be set to
157 refer to this function; they cannot be expanded in the containing
159 if (decl_function_context (fndecl
)
160 && variably_modified_type_p (TREE_TYPE (fndecl
)))
161 walk_tree (&TREE_TYPE (fndecl
), set_save_expr_context
, fndecl
,
164 /* Set up parameters and prepare for return, for the function. */
165 expand_function_start (fndecl
, 0);
167 /* Allow language dialects to perform special processing. */
168 lang_hooks
.rtl_expand
.start ();
170 /* If this function is `main', emit a call to `__main'
171 to run global initializers, etc. */
172 if (DECL_NAME (fndecl
)
173 && MAIN_NAME_P (DECL_NAME (fndecl
))
174 && DECL_FILE_SCOPE_P (fndecl
))
175 expand_main_function ();
177 /* Generate the RTL for this function. */
178 lang_hooks
.rtl_expand
.stmt (DECL_SAVED_TREE (fndecl
));
180 /* We hard-wired immediate_size_expand to zero above.
181 expand_function_end will decrement this variable. So, we set the
182 variable to one here, so that after the decrement it will remain
184 immediate_size_expand
= 1;
186 /* Allow language dialects to perform special processing. */
187 lang_hooks
.rtl_expand
.end ();
189 /* Generate rtl for function exit. */
190 expand_function_end ();
192 /* If this is a nested function, protect the local variables in the stack
193 above us from being collected while we're compiling this function. */
197 /* There's no need to defer outputting this function any more; we
198 know we want to output it. */
199 DECL_DEFER_OUTPUT (fndecl
) = 0;
201 /* Run the optimizers and output the assembler code for this function. */
202 rest_of_compilation (fndecl
);
205 /* Undo the GC context switch. */
209 /* If requested, warn about function definitions where the function will
210 return a value (usually of some struct or union type) which itself will
211 take up a lot of stack space. */
212 if (warn_larger_than
&& !DECL_EXTERNAL (fndecl
) && TREE_TYPE (fndecl
))
214 tree ret_type
= TREE_TYPE (TREE_TYPE (fndecl
));
216 if (ret_type
&& TYPE_SIZE_UNIT (ret_type
)
217 && TREE_CODE (TYPE_SIZE_UNIT (ret_type
)) == INTEGER_CST
218 && 0 < compare_tree_int (TYPE_SIZE_UNIT (ret_type
),
221 unsigned int size_as_int
222 = TREE_INT_CST_LOW (TYPE_SIZE_UNIT (ret_type
));
224 if (compare_tree_int (TYPE_SIZE_UNIT (ret_type
), size_as_int
) == 0)
225 warning ("%Jsize of return value of '%D' is %u bytes",
226 fndecl
, fndecl
, size_as_int
);
228 warning ("%Jsize of return value of '%D' is larger than %wd bytes",
229 fndecl
, fndecl
, larger_than_size
);
233 /* Since we don't need the RTL for this function anymore, stop pointing to
234 it. That's especially important for LABEL_DECLs, since you can reach all
235 the instructions in the function from the CODE_LABEL stored in the
236 DECL_RTL for the LABEL_DECL. Walk the BLOCK-tree, clearing DECL_RTL for
237 LABEL_DECLs and non-static local variables. Note that we must check the
238 context of the variables, otherwise processing a nested function can kill
239 the rtl of a variable from an outer function. */
240 walk_tree_without_duplicates (&DECL_SAVED_TREE (fndecl
),
243 /* Restore original body if still needed. */
244 if (cfun
->saved_tree
)
246 DECL_SAVED_TREE (fndecl
) = cfun
->saved_tree
;
247 DECL_ARGUMENTS (fndecl
) = cfun
->saved_args
;
249 /* When not in unit-at-a-time mode, we must preserve out of line copy
250 representing node before inlining. Restore original outgoing edges
251 using clone we created earlier. */
252 if (!flag_unit_at_a_time
)
254 struct cgraph_edge
*e
;
255 while (node
->callees
)
256 cgraph_remove_edge (node
->callees
);
257 node
->callees
= saved_node
->callees
;
258 saved_node
->callees
= NULL
;
259 for (e
= saved_node
->callees
; e
; e
= e
->next_callee
)
261 cgraph_remove_node (saved_node
);
266 DECL_SAVED_TREE (fndecl
) = NULL
;
267 if (cgraph_node (fndecl
)->origin
)
269 /* Stop pointing to the local nodes about to be freed.
270 But DECL_INITIAL must remain nonzero so we know this
271 was an actual function definition.
272 For a nested function, this is done in c_pop_function_context.
273 If rest_of_compilation set this to 0, leave it 0. */
274 if (DECL_INITIAL (fndecl
) != 0)
275 DECL_INITIAL (fndecl
) = error_mark_node
;
278 free_after_compilation (cfun
);
280 DECL_STRUCT_FUNCTION (fndecl
) = 0;
282 input_location
= saved_loc
;
284 timevar_pop (TV_EXPAND
);