optimize.c revision 90075
1/* Perform optimizations on tree structure.
2   Copyright (C) 1998, 1999, 2000, 2001 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) 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 non-zero 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 non-zero 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_FILE (cloned_parm) = DECL_SOURCE_FILE (parm);
133  DECL_SOURCE_LINE (cloned_parm) = DECL_SOURCE_LINE (parm);
134}
135
136/* FN is a function that has a complete body.  Clone the body as
137   necessary.  Returns non-zero if there's no longer any need to
138   process the main body.  */
139
140int
141maybe_clone_body (fn)
142     tree fn;
143{
144  tree clone;
145  int first = 1;
146
147  /* We only clone constructors and destructors.  */
148  if (!DECL_MAYBE_IN_CHARGE_CONSTRUCTOR_P (fn)
149      && !DECL_MAYBE_IN_CHARGE_DESTRUCTOR_P (fn))
150    return 0;
151
152  /* Emit the DWARF1 abstract instance.  */
153  (*debug_hooks->deferred_inline_function) (fn);
154
155  /* We know that any clones immediately follow FN in the TYPE_METHODS
156     list.  */
157  for (clone = TREE_CHAIN (fn);
158       clone && DECL_CLONED_FUNCTION_P (clone);
159       clone = TREE_CHAIN (clone), first = 0)
160    {
161      tree parm;
162      tree clone_parm;
163      int parmno;
164      splay_tree decl_map;
165
166      /* Update CLONE's source position information to match FN's.  */
167      DECL_SOURCE_FILE (clone) = DECL_SOURCE_FILE (fn);
168      DECL_SOURCE_LINE (clone) = DECL_SOURCE_LINE (fn);
169      DECL_INLINE (clone) = DECL_INLINE (fn);
170      DECL_DECLARED_INLINE_P (clone) = DECL_DECLARED_INLINE_P (fn);
171      DECL_COMDAT (clone) = DECL_COMDAT (fn);
172      DECL_WEAK (clone) = DECL_WEAK (fn);
173      DECL_ONE_ONLY (clone) = DECL_ONE_ONLY (fn);
174      DECL_SECTION_NAME (clone) = DECL_SECTION_NAME (fn);
175      DECL_USE_TEMPLATE (clone) = DECL_USE_TEMPLATE (fn);
176      DECL_EXTERNAL (clone) = DECL_EXTERNAL (fn);
177      DECL_INTERFACE_KNOWN (clone) = DECL_INTERFACE_KNOWN (fn);
178      DECL_NOT_REALLY_EXTERN (clone) = DECL_NOT_REALLY_EXTERN (fn);
179      TREE_PUBLIC (clone) = TREE_PUBLIC (fn);
180
181      /* Adjust the parameter names and locations. */
182      parm = DECL_ARGUMENTS (fn);
183      clone_parm = DECL_ARGUMENTS (clone);
184      /* Update the `this' parameter, which is always first.  */
185      update_cloned_parm (parm, clone_parm);
186      parm = TREE_CHAIN (parm);
187      clone_parm = TREE_CHAIN (clone_parm);
188      if (DECL_HAS_IN_CHARGE_PARM_P (fn))
189	parm = TREE_CHAIN (parm);
190      if (DECL_HAS_VTT_PARM_P (fn))
191	parm = TREE_CHAIN (parm);
192      if (DECL_HAS_VTT_PARM_P (clone))
193	clone_parm = TREE_CHAIN (clone_parm);
194      for (; parm;
195	   parm = TREE_CHAIN (parm), clone_parm = TREE_CHAIN (clone_parm))
196	{
197	  /* Update this parameter.  */
198	  update_cloned_parm (parm, clone_parm);
199	  /* We should only give unused information for one clone. */
200	  if (!first)
201	    TREE_USED (clone_parm) = 1;
202	}
203
204      /* Start processing the function.  */
205      push_to_top_level ();
206      start_function (NULL_TREE, clone, NULL_TREE, SF_PRE_PARSED);
207
208      /* Remap the parameters.  */
209      decl_map = splay_tree_new (splay_tree_compare_pointers, NULL, NULL);
210      for (parmno = 0,
211	     parm = DECL_ARGUMENTS (fn),
212	     clone_parm = DECL_ARGUMENTS (clone);
213	   parm;
214	   ++parmno,
215	     parm = TREE_CHAIN (parm))
216	{
217	  /* Map the in-charge parameter to an appropriate constant.  */
218	  if (DECL_HAS_IN_CHARGE_PARM_P (fn) && parmno == 1)
219	    {
220	      tree in_charge;
221	      in_charge = in_charge_arg_for_name (DECL_NAME (clone));
222	      splay_tree_insert (decl_map,
223				 (splay_tree_key) parm,
224				 (splay_tree_value) in_charge);
225	    }
226	  else if (DECL_ARTIFICIAL (parm)
227		   && DECL_NAME (parm) == vtt_parm_identifier)
228	    {
229	      /* For a subobject constructor or destructor, the next
230		 argument is the VTT parameter.  Remap the VTT_PARM
231		 from the CLONE to this parameter.  */
232	      if (DECL_HAS_VTT_PARM_P (clone))
233		{
234		  DECL_ABSTRACT_ORIGIN (clone_parm) = parm;
235		  splay_tree_insert (decl_map,
236				     (splay_tree_key) parm,
237				     (splay_tree_value) clone_parm);
238		  clone_parm = TREE_CHAIN (clone_parm);
239		}
240	      /* Otherwise, map the VTT parameter to `NULL'.  */
241	      else
242		{
243		  splay_tree_insert (decl_map,
244				     (splay_tree_key) parm,
245				     (splay_tree_value) null_pointer_node);
246		}
247	    }
248	  /* Map other parameters to their equivalents in the cloned
249	     function.  */
250	  else
251	    {
252	      splay_tree_insert (decl_map,
253				 (splay_tree_key) parm,
254				 (splay_tree_value) clone_parm);
255	      clone_parm = TREE_CHAIN (clone_parm);
256	    }
257	}
258
259      /* Clone the body.  */
260      clone_body (clone, fn, decl_map);
261
262      /* There are as many statements in the clone as in the
263	 original.  */
264      DECL_NUM_STMTS (clone) = DECL_NUM_STMTS (fn);
265
266      /* Clean up.  */
267      splay_tree_delete (decl_map);
268
269      /* Now, expand this function into RTL, if appropriate.  */
270      finish_function (0);
271      BLOCK_ABSTRACT_ORIGIN (DECL_INITIAL (clone)) = DECL_INITIAL (fn);
272      expand_body (clone);
273      pop_from_top_level ();
274    }
275
276  /* We don't need to process the original function any further.  */
277  return 1;
278}
279
280/* Dump FUNCTION_DECL FN as tree dump PHASE. */
281
282static void
283dump_function (phase, fn)
284     enum tree_dump_index phase;
285     tree fn;
286{
287  FILE *stream;
288  int flags;
289
290  stream = dump_begin (phase, &flags);
291  if (stream)
292    {
293      fprintf (stream, "\n;; Function %s",
294	       decl_as_string (fn, TFF_DECL_SPECIFIERS));
295      fprintf (stream, " (%s)\n",
296	       decl_as_string (DECL_ASSEMBLER_NAME (fn), 0));
297      fprintf (stream, ";; enabled by -%s\n", dump_flag_name (phase));
298      fprintf (stream, "\n");
299
300      dump_node (fn, TDF_SLIM | flags, stream);
301      dump_end (phase, stream);
302    }
303}
304