]>
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 | ||
06ceef4e | 5 | This file is part of GNU CC. |
46e8c075 | 6 | |
06ceef4e RK |
7 | GNU CC is free software; you can redistribute it and/or modify it |
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 | ||
12 | GNU CC is distributed in the hope that it will be useful, but | |
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 RK |
17 | You should have received a copy of the GNU General Public License |
18 | along with GNU CC; see the file COPYING. If not, write to the Free | |
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" |
b3bae5e2 | 34 | #include "ggc.h" |
b850de4f | 35 | #include "params.h" |
11fe225a | 36 | #include "hashtab.h" |
2b85879e | 37 | #include "debug.h" |
25af8512 | 38 | #include "tree-inline.h" |
46e8c075 | 39 | |
46e8c075 MM |
40 | /* Prototypes. */ |
41 | ||
4977bab6 ZW |
42 | static tree calls_setjmp_r (tree *, int *, void *); |
43 | static void update_cloned_parm (tree, tree); | |
44 | static void dump_function (enum tree_dump_index, tree); | |
390f4e9a | 45 | |
c6002625 | 46 | /* Optimize the body of FN. */ |
46e8c075 MM |
47 | |
48 | void | |
4977bab6 | 49 | optimize_function (tree fn) |
46e8c075 | 50 | { |
b7442fb5 NS |
51 | dump_function (TDI_original, fn); |
52 | ||
b2244c65 MM |
53 | /* While in this function, we may choose to go off and compile |
54 | another function. For example, we might instantiate a function | |
55 | in the hopes of inlining it. Normally, that wouldn't trigger any | |
56 | actual RTL code-generation -- but it will if the template is | |
57 | actually needed. (For example, if it's address is taken, or if | |
58 | some other function already refers to the template.) If | |
59 | code-generation occurs, then garbage collection will occur, so we | |
60 | must protect ourselves, just as we do while building up the body | |
61 | of the function. */ | |
62 | ++function_depth; | |
63 | ||
6be77748 NS |
64 | if (flag_inline_trees |
65 | /* We do not inline thunks, as (a) the backend tries to optimize | |
66 | the call to the thunkee, (b) tree based inlining breaks that | |
67 | optimization, (c) virtual functions are rarely inlineable, | |
eb0424da | 68 | and (d) TARGET_ASM_OUTPUT_MI_THUNK is there to DTRT anyway. */ |
6be77748 | 69 | && !DECL_THUNK_P (fn)) |
25af8512 AO |
70 | { |
71 | optimize_inline_calls (fn); | |
72 | ||
73 | dump_function (TDI_inlined, fn); | |
74 | } | |
6be77748 | 75 | |
b2244c65 MM |
76 | /* Undo the call to ggc_push_context above. */ |
77 | --function_depth; | |
b7442fb5 NS |
78 | |
79 | dump_function (TDI_optimized, fn); | |
46e8c075 | 80 | } |
95fabfd3 MM |
81 | |
82 | /* Called from calls_setjmp_p via walk_tree. */ | |
83 | ||
84 | static tree | |
4977bab6 ZW |
85 | calls_setjmp_r (tree *tp, int *walk_subtrees ATTRIBUTE_UNUSED, |
86 | void *data ATTRIBUTE_UNUSED) | |
95fabfd3 | 87 | { |
95fabfd3 MM |
88 | /* We're only interested in FUNCTION_DECLS. */ |
89 | if (TREE_CODE (*tp) != FUNCTION_DECL) | |
90 | return NULL_TREE; | |
91 | ||
c9fff01f | 92 | return setjmp_call_p (*tp) ? *tp : NULL_TREE; |
95fabfd3 MM |
93 | } |
94 | ||
838dfd8a | 95 | /* Returns nonzero if FN calls `setjmp' or some other function that |
95fabfd3 | 96 | can return more than once. This function is conservative; it may |
838dfd8a | 97 | occasionally return a nonzero value even when FN does not actually |
95fabfd3 MM |
98 | call `setjmp'. */ |
99 | ||
4977bab6 ZW |
100 | bool |
101 | calls_setjmp_p (tree fn) | |
95fabfd3 | 102 | { |
9c96f3f8 AJ |
103 | return walk_tree_without_duplicates (&DECL_SAVED_TREE (fn), |
104 | calls_setjmp_r, | |
ee94fce6 | 105 | NULL) != NULL_TREE; |
95fabfd3 MM |
106 | } |
107 | ||
d60e5448 MM |
108 | /* CLONED_PARM is a copy of CLONE, generated for a cloned constructor |
109 | or destructor. Update it to ensure that the source-position for | |
110 | the cloned parameter matches that for the original, and that the | |
111 | debugging generation code will be able to find the original PARM. */ | |
112 | ||
113 | static void | |
4977bab6 | 114 | update_cloned_parm (tree parm, tree cloned_parm) |
d60e5448 MM |
115 | { |
116 | DECL_ABSTRACT_ORIGIN (cloned_parm) = parm; | |
d30a825a | 117 | |
c6002625 | 118 | /* We may have taken its address. */ |
d30a825a NS |
119 | TREE_ADDRESSABLE (cloned_parm) = TREE_ADDRESSABLE (parm); |
120 | ||
c6002625 | 121 | /* The definition might have different constness. */ |
d30a825a NS |
122 | TREE_READONLY (cloned_parm) = TREE_READONLY (parm); |
123 | ||
124 | TREE_USED (cloned_parm) = TREE_USED (parm); | |
d60e5448 | 125 | |
c6002625 | 126 | /* The name may have changed from the declaration. */ |
d60e5448 | 127 | DECL_NAME (cloned_parm) = DECL_NAME (parm); |
3e72ec9a | 128 | DECL_SOURCE_LOCATION (cloned_parm) = DECL_SOURCE_LOCATION (parm); |
d60e5448 MM |
129 | } |
130 | ||
db9b2174 | 131 | /* FN is a function that has a complete body. Clone the body as |
838dfd8a | 132 | necessary. Returns nonzero if there's no longer any need to |
db9b2174 MM |
133 | process the main body. */ |
134 | ||
4977bab6 ZW |
135 | bool |
136 | maybe_clone_body (tree fn) | |
db9b2174 | 137 | { |
db9b2174 | 138 | tree clone; |
4977bab6 | 139 | bool first = true; |
db9b2174 | 140 | |
db9b2174 MM |
141 | /* We only clone constructors and destructors. */ |
142 | if (!DECL_MAYBE_IN_CHARGE_CONSTRUCTOR_P (fn) | |
143 | && !DECL_MAYBE_IN_CHARGE_DESTRUCTOR_P (fn)) | |
144 | return 0; | |
145 | ||
5daf7c0a | 146 | /* Emit the DWARF1 abstract instance. */ |
2b85879e | 147 | (*debug_hooks->deferred_inline_function) (fn); |
5daf7c0a | 148 | |
db9b2174 MM |
149 | /* We know that any clones immediately follow FN in the TYPE_METHODS |
150 | list. */ | |
151 | for (clone = TREE_CHAIN (fn); | |
152 | clone && DECL_CLONED_FUNCTION_P (clone); | |
4977bab6 | 153 | clone = TREE_CHAIN (clone), first = false) |
db9b2174 MM |
154 | { |
155 | tree parm; | |
156 | tree clone_parm; | |
157 | int parmno; | |
25af8512 | 158 | splay_tree decl_map; |
db9b2174 MM |
159 | |
160 | /* Update CLONE's source position information to match FN's. */ | |
3e72ec9a | 161 | DECL_SOURCE_LOCATION (clone) = DECL_SOURCE_LOCATION (fn); |
99389463 | 162 | DECL_INLINE (clone) = DECL_INLINE (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 MM |
261 | |
262 | /* Now, expand this function into RTL, if appropriate. */ | |
5daf7c0a JM |
263 | finish_function (0); |
264 | BLOCK_ABSTRACT_ORIGIN (DECL_INITIAL (clone)) = DECL_INITIAL (fn); | |
265 | expand_body (clone); | |
db9b2174 MM |
266 | pop_from_top_level (); |
267 | } | |
9c96f3f8 | 268 | |
db9b2174 MM |
269 | /* We don't need to process the original function any further. */ |
270 | return 1; | |
271 | } | |
b7442fb5 | 272 | |
c6002625 | 273 | /* Dump FUNCTION_DECL FN as tree dump PHASE. */ |
b7442fb5 NS |
274 | |
275 | static void | |
4977bab6 | 276 | dump_function (enum tree_dump_index phase, tree fn) |
b7442fb5 NS |
277 | { |
278 | FILE *stream; | |
279 | int flags; | |
280 | ||
281 | stream = dump_begin (phase, &flags); | |
282 | if (stream) | |
283 | { | |
284 | fprintf (stream, "\n;; Function %s", | |
285 | decl_as_string (fn, TFF_DECL_SPECIFIERS)); | |
6be77748 NS |
286 | fprintf (stream, " (%s)\n", |
287 | decl_as_string (DECL_ASSEMBLER_NAME (fn), 0)); | |
288 | fprintf (stream, ";; enabled by -%s\n", dump_flag_name (phase)); | |
289 | fprintf (stream, "\n"); | |
b7442fb5 NS |
290 | |
291 | dump_node (fn, TDF_SLIM | flags, stream); | |
292 | dump_end (phase, stream); | |
293 | } | |
294 | } |