optimize.c revision 117395
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
5This file is part of GNU CC.
6
7GNU CC is free software; you can redistribute it and/or modify it
8under the terms of the GNU General Public License as published by
9the Free Software Foundation; either version 2, or (at your option)
10any later version.
11
12GNU CC is distributed in the hope that it will be useful, but
13WITHOUT ANY WARRANTY; without even the implied warranty of
14MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15General Public License for more details.
16
17You should have received a copy of the GNU General Public License
18along with GNU CC; see the file COPYING.  If not, write to the Free
19Software Foundation, 59 Temple Place - Suite 330, Boston, MA
2002111-1307, USA.  */
21
22#include "config.h"
23#include "system.h"
24#include "tree.h"
25#include "cp-tree.h"
26#include "rtl.h"
27#include "insn-config.h"
28#include "input.h"
29#include "integrate.h"
30#include "toplev.h"
31#include "varray.h"
32#include "ggc.h"
33#include "params.h"
34#include "hashtab.h"
35#include "debug.h"
36#include "tree-inline.h"
37
38/* Prototypes.  */
39
40static tree calls_setjmp_r PARAMS ((tree *, int *, void *));
41static void update_cloned_parm PARAMS ((tree, tree));
42static void dump_function PARAMS ((enum tree_dump_index, tree));
43
44/* Optimize the body of FN.  */
45
46void
47optimize_function (fn)
48     tree fn;
49{
50  dump_function (TDI_original, fn);
51
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
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,
67         and (d) TARGET_ASM_OUTPUT_MI_THUNK is there to DTRT anyway.  */
68      && !DECL_THUNK_P (fn))
69    {
70      optimize_inline_calls (fn);
71
72      dump_function (TDI_inlined, fn);
73    }
74
75  /* Undo the call to ggc_push_context above.  */
76  --function_depth;
77
78  dump_function (TDI_optimized, fn);
79}
80
81/* Called from calls_setjmp_p via walk_tree.  */
82
83static tree
84calls_setjmp_r (tp, walk_subtrees, data)
85     tree *tp;
86     int *walk_subtrees ATTRIBUTE_UNUSED;
87     void *data ATTRIBUTE_UNUSED;
88{
89  /* We're only interested in FUNCTION_DECLS.  */
90  if (TREE_CODE (*tp) != FUNCTION_DECL)
91    return NULL_TREE;
92
93  return setjmp_call_p (*tp) ? *tp : NULL_TREE;
94}
95
96/* Returns nonzero if FN calls `setjmp' or some other function that
97   can return more than once.  This function is conservative; it may
98   occasionally return a nonzero value even when FN does not actually
99   call `setjmp'.  */
100
101int
102calls_setjmp_p (fn)
103     tree fn;
104{
105  return walk_tree_without_duplicates (&DECL_SAVED_TREE (fn),
106				       calls_setjmp_r,
107				       NULL) != NULL_TREE;
108}
109
110/* CLONED_PARM is a copy of CLONE, generated for a cloned constructor
111   or destructor.  Update it to ensure that the source-position for
112   the cloned parameter matches that for the original, and that the
113   debugging generation code will be able to find the original PARM.  */
114
115static void
116update_cloned_parm (parm, cloned_parm)
117     tree parm;
118     tree cloned_parm;
119{
120  DECL_ABSTRACT_ORIGIN (cloned_parm) = parm;
121
122  /* We may have taken its address.  */
123  TREE_ADDRESSABLE (cloned_parm) = TREE_ADDRESSABLE (parm);
124
125  /* The definition might have different constness.  */
126  TREE_READONLY (cloned_parm) = TREE_READONLY (parm);
127
128  TREE_USED (cloned_parm) = TREE_USED (parm);
129
130  /* The name may have changed from the declaration.  */
131  DECL_NAME (cloned_parm) = DECL_NAME (parm);
132  DECL_SOURCE_LOCATION (cloned_parm) = DECL_SOURCE_LOCATION (parm);
133}
134
135/* FN is a function that has a complete body.  Clone the body as
136   necessary.  Returns nonzero if there's no longer any need to
137   process the main body.  */
138
139int
140maybe_clone_body (fn)
141     tree fn;
142{
143  tree clone;
144  int first = 1;
145
146  /* We only clone constructors and destructors.  */
147  if (!DECL_MAYBE_IN_CHARGE_CONSTRUCTOR_P (fn)
148      && !DECL_MAYBE_IN_CHARGE_DESTRUCTOR_P (fn))
149    return 0;
150
151  /* Emit the DWARF1 abstract instance.  */
152  (*debug_hooks->deferred_inline_function) (fn);
153
154  /* We know that any clones immediately follow FN in the TYPE_METHODS
155     list.  */
156  for (clone = TREE_CHAIN (fn);
157       clone && DECL_CLONED_FUNCTION_P (clone);
158       clone = TREE_CHAIN (clone), first = 0)
159    {
160      tree parm;
161      tree clone_parm;
162      int parmno;
163      splay_tree decl_map;
164
165      /* Update CLONE's source position information to match FN's.  */
166      DECL_SOURCE_LOCATION (clone) = DECL_SOURCE_LOCATION (fn);
167      DECL_INLINE (clone) = DECL_INLINE (fn);
168      DID_INLINE_FUNC (clone) = DID_INLINE_FUNC (fn);
169      DECL_DECLARED_INLINE_P (clone) = DECL_DECLARED_INLINE_P (fn);
170      DECL_COMDAT (clone) = DECL_COMDAT (fn);
171      DECL_WEAK (clone) = DECL_WEAK (fn);
172      DECL_ONE_ONLY (clone) = DECL_ONE_ONLY (fn);
173      DECL_SECTION_NAME (clone) = DECL_SECTION_NAME (fn);
174      DECL_USE_TEMPLATE (clone) = DECL_USE_TEMPLATE (fn);
175      DECL_EXTERNAL (clone) = DECL_EXTERNAL (fn);
176      DECL_INTERFACE_KNOWN (clone) = DECL_INTERFACE_KNOWN (fn);
177      DECL_NOT_REALLY_EXTERN (clone) = DECL_NOT_REALLY_EXTERN (fn);
178      TREE_PUBLIC (clone) = TREE_PUBLIC (fn);
179
180      /* Adjust the parameter names and locations.  */
181      parm = DECL_ARGUMENTS (fn);
182      clone_parm = DECL_ARGUMENTS (clone);
183      /* Update the `this' parameter, which is always first.  */
184      update_cloned_parm (parm, clone_parm);
185      parm = TREE_CHAIN (parm);
186      clone_parm = TREE_CHAIN (clone_parm);
187      if (DECL_HAS_IN_CHARGE_PARM_P (fn))
188	parm = TREE_CHAIN (parm);
189      if (DECL_HAS_VTT_PARM_P (fn))
190	parm = TREE_CHAIN (parm);
191      if (DECL_HAS_VTT_PARM_P (clone))
192	clone_parm = TREE_CHAIN (clone_parm);
193      for (; parm;
194	   parm = TREE_CHAIN (parm), clone_parm = TREE_CHAIN (clone_parm))
195	{
196	  /* Update this parameter.  */
197	  update_cloned_parm (parm, clone_parm);
198	  /* We should only give unused information for one clone.  */
199	  if (!first)
200	    TREE_USED (clone_parm) = 1;
201	}
202
203      /* Start processing the function.  */
204      push_to_top_level ();
205      start_function (NULL_TREE, clone, NULL_TREE, SF_PRE_PARSED);
206
207      /* Remap the parameters.  */
208      decl_map = splay_tree_new (splay_tree_compare_pointers, NULL, NULL);
209      for (parmno = 0,
210	     parm = DECL_ARGUMENTS (fn),
211	     clone_parm = DECL_ARGUMENTS (clone);
212	   parm;
213	   ++parmno,
214	     parm = TREE_CHAIN (parm))
215	{
216	  /* Map the in-charge parameter to an appropriate constant.  */
217	  if (DECL_HAS_IN_CHARGE_PARM_P (fn) && parmno == 1)
218	    {
219	      tree in_charge;
220	      in_charge = in_charge_arg_for_name (DECL_NAME (clone));
221	      splay_tree_insert (decl_map,
222				 (splay_tree_key) parm,
223				 (splay_tree_value) in_charge);
224	    }
225	  else if (DECL_ARTIFICIAL (parm)
226		   && DECL_NAME (parm) == vtt_parm_identifier)
227	    {
228	      /* For a subobject constructor or destructor, the next
229		 argument is the VTT parameter.  Remap the VTT_PARM
230		 from the CLONE to this parameter.  */
231	      if (DECL_HAS_VTT_PARM_P (clone))
232		{
233		  DECL_ABSTRACT_ORIGIN (clone_parm) = parm;
234		  splay_tree_insert (decl_map,
235				     (splay_tree_key) parm,
236				     (splay_tree_value) clone_parm);
237		  clone_parm = TREE_CHAIN (clone_parm);
238		}
239	      /* Otherwise, map the VTT parameter to `NULL'.  */
240	      else
241		{
242		  splay_tree_insert (decl_map,
243				     (splay_tree_key) parm,
244				     (splay_tree_value) null_pointer_node);
245		}
246	    }
247	  /* Map other parameters to their equivalents in the cloned
248	     function.  */
249	  else
250	    {
251	      splay_tree_insert (decl_map,
252				 (splay_tree_key) parm,
253				 (splay_tree_value) clone_parm);
254	      clone_parm = TREE_CHAIN (clone_parm);
255	    }
256	}
257
258      /* Clone the body.  */
259      clone_body (clone, fn, decl_map);
260
261      /* There are as many statements in the clone as in the
262	 original.  */
263      DECL_NUM_STMTS (clone) = DECL_NUM_STMTS (fn);
264
265      /* Clean up.  */
266      splay_tree_delete (decl_map);
267
268      /* The clone can throw iff the original function can throw.  */
269      cp_function_chain->can_throw = !TREE_NOTHROW (fn);
270
271      /* Now, expand this function into RTL, if appropriate.  */
272      finish_function (0);
273      BLOCK_ABSTRACT_ORIGIN (DECL_INITIAL (clone)) = DECL_INITIAL (fn);
274      expand_body (clone);
275      pop_from_top_level ();
276    }
277
278  /* We don't need to process the original function any further.  */
279  return 1;
280}
281
282/* Dump FUNCTION_DECL FN as tree dump PHASE.  */
283
284static void
285dump_function (phase, fn)
286     enum tree_dump_index phase;
287     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 -%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}
306