OSDN Git Service

* optimize.c (optimize_function): Push/pop ggc context around
[pf3gnuchains/gcc-fork.git] / gcc / cp / optimize.c
1 /* Perform optimizations on tree structure.
2    Copyright (C) 1998, 1999, 2000, 2001, 2002 Free Software Foundation, Inc.
3    Written by Mark Michell (mark@codesourcery.com).
4
5 This file is part of GCC.
6
7 GCC 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 GCC 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.
16
17 You should have received a copy of the GNU General Public License
18 along with GCC; see the file COPYING.  If not, write to the Free
19 Software Foundation, 59 Temple Place - Suite 330, Boston, MA
20 02111-1307, USA.  */
21
22 #include "config.h"
23 #include "system.h"
24 #include "coretypes.h"
25 #include "tm.h"
26 #include "tree.h"
27 #include "cp-tree.h"
28 #include "rtl.h"
29 #include "insn-config.h"
30 #include "input.h"
31 #include "integrate.h"
32 #include "toplev.h"
33 #include "varray.h"
34 #include "params.h"
35 #include "hashtab.h"
36 #include "debug.h"
37 #include "tree-inline.h"
38
39 /* Prototypes.  */
40
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);
44
45 /* Optimize the body of FN.  */
46
47 void
48 optimize_function (tree fn)
49 {
50   dump_function (TDI_original, fn);
51
52   if (flag_inline_trees
53       /* We do not inline thunks, as (a) the backend tries to optimize
54          the call to the thunkee, (b) tree based inlining breaks that
55          optimization, (c) virtual functions are rarely inlineable,
56          and (d) TARGET_ASM_OUTPUT_MI_THUNK is there to DTRT anyway.  */
57       && !DECL_THUNK_P (fn))
58     {
59       /* ??? Work around GC problem.  Call stack is
60
61          -> instantiate_decl
62          -> expand_or_defer_fn
63          -> maybe_clone_body
64          -> expand_body
65          -> tree_rest_of_compilation
66
67          which of course collects.  This used to be protected by the
68          "regular" nested call ggc_push_context that now lives in 
69          tree_rest_of_compilation.
70
71          Two good fixes:
72          (1) Do inlining in tree_rest_of_compilation.  This is good
73              in that this common optimization happens in common code.
74          (2) Don't nest compilation of functions.  Instead queue the
75              new function to cgraph, and let it get picked up in the
76              next round of "emit everything that needs emitting".
77
78          For the nonce, just protect things here.  */
79
80       ggc_push_context ();
81       optimize_inline_calls (fn);
82       ggc_pop_context ();
83
84       dump_function (TDI_inlined, fn);
85     }
86   
87   dump_function (TDI_optimized, fn);
88 }
89
90 /* Called from calls_setjmp_p via walk_tree.  */
91
92 static tree
93 calls_setjmp_r (tree *tp, int *walk_subtrees ATTRIBUTE_UNUSED,
94                 void *data ATTRIBUTE_UNUSED)
95 {
96   /* We're only interested in FUNCTION_DECLS.  */
97   if (TREE_CODE (*tp) != FUNCTION_DECL)
98     return NULL_TREE;
99
100   return setjmp_call_p (*tp) ? *tp : NULL_TREE;
101 }
102
103 /* Returns nonzero if FN calls `setjmp' or some other function that
104    can return more than once.  This function is conservative; it may
105    occasionally return a nonzero value even when FN does not actually
106    call `setjmp'.  */
107
108 bool
109 calls_setjmp_p (tree fn)
110 {
111   return walk_tree_without_duplicates (&DECL_SAVED_TREE (fn),
112                                        calls_setjmp_r,
113                                        NULL) != NULL_TREE;
114 }
115
116 /* CLONED_PARM is a copy of CLONE, generated for a cloned constructor
117    or destructor.  Update it to ensure that the source-position for
118    the cloned parameter matches that for the original, and that the
119    debugging generation code will be able to find the original PARM.  */
120
121 static void
122 update_cloned_parm (tree parm, tree cloned_parm)
123 {
124   DECL_ABSTRACT_ORIGIN (cloned_parm) = parm;
125
126   /* We may have taken its address.  */
127   TREE_ADDRESSABLE (cloned_parm) = TREE_ADDRESSABLE (parm);
128
129   /* The definition might have different constness.  */
130   TREE_READONLY (cloned_parm) = TREE_READONLY (parm);
131   
132   TREE_USED (cloned_parm) = TREE_USED (parm);
133   
134   /* The name may have changed from the declaration.  */
135   DECL_NAME (cloned_parm) = DECL_NAME (parm);
136   DECL_SOURCE_LOCATION (cloned_parm) = DECL_SOURCE_LOCATION (parm);
137 }
138
139 /* FN is a function that has a complete body.  Clone the body as
140    necessary.  Returns nonzero if there's no longer any need to
141    process the main body.  */
142
143 bool
144 maybe_clone_body (tree fn)
145 {
146   tree clone;
147   bool first = true;
148
149   /* We only clone constructors and destructors.  */
150   if (!DECL_MAYBE_IN_CHARGE_CONSTRUCTOR_P (fn)
151       && !DECL_MAYBE_IN_CHARGE_DESTRUCTOR_P (fn))
152     return 0;
153
154   /* Emit the DWARF1 abstract instance.  */
155   (*debug_hooks->deferred_inline_function) (fn);
156
157   /* We know that any clones immediately follow FN in the TYPE_METHODS
158      list.  */
159   for (clone = TREE_CHAIN (fn);
160        clone && DECL_CLONED_FUNCTION_P (clone);
161        clone = TREE_CHAIN (clone), first = false)
162     {
163       tree parm;
164       tree clone_parm;
165       int parmno;
166       splay_tree decl_map;
167
168       /* Update CLONE's source position information to match FN's.  */
169       DECL_SOURCE_LOCATION (clone) = DECL_SOURCE_LOCATION (fn);
170       DECL_INLINE (clone) = DECL_INLINE (fn);
171       DECL_DECLARED_INLINE_P (clone) = DECL_DECLARED_INLINE_P (fn);
172       DECL_COMDAT (clone) = DECL_COMDAT (fn);
173       DECL_WEAK (clone) = DECL_WEAK (fn);
174       DECL_ONE_ONLY (clone) = DECL_ONE_ONLY (fn);
175       DECL_SECTION_NAME (clone) = DECL_SECTION_NAME (fn);
176       DECL_USE_TEMPLATE (clone) = DECL_USE_TEMPLATE (fn);
177       DECL_EXTERNAL (clone) = DECL_EXTERNAL (fn);
178       DECL_INTERFACE_KNOWN (clone) = DECL_INTERFACE_KNOWN (fn);
179       DECL_NOT_REALLY_EXTERN (clone) = DECL_NOT_REALLY_EXTERN (fn);
180       TREE_PUBLIC (clone) = TREE_PUBLIC (fn);
181
182       /* Adjust the parameter names and locations.  */
183       parm = DECL_ARGUMENTS (fn);
184       clone_parm = DECL_ARGUMENTS (clone);
185       /* Update the `this' parameter, which is always first.  */
186       update_cloned_parm (parm, clone_parm);
187       parm = TREE_CHAIN (parm);
188       clone_parm = TREE_CHAIN (clone_parm);
189       if (DECL_HAS_IN_CHARGE_PARM_P (fn))
190         parm = TREE_CHAIN (parm);
191       if (DECL_HAS_VTT_PARM_P (fn))
192         parm = TREE_CHAIN (parm);
193       if (DECL_HAS_VTT_PARM_P (clone))
194         clone_parm = TREE_CHAIN (clone_parm);
195       for (; parm;
196            parm = TREE_CHAIN (parm), clone_parm = TREE_CHAIN (clone_parm))
197         {
198           /* Update this parameter.  */
199           update_cloned_parm (parm, clone_parm);
200           /* We should only give unused information for one clone.  */
201           if (!first)
202             TREE_USED (clone_parm) = 1;
203         }
204
205       /* Start processing the function.  */
206       push_to_top_level ();
207       start_function (NULL_TREE, clone, NULL_TREE, SF_PRE_PARSED);
208
209       /* Remap the parameters.  */
210       decl_map = splay_tree_new (splay_tree_compare_pointers, NULL, NULL);
211       for (parmno = 0,
212              parm = DECL_ARGUMENTS (fn),
213              clone_parm = DECL_ARGUMENTS (clone);
214            parm;
215            ++parmno,
216              parm = TREE_CHAIN (parm))
217         {
218           /* Map the in-charge parameter to an appropriate constant.  */
219           if (DECL_HAS_IN_CHARGE_PARM_P (fn) && parmno == 1)
220             {
221               tree in_charge;
222               in_charge = in_charge_arg_for_name (DECL_NAME (clone));
223               splay_tree_insert (decl_map,
224                                  (splay_tree_key) parm,
225                                  (splay_tree_value) in_charge);
226             }
227           else if (DECL_ARTIFICIAL (parm)
228                    && DECL_NAME (parm) == vtt_parm_identifier)
229             {
230               /* For a subobject constructor or destructor, the next
231                  argument is the VTT parameter.  Remap the VTT_PARM
232                  from the CLONE to this parameter.  */
233               if (DECL_HAS_VTT_PARM_P (clone))
234                 {
235                   DECL_ABSTRACT_ORIGIN (clone_parm) = parm;
236                   splay_tree_insert (decl_map,
237                                      (splay_tree_key) parm,
238                                      (splay_tree_value) clone_parm);
239                   clone_parm = TREE_CHAIN (clone_parm);
240                 }
241               /* Otherwise, map the VTT parameter to `NULL'.  */
242               else
243                 {
244                   splay_tree_insert (decl_map,
245                                      (splay_tree_key) parm,
246                                      (splay_tree_value) null_pointer_node);
247                 }
248             }
249           /* Map other parameters to their equivalents in the cloned
250              function.  */
251           else
252             {
253               splay_tree_insert (decl_map,
254                                  (splay_tree_key) parm,
255                                  (splay_tree_value) clone_parm);
256               clone_parm = TREE_CHAIN (clone_parm);
257             }
258         }
259
260       /* Clone the body.  */
261       clone_body (clone, fn, decl_map);
262
263       /* There are as many statements in the clone as in the
264          original.  */
265       DECL_ESTIMATED_INSNS (clone) = DECL_ESTIMATED_INSNS (fn);
266
267       /* Clean up.  */
268       splay_tree_delete (decl_map);
269
270       /* The clone can throw iff the original function can throw.  */
271       cp_function_chain->can_throw = !TREE_NOTHROW (fn);
272
273       /* Now, expand this function into RTL, if appropriate.  */
274       finish_function (0);
275       BLOCK_ABSTRACT_ORIGIN (DECL_INITIAL (clone)) = DECL_INITIAL (fn);
276       expand_or_defer_fn (clone);
277       pop_from_top_level ();
278     }
279
280   /* We don't need to process the original function any further.  */
281   return 1;
282 }
283
284 /* Dump FUNCTION_DECL FN as tree dump PHASE.  */
285
286 static void
287 dump_function (enum tree_dump_index phase, tree fn)
288 {
289   FILE *stream;
290   int flags;
291
292   stream = dump_begin (phase, &flags);
293   if (stream)
294     {
295       fprintf (stream, "\n;; Function %s",
296                decl_as_string (fn, TFF_DECL_SPECIFIERS));
297       fprintf (stream, " (%s)\n",
298                decl_as_string (DECL_ASSEMBLER_NAME (fn), 0));
299       fprintf (stream, ";; enabled by -fdump-%s\n", dump_flag_name (phase));
300       fprintf (stream, "\n");
301       
302       dump_node (fn, TDF_SLIM | flags, stream);
303       dump_end (phase, stream);
304     }
305 }