OSDN Git Service

* obj-c++-dg.exp: Add.
[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, 59 Temple Place - Suite 330, Boston, MA
19 02111-1307, USA.  */
20
21 #include "config.h"
22 #include "system.h"
23 #include "coretypes.h"
24 #include "tm.h"
25 #include "cgraph.h"
26
27 /* Fill array order with all nodes with output flag set in the reverse
28    topological order.  */
29
30 int
31 cgraph_postorder (struct cgraph_node **order)
32 {
33   struct cgraph_node *node, *node2;
34   int stack_size = 0;
35   int order_pos = 0;
36   struct cgraph_edge *edge, last;
37
38   struct cgraph_node **stack =
39     xcalloc (cgraph_n_nodes, sizeof (struct cgraph_node *));
40
41   /* We have to deal with cycles nicely, so use a depth first traversal
42      output algorithm.  Ignore the fact that some functions won't need
43      to be output and put them into order as well, so we get dependencies
44      right through intline functions.  */
45   for (node = cgraph_nodes; node; node = node->next)
46     node->aux = NULL;
47   for (node = cgraph_nodes; node; node = node->next)
48     if (!node->aux)
49       {
50         node2 = node;
51         if (!node->callers)
52           node->aux = &last;
53         else
54           node->aux = node->callers;
55         while (node2)
56           {
57             while (node2->aux != &last)
58               {
59                 edge = node2->aux;
60                 if (edge->next_caller)
61                   node2->aux = edge->next_caller;
62                 else
63                   node2->aux = &last;
64                 if (!edge->caller->aux)
65                   {
66                     if (!edge->caller->callers)
67                       edge->caller->aux = &last;
68                     else
69                       edge->caller->aux = edge->caller->callers;
70                     stack[stack_size++] = node2;
71                     node2 = edge->caller;
72                     break;
73                   }
74               }
75             if (node2->aux == &last)
76               {
77                 order[order_pos++] = node2;
78                 if (stack_size)
79                   node2 = stack[--stack_size];
80                 else
81                   node2 = NULL;
82               }
83           }
84       }
85   free (stack);
86   return order_pos;
87 }
88
89 /* Perform reachability analysis and reclaim all unreachable nodes.
90    If BEFORE_INLINING_P is true this function is called before inlining
91    decisions has been made.  If BEFORE_INLINING_P is false this function also 
92    removes unneeded bodies of extern inline functions.  */
93
94 bool
95 cgraph_remove_unreachable_nodes (bool before_inlining_p, FILE *dump_file)
96 {
97   struct cgraph_node *first = (void *) 1;
98   struct cgraph_node *node;
99   bool changed = false;
100   int insns = 0;
101
102 #ifdef ENABLE_CHECKING
103   verify_cgraph ();
104 #endif
105   if (dump_file)
106     fprintf (dump_file, "\nReclaiming functions:");
107 #ifdef ENABLE_CHECKING
108   for (node = cgraph_nodes; node; node = node->next)
109     gcc_assert (!node->aux);
110 #endif
111   for (node = cgraph_nodes; node; node = node->next)
112     if (node->needed && !node->global.inlined_to
113         && ((!DECL_EXTERNAL (node->decl)) 
114             || !node->analyzed
115             || before_inlining_p))
116       {
117         node->aux = first;
118         first = node;
119       }
120     else
121       gcc_assert (!node->aux);
122
123   /* Perform reachability analysis.  As a special case do not consider
124      extern inline functions not inlined as live because we won't output
125      them at all.  */
126   while (first != (void *) 1)
127     {
128       struct cgraph_edge *e;
129       node = first;
130       first = first->aux;
131
132       for (e = node->callees; e; e = e->next_callee)
133         if (!e->callee->aux
134             && node->analyzed
135             && (!e->inline_failed || !e->callee->analyzed
136                 || (!DECL_EXTERNAL (e->callee->decl))
137                 || before_inlining_p))
138           {
139             e->callee->aux = first;
140             first = e->callee;
141           }
142     }
143
144   /* Remove unreachable nodes.  Extern inline functions need special care;
145      Unreachable extern inline functions shall be removed.
146      Reachable extern inline functions we never inlined shall get their bodies
147      eliminated.
148      Reachable extern inline functions we sometimes inlined will be turned into
149      unanalyzed nodes so they look like for true extern functions to the rest
150      of code.  Body of such functions is released via remove_node once the
151      inline clones are eliminated.  */
152   for (node = cgraph_nodes; node; node = node->next)
153     {
154       if (!node->aux)
155         {
156           int local_insns;
157           tree decl = node->decl;
158
159           node->global.inlined_to = NULL;
160           if (DECL_STRUCT_FUNCTION (decl))
161             local_insns = node->local.self_insns;
162           else
163             local_insns = 0;
164           if (dump_file)
165             fprintf (dump_file, " %s", cgraph_node_name (node));
166           if (!node->analyzed || !DECL_EXTERNAL (node->decl)
167               || before_inlining_p)
168             cgraph_remove_node (node);
169           else
170             {
171               struct cgraph_edge *e;
172
173               for (e = node->callers; e; e = e->next_caller)
174                 if (e->caller->aux)
175                   break;
176               if (e || node->needed)
177                 {
178                   struct cgraph_node *clone;
179
180                   for (clone = node->next_clone; clone;
181                        clone = clone->next_clone)
182                     if (clone->aux)
183                       break;
184                   if (!clone)
185                     {
186                       DECL_SAVED_TREE (node->decl) = NULL;
187                       DECL_STRUCT_FUNCTION (node->decl) = NULL;
188                       DECL_INITIAL (node->decl) = error_mark_node;
189                       node->analyzed = false;
190                     }
191                   cgraph_node_remove_callees (node);
192                   node->analyzed = false;
193                 }
194               else
195                 cgraph_remove_node (node);
196             }
197           if (!DECL_SAVED_TREE (decl))
198             insns += local_insns;
199           changed = true;
200         }
201     }
202   for (node = cgraph_nodes; node; node = node->next)
203     node->aux = NULL;
204   if (dump_file)
205     fprintf (dump_file, "\nReclaimed %i insns", insns);
206   return changed;
207 }