]>
Commit | Line | Data |
---|---|---|
46e8c075 | 1 | /* Perform optimizations on tree structure. |
eb0424da | 2 | Copyright (C) 1998, 1999, 2000, 2001, 2002 Free Software Foundation, Inc. |
46e8c075 MM |
3 | Written by Mark Michell (mark@codesourcery.com). |
4 | ||
f5adbb8d | 5 | This file is part of GCC. |
46e8c075 | 6 | |
f5adbb8d | 7 | GCC is free software; you can redistribute it and/or modify it |
06ceef4e RK |
8 | under the terms of the GNU General Public License as published by |
9 | the Free Software Foundation; either version 2, or (at your option) | |
10 | any later version. | |
11 | ||
f5adbb8d | 12 | GCC is distributed in the hope that it will be useful, but |
06ceef4e RK |
13 | WITHOUT ANY WARRANTY; without even the implied warranty of |
14 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |
15 | General Public License for more details. | |
9c96f3f8 | 16 | |
06ceef4e | 17 | You should have received a copy of the GNU General Public License |
f5adbb8d | 18 | along with GCC; see the file COPYING. If not, write to the Free |
06ceef4e RK |
19 | Software Foundation, 59 Temple Place - Suite 330, Boston, MA |
20 | 02111-1307, USA. */ | |
46e8c075 MM |
21 | |
22 | #include "config.h" | |
23 | #include "system.h" | |
4977bab6 ZW |
24 | #include "coretypes.h" |
25 | #include "tm.h" | |
46e8c075 MM |
26 | #include "tree.h" |
27 | #include "cp-tree.h" | |
28 | #include "rtl.h" | |
29 | #include "insn-config.h" | |
574a0ef5 | 30 | #include "input.h" |
46e8c075 | 31 | #include "integrate.h" |
9c96f3f8 | 32 | #include "toplev.h" |
46e8c075 | 33 | #include "varray.h" |
b850de4f | 34 | #include "params.h" |
11fe225a | 35 | #include "hashtab.h" |
2b85879e | 36 | #include "debug.h" |
25af8512 | 37 | #include "tree-inline.h" |
46e8c075 | 38 | |
46e8c075 MM |
39 | /* Prototypes. */ |
40 | ||
4977bab6 ZW |
41 | static tree calls_setjmp_r (tree *, int *, void *); |
42 | static void update_cloned_parm (tree, tree); | |
43 | static void dump_function (enum tree_dump_index, tree); | |
390f4e9a | 44 | |
c6002625 | 45 | /* Optimize the body of FN. */ |
46e8c075 MM |
46 | |
47 | void | |
4977bab6 | 48 | optimize_function (tree fn) |
46e8c075 | 49 | { |
b7442fb5 NS |
50 | dump_function (TDI_original, fn); |
51 | ||
b2244c65 MM |
52 | /* While in this function, we may choose to go off and compile |
53 | another function. For example, we might instantiate a function | |
54 | in the hopes of inlining it. Normally, that wouldn't trigger any | |
55 | actual RTL code-generation -- but it will if the template is | |
56 | actually needed. (For example, if it's address is taken, or if | |
57 | some other function already refers to the template.) If | |
58 | code-generation occurs, then garbage collection will occur, so we | |
59 | must protect ourselves, just as we do while building up the body | |
60 | of the function. */ | |
61 | ++function_depth; | |
62 | ||
6be77748 NS |
63 | if (flag_inline_trees |
64 | /* We do not inline thunks, as (a) the backend tries to optimize | |
65 | the call to the thunkee, (b) tree based inlining breaks that | |
66 | optimization, (c) virtual functions are rarely inlineable, | |
eb0424da | 67 | and (d) TARGET_ASM_OUTPUT_MI_THUNK is there to DTRT anyway. */ |
6be77748 | 68 | && !DECL_THUNK_P (fn)) |
25af8512 AO |
69 | { |
70 | optimize_inline_calls (fn); | |
71 | ||
72 | dump_function (TDI_inlined, fn); | |
73 | } | |
6be77748 | 74 | |
b2244c65 MM |
75 | /* Undo the call to ggc_push_context above. */ |
76 | --function_depth; | |
b7442fb5 NS |
77 | |
78 | dump_function (TDI_optimized, fn); | |
46e8c075 | 79 | } |
95fabfd3 MM |
80 | |
81 | /* Called from calls_setjmp_p via walk_tree. */ | |
82 | ||
83 | static tree | |
4977bab6 ZW |
84 | calls_setjmp_r (tree *tp, int *walk_subtrees ATTRIBUTE_UNUSED, |
85 | void *data ATTRIBUTE_UNUSED) | |
95fabfd3 | 86 | { |
95fabfd3 MM |
87 | /* We're only interested in FUNCTION_DECLS. */ |
88 | if (TREE_CODE (*tp) != FUNCTION_DECL) | |
89 | return NULL_TREE; | |
90 | ||
c9fff01f | 91 | return setjmp_call_p (*tp) ? *tp : NULL_TREE; |
95fabfd3 MM |
92 | } |
93 | ||
838dfd8a | 94 | /* Returns nonzero if FN calls `setjmp' or some other function that |
95fabfd3 | 95 | can return more than once. This function is conservative; it may |
838dfd8a | 96 | occasionally return a nonzero value even when FN does not actually |
95fabfd3 MM |
97 | call `setjmp'. */ |
98 | ||
4977bab6 ZW |
99 | bool |
100 | calls_setjmp_p (tree fn) | |
95fabfd3 | 101 | { |
9c96f3f8 AJ |
102 | return walk_tree_without_duplicates (&DECL_SAVED_TREE (fn), |
103 | calls_setjmp_r, | |
ee94fce6 | 104 | NULL) != NULL_TREE; |
95fabfd3 MM |
105 | } |
106 | ||
d60e5448 MM |
107 | /* CLONED_PARM is a copy of CLONE, generated for a cloned constructor |
108 | or destructor. Update it to ensure that the source-position for | |
109 | the cloned parameter matches that for the original, and that the | |
110 | debugging generation code will be able to find the original PARM. */ | |
111 | ||
112 | static void | |
4977bab6 | 113 | update_cloned_parm (tree parm, tree cloned_parm) |
d60e5448 MM |
114 | { |
115 | DECL_ABSTRACT_ORIGIN (cloned_parm) = parm; | |
d30a825a | 116 | |
c6002625 | 117 | /* We may have taken its address. */ |
d30a825a NS |
118 | TREE_ADDRESSABLE (cloned_parm) = TREE_ADDRESSABLE (parm); |
119 | ||
c6002625 | 120 | /* The definition might have different constness. */ |
d30a825a NS |
121 | TREE_READONLY (cloned_parm) = TREE_READONLY (parm); |
122 | ||
123 | TREE_USED (cloned_parm) = TREE_USED (parm); | |
d60e5448 | 124 | |
c6002625 | 125 | /* The name may have changed from the declaration. */ |
d60e5448 | 126 | DECL_NAME (cloned_parm) = DECL_NAME (parm); |
3e72ec9a | 127 | DECL_SOURCE_LOCATION (cloned_parm) = DECL_SOURCE_LOCATION (parm); |
d60e5448 MM |
128 | } |
129 | ||
db9b2174 | 130 | /* FN is a function that has a complete body. Clone the body as |
838dfd8a | 131 | necessary. Returns nonzero if there's no longer any need to |
db9b2174 MM |
132 | process the main body. */ |
133 | ||
4977bab6 ZW |
134 | bool |
135 | maybe_clone_body (tree fn) | |
db9b2174 | 136 | { |
db9b2174 | 137 | tree clone; |
4977bab6 | 138 | bool first = true; |
db9b2174 | 139 | |
db9b2174 MM |
140 | /* We only clone constructors and destructors. */ |
141 | if (!DECL_MAYBE_IN_CHARGE_CONSTRUCTOR_P (fn) | |
142 | && !DECL_MAYBE_IN_CHARGE_DESTRUCTOR_P (fn)) | |
143 | return 0; | |
144 | ||
5daf7c0a | 145 | /* Emit the DWARF1 abstract instance. */ |
2b85879e | 146 | (*debug_hooks->deferred_inline_function) (fn); |
5daf7c0a | 147 | |
db9b2174 MM |
148 | /* We know that any clones immediately follow FN in the TYPE_METHODS |
149 | list. */ | |
150 | for (clone = TREE_CHAIN (fn); | |
151 | clone && DECL_CLONED_FUNCTION_P (clone); | |
4977bab6 | 152 | clone = TREE_CHAIN (clone), first = false) |
db9b2174 MM |
153 | { |
154 | tree parm; | |
155 | tree clone_parm; | |
156 | int parmno; | |
25af8512 | 157 | splay_tree decl_map; |
db9b2174 MM |
158 | |
159 | /* Update CLONE's source position information to match FN's. */ | |
3e72ec9a | 160 | DECL_SOURCE_LOCATION (clone) = DECL_SOURCE_LOCATION (fn); |
99389463 | 161 | DECL_INLINE (clone) = DECL_INLINE (fn); |
bc522472 | 162 | DID_INLINE_FUNC (clone) = DID_INLINE_FUNC (fn); |
79065db2 | 163 | DECL_DECLARED_INLINE_P (clone) = DECL_DECLARED_INLINE_P (fn); |
3ec6bad3 MM |
164 | DECL_COMDAT (clone) = DECL_COMDAT (fn); |
165 | DECL_WEAK (clone) = DECL_WEAK (fn); | |
166 | DECL_ONE_ONLY (clone) = DECL_ONE_ONLY (fn); | |
167 | DECL_SECTION_NAME (clone) = DECL_SECTION_NAME (fn); | |
459c43ad MM |
168 | DECL_USE_TEMPLATE (clone) = DECL_USE_TEMPLATE (fn); |
169 | DECL_EXTERNAL (clone) = DECL_EXTERNAL (fn); | |
170 | DECL_INTERFACE_KNOWN (clone) = DECL_INTERFACE_KNOWN (fn); | |
171 | DECL_NOT_REALLY_EXTERN (clone) = DECL_NOT_REALLY_EXTERN (fn); | |
b96ada87 | 172 | TREE_PUBLIC (clone) = TREE_PUBLIC (fn); |
db9b2174 | 173 | |
c6002625 | 174 | /* Adjust the parameter names and locations. */ |
02a1a68c NS |
175 | parm = DECL_ARGUMENTS (fn); |
176 | clone_parm = DECL_ARGUMENTS (clone); | |
4a90862e | 177 | /* Update the `this' parameter, which is always first. */ |
d60e5448 | 178 | update_cloned_parm (parm, clone_parm); |
4a90862e JM |
179 | parm = TREE_CHAIN (parm); |
180 | clone_parm = TREE_CHAIN (clone_parm); | |
02a1a68c NS |
181 | if (DECL_HAS_IN_CHARGE_PARM_P (fn)) |
182 | parm = TREE_CHAIN (parm); | |
183 | if (DECL_HAS_VTT_PARM_P (fn)) | |
184 | parm = TREE_CHAIN (parm); | |
185 | if (DECL_HAS_VTT_PARM_P (clone)) | |
186 | clone_parm = TREE_CHAIN (clone_parm); | |
187 | for (; parm; | |
188 | parm = TREE_CHAIN (parm), clone_parm = TREE_CHAIN (clone_parm)) | |
189 | { | |
aba649ba | 190 | /* Update this parameter. */ |
d60e5448 | 191 | update_cloned_parm (parm, clone_parm); |
c6002625 | 192 | /* We should only give unused information for one clone. */ |
02a1a68c NS |
193 | if (!first) |
194 | TREE_USED (clone_parm) = 1; | |
195 | } | |
196 | ||
db9b2174 MM |
197 | /* Start processing the function. */ |
198 | push_to_top_level (); | |
199 | start_function (NULL_TREE, clone, NULL_TREE, SF_PRE_PARSED); | |
db9b2174 | 200 | |
db9b2174 | 201 | /* Remap the parameters. */ |
25af8512 | 202 | decl_map = splay_tree_new (splay_tree_compare_pointers, NULL, NULL); |
db9b2174 MM |
203 | for (parmno = 0, |
204 | parm = DECL_ARGUMENTS (fn), | |
205 | clone_parm = DECL_ARGUMENTS (clone); | |
206 | parm; | |
207 | ++parmno, | |
208 | parm = TREE_CHAIN (parm)) | |
209 | { | |
210 | /* Map the in-charge parameter to an appropriate constant. */ | |
211 | if (DECL_HAS_IN_CHARGE_PARM_P (fn) && parmno == 1) | |
212 | { | |
213 | tree in_charge; | |
298d6f60 | 214 | in_charge = in_charge_arg_for_name (DECL_NAME (clone)); |
25af8512 | 215 | splay_tree_insert (decl_map, |
db9b2174 | 216 | (splay_tree_key) parm, |
3ec6bad3 | 217 | (splay_tree_value) in_charge); |
e0fff4b3 JM |
218 | } |
219 | else if (DECL_ARTIFICIAL (parm) | |
220 | && DECL_NAME (parm) == vtt_parm_identifier) | |
221 | { | |
3ec6bad3 MM |
222 | /* For a subobject constructor or destructor, the next |
223 | argument is the VTT parameter. Remap the VTT_PARM | |
224 | from the CLONE to this parameter. */ | |
e0fff4b3 | 225 | if (DECL_HAS_VTT_PARM_P (clone)) |
3ec6bad3 | 226 | { |
5daf7c0a | 227 | DECL_ABSTRACT_ORIGIN (clone_parm) = parm; |
25af8512 | 228 | splay_tree_insert (decl_map, |
e0fff4b3 | 229 | (splay_tree_key) parm, |
3ec6bad3 | 230 | (splay_tree_value) clone_parm); |
3ec6bad3 MM |
231 | clone_parm = TREE_CHAIN (clone_parm); |
232 | } | |
233 | /* Otherwise, map the VTT parameter to `NULL'. */ | |
e0fff4b3 | 234 | else |
3ec6bad3 | 235 | { |
25af8512 | 236 | splay_tree_insert (decl_map, |
e0fff4b3 | 237 | (splay_tree_key) parm, |
3ec6bad3 | 238 | (splay_tree_value) null_pointer_node); |
3ec6bad3 | 239 | } |
db9b2174 MM |
240 | } |
241 | /* Map other parameters to their equivalents in the cloned | |
242 | function. */ | |
243 | else | |
244 | { | |
25af8512 | 245 | splay_tree_insert (decl_map, |
db9b2174 MM |
246 | (splay_tree_key) parm, |
247 | (splay_tree_value) clone_parm); | |
248 | clone_parm = TREE_CHAIN (clone_parm); | |
249 | } | |
250 | } | |
251 | ||
25af8512 AO |
252 | /* Clone the body. */ |
253 | clone_body (clone, fn, decl_map); | |
db9b2174 | 254 | |
9b7949d5 MM |
255 | /* There are as many statements in the clone as in the |
256 | original. */ | |
257 | DECL_NUM_STMTS (clone) = DECL_NUM_STMTS (fn); | |
258 | ||
db9b2174 | 259 | /* Clean up. */ |
25af8512 | 260 | splay_tree_delete (decl_map); |
db9b2174 | 261 | |
b2dd096b MM |
262 | /* The clone can throw iff the original function can throw. */ |
263 | cp_function_chain->can_throw = !TREE_NOTHROW (fn); | |
264 | ||
db9b2174 | 265 | /* Now, expand this function into RTL, if appropriate. */ |
5daf7c0a JM |
266 | finish_function (0); |
267 | BLOCK_ABSTRACT_ORIGIN (DECL_INITIAL (clone)) = DECL_INITIAL (fn); | |
268 | expand_body (clone); | |
db9b2174 MM |
269 | pop_from_top_level (); |
270 | } | |
9c96f3f8 | 271 | |
db9b2174 MM |
272 | /* We don't need to process the original function any further. */ |
273 | return 1; | |
274 | } | |
b7442fb5 | 275 | |
c6002625 | 276 | /* Dump FUNCTION_DECL FN as tree dump PHASE. */ |
b7442fb5 NS |
277 | |
278 | static void | |
4977bab6 | 279 | dump_function (enum tree_dump_index phase, tree fn) |
b7442fb5 NS |
280 | { |
281 | FILE *stream; | |
282 | int flags; | |
283 | ||
284 | stream = dump_begin (phase, &flags); | |
285 | if (stream) | |
286 | { | |
287 | fprintf (stream, "\n;; Function %s", | |
288 | decl_as_string (fn, TFF_DECL_SPECIFIERS)); | |
6be77748 NS |
289 | fprintf (stream, " (%s)\n", |
290 | decl_as_string (DECL_ASSEMBLER_NAME (fn), 0)); | |
291 | fprintf (stream, ";; enabled by -%s\n", dump_flag_name (phase)); | |
292 | fprintf (stream, "\n"); | |
b7442fb5 NS |
293 | |
294 | dump_node (fn, TDF_SLIM | flags, stream); | |
295 | dump_end (phase, stream); | |
296 | } | |
297 | } |