OSDN Git Service

572b5f9b733fd0523495974b937666e8bcda7766
[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 = 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 = (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 = 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   return changed;
210 }
211
212 /* Mark visibility of all functions.
213
214    A local function is one whose calls can occur only in the current
215    compilation unit and all its calls are explicit, so we can change
216    its calling convention.  We simply mark all static functions whose
217    address is not taken as local.
218
219    We also change the TREE_PUBLIC flag of all declarations that are public
220    in language point of view but we want to overwrite this default
221    via visibilities for the backend point of view.  */
222
223 static unsigned int
224 function_and_variable_visibility (void)
225 {
226   struct cgraph_node *node;
227   struct varpool_node *vnode;
228
229   for (node = cgraph_nodes; node; node = node->next)
230     {
231       if (node->reachable
232           && (DECL_COMDAT (node->decl)
233               || (!flag_whole_program
234                   && TREE_PUBLIC (node->decl) && !DECL_EXTERNAL (node->decl))))
235         node->local.externally_visible = true;
236       if (!node->local.externally_visible && node->analyzed
237           && !DECL_EXTERNAL (node->decl))
238         {
239           gcc_assert (flag_whole_program || !TREE_PUBLIC (node->decl));
240           TREE_PUBLIC (node->decl) = 0;
241         }
242       node->local.local = (!node->needed
243                            && node->analyzed
244                            && !DECL_EXTERNAL (node->decl)
245                            && !node->local.externally_visible);
246     }
247   for (vnode = varpool_nodes_queue; vnode; vnode = vnode->next_needed)
248     {
249       if (vnode->needed
250           && !flag_whole_program
251           && (DECL_COMDAT (vnode->decl) || TREE_PUBLIC (vnode->decl)))
252         vnode->externally_visible = 1;
253       if (!vnode->externally_visible)
254         {
255           gcc_assert (flag_whole_program || !TREE_PUBLIC (vnode->decl));
256           TREE_PUBLIC (vnode->decl) = 0;
257         }
258      gcc_assert (TREE_STATIC (vnode->decl));
259     }
260
261   if (dump_file)
262     {
263       fprintf (dump_file, "\nMarking local functions:");
264       for (node = cgraph_nodes; node; node = node->next)
265         if (node->local.local)
266           fprintf (dump_file, " %s", cgraph_node_name (node));
267       fprintf (dump_file, "\n\n");
268       fprintf (dump_file, "\nMarking externally visible functions:");
269       for (node = cgraph_nodes; node; node = node->next)
270         if (node->local.externally_visible)
271           fprintf (dump_file, " %s", cgraph_node_name (node));
272       fprintf (dump_file, "\n\n");
273     }
274   cgraph_function_flags_ready = true;
275   return 0;
276 }
277
278 struct tree_opt_pass pass_ipa_function_and_variable_visibility = 
279 {
280   "visibility",                         /* name */
281   NULL,                                 /* gate */
282   function_and_variable_visibility,     /* execute */
283   NULL,                                 /* sub */
284   NULL,                                 /* next */
285   0,                                    /* static_pass_number */
286   TV_CGRAPHOPT,                         /* tv_id */
287   0,                                    /* properties_required */
288   0,                                    /* properties_provided */
289   0,                                    /* properties_destroyed */
290   0,                                    /* todo_flags_start */
291   TODO_remove_functions | TODO_dump_cgraph,/* todo_flags_finish */
292   0                                     /* letter */
293 };