OSDN Git Service

Daily bump.
[pf3gnuchains/gcc-fork.git] / gcc / ipa.c
1 /* Basic IPA optimizations and utilities.
2    Copyright (C) 2003, 2004, 2005 Free Software Foundation, Inc.  
3
4 This file is part of GCC.
5
6 GCC is free software; you can redistribute it and/or modify it under
7 the terms of the GNU General Public License as published by the Free
8 Software Foundation; either version 2, or (at your option) any later
9 version.
10
11 GCC is distributed in the hope that it will be useful, but WITHOUT ANY
12 WARRANTY; without even the implied warranty of MERCHANTABILITY or
13 FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
14 for more details.
15
16 You should have received a copy of the GNU General Public License
17 along with GCC; see the file COPYING.  If not, write to the Free
18 Software Foundation, 51 Franklin Street, Fifth Floor, Boston, MA
19 02110-1301, USA.  */
20
21 #include "config.h"
22 #include "system.h"
23 #include "coretypes.h"
24 #include "tm.h"
25 #include "cgraph.h"
26 #include "tree-pass.h"
27 #include "timevar.h"
28
29 /* Fill array order with all nodes with output flag set in the reverse
30    topological order.  */
31
32 int
33 cgraph_postorder (struct cgraph_node **order)
34 {
35   struct cgraph_node *node, *node2;
36   int stack_size = 0;
37   int order_pos = 0;
38   struct cgraph_edge *edge, last;
39
40   struct cgraph_node **stack =
41     XCNEWVEC (struct cgraph_node *, cgraph_n_nodes);
42
43   /* We have to deal with cycles nicely, so use a depth first traversal
44      output algorithm.  Ignore the fact that some functions won't need
45      to be output and put them into order as well, so we get dependencies
46      right through intline functions.  */
47   for (node = cgraph_nodes; node; node = node->next)
48     node->aux = NULL;
49   for (node = cgraph_nodes; node; node = node->next)
50     if (!node->aux)
51       {
52         node2 = node;
53         if (!node->callers)
54           node->aux = &last;
55         else
56           node->aux = node->callers;
57         while (node2)
58           {
59             while (node2->aux != &last)
60               {
61                 edge = (struct cgraph_edge *) node2->aux;
62                 if (edge->next_caller)
63                   node2->aux = edge->next_caller;
64                 else
65                   node2->aux = &last;
66                 if (!edge->caller->aux)
67                   {
68                     if (!edge->caller->callers)
69                       edge->caller->aux = &last;
70                     else
71                       edge->caller->aux = edge->caller->callers;
72                     stack[stack_size++] = node2;
73                     node2 = edge->caller;
74                     break;
75                   }
76               }
77             if (node2->aux == &last)
78               {
79                 order[order_pos++] = node2;
80                 if (stack_size)
81                   node2 = stack[--stack_size];
82                 else
83                   node2 = NULL;
84               }
85           }
86       }
87   free (stack);
88   for (node = cgraph_nodes; node; node = node->next)
89     node->aux = NULL;
90   return order_pos;
91 }
92
93 /* Perform reachability analysis and reclaim all unreachable nodes.
94    If BEFORE_INLINING_P is true this function is called before inlining
95    decisions has been made.  If BEFORE_INLINING_P is false this function also 
96    removes unneeded bodies of extern inline functions.  */
97
98 bool
99 cgraph_remove_unreachable_nodes (bool before_inlining_p, FILE *file)
100 {
101   struct cgraph_node *first = (struct cgraph_node *) (void *) 1;
102   struct cgraph_node *node, *next;
103   bool changed = false;
104   int insns = 0;
105
106 #ifdef ENABLE_CHECKING
107   verify_cgraph ();
108 #endif
109   if (file)
110     fprintf (file, "\nReclaiming functions:");
111 #ifdef ENABLE_CHECKING
112   for (node = cgraph_nodes; node; node = node->next)
113     gcc_assert (!node->aux);
114 #endif
115   for (node = cgraph_nodes; node; node = node->next)
116     if (node->needed && !node->global.inlined_to
117         && ((!DECL_EXTERNAL (node->decl)) 
118             || !node->analyzed
119             || before_inlining_p))
120       {
121         node->aux = first;
122         first = node;
123       }
124     else
125       gcc_assert (!node->aux);
126
127   /* Perform reachability analysis.  As a special case do not consider
128      extern inline functions not inlined as live because we won't output
129      them at all.  */
130   while (first != (void *) 1)
131     {
132       struct cgraph_edge *e;
133       node = first;
134       first = (struct cgraph_node *) first->aux;
135
136       for (e = node->callees; e; e = e->next_callee)
137         if (!e->callee->aux
138             && node->analyzed
139             && (!e->inline_failed || !e->callee->analyzed
140                 || (!DECL_EXTERNAL (e->callee->decl))
141                 || before_inlining_p))
142           {
143             e->callee->aux = first;
144             first = e->callee;
145           }
146     }
147
148   /* Remove unreachable nodes.  Extern inline functions need special care;
149      Unreachable extern inline functions shall be removed.
150      Reachable extern inline functions we never inlined shall get their bodies
151      eliminated.
152      Reachable extern inline functions we sometimes inlined will be turned into
153      unanalyzed nodes so they look like for true extern functions to the rest
154      of code.  Body of such functions is released via remove_node once the
155      inline clones are eliminated.  */
156   for (node = cgraph_nodes; node; node = next)
157     {
158       next = node->next;
159       if (!node->aux)
160         {
161           int local_insns;
162           tree decl = node->decl;
163
164           node->global.inlined_to = NULL;
165           if (DECL_STRUCT_FUNCTION (decl))
166             local_insns = node->local.self_insns;
167           else
168             local_insns = 0;
169           if (file)
170             fprintf (file, " %s", cgraph_node_name (node));
171           if (!node->analyzed || !DECL_EXTERNAL (node->decl)
172               || before_inlining_p)
173             cgraph_remove_node (node);
174           else
175             {
176               struct cgraph_edge *e;
177
178               for (e = node->callers; e; e = e->next_caller)
179                 if (e->caller->aux)
180                   break;
181               if (e || node->needed)
182                 {
183                   struct cgraph_node *clone;
184
185                   for (clone = node->next_clone; clone;
186                        clone = clone->next_clone)
187                     if (clone->aux)
188                       break;
189                   if (!clone)
190                     {
191                       cgraph_release_function_body (node);
192                       node->analyzed = false;
193                     }
194                   cgraph_node_remove_callees (node);
195                   node->analyzed = false;
196                 }
197               else
198                 cgraph_remove_node (node);
199             }
200           if (!DECL_SAVED_TREE (decl))
201             insns += local_insns;
202           changed = true;
203         }
204     }
205   for (node = cgraph_nodes; node; node = node->next)
206     node->aux = NULL;
207   if (file)
208     fprintf (file, "\nReclaimed %i insns", insns);
209 #ifdef ENABLE_CHECKING
210   verify_cgraph ();
211 #endif
212   return changed;
213 }
214
215 /* Mark visibility of all functions.
216
217    A local function is one whose calls can occur only in the current
218    compilation unit and all its calls are explicit, so we can change
219    its calling convention.  We simply mark all static functions whose
220    address is not taken as local.
221
222    We also change the TREE_PUBLIC flag of all declarations that are public
223    in language point of view but we want to overwrite this default
224    via visibilities for the backend point of view.  */
225
226 static unsigned int
227 function_and_variable_visibility (void)
228 {
229   struct cgraph_node *node;
230   struct varpool_node *vnode;
231
232   for (node = cgraph_nodes; node; node = node->next)
233     {
234       if (node->reachable
235           && (DECL_COMDAT (node->decl)
236               || (!flag_whole_program
237                   && TREE_PUBLIC (node->decl) && !DECL_EXTERNAL (node->decl))))
238         node->local.externally_visible = true;
239       if (!node->local.externally_visible && node->analyzed
240           && !DECL_EXTERNAL (node->decl))
241         {
242           gcc_assert (flag_whole_program || !TREE_PUBLIC (node->decl));
243           TREE_PUBLIC (node->decl) = 0;
244         }
245       node->local.local = (!node->needed
246                            && node->analyzed
247                            && !DECL_EXTERNAL (node->decl)
248                            && !node->local.externally_visible);
249     }
250   for (vnode = varpool_nodes_queue; vnode; vnode = vnode->next_needed)
251     {
252       if (vnode->needed
253           && !flag_whole_program
254           && (DECL_COMDAT (vnode->decl) || TREE_PUBLIC (vnode->decl)))
255         vnode->externally_visible = 1;
256       if (!vnode->externally_visible)
257         {
258           gcc_assert (flag_whole_program || !TREE_PUBLIC (vnode->decl));
259           TREE_PUBLIC (vnode->decl) = 0;
260         }
261      gcc_assert (TREE_STATIC (vnode->decl));
262     }
263
264   if (dump_file)
265     {
266       fprintf (dump_file, "\nMarking local functions:");
267       for (node = cgraph_nodes; node; node = node->next)
268         if (node->local.local)
269           fprintf (dump_file, " %s", cgraph_node_name (node));
270       fprintf (dump_file, "\n\n");
271       fprintf (dump_file, "\nMarking externally visible functions:");
272       for (node = cgraph_nodes; node; node = node->next)
273         if (node->local.externally_visible)
274           fprintf (dump_file, " %s", cgraph_node_name (node));
275       fprintf (dump_file, "\n\n");
276     }
277   cgraph_function_flags_ready = true;
278   return 0;
279 }
280
281 struct tree_opt_pass pass_ipa_function_and_variable_visibility = 
282 {
283   "visibility",                         /* name */
284   NULL,                                 /* gate */
285   function_and_variable_visibility,     /* execute */
286   NULL,                                 /* sub */
287   NULL,                                 /* next */
288   0,                                    /* static_pass_number */
289   TV_CGRAPHOPT,                         /* tv_id */
290   0,                                    /* properties_required */
291   0,                                    /* properties_provided */
292   0,                                    /* properties_destroyed */
293   0,                                    /* todo_flags_start */
294   TODO_remove_functions | TODO_dump_cgraph,/* todo_flags_finish */
295   0                                     /* letter */
296 };