OSDN Git Service

* basic-block.h (update_bb_profile_after_threading): Declare.
[pf3gnuchains/gcc-fork.git] / gcc / tree-ssa-threadupdate.c
1 /* Thread edges through blocks and update the control flow and SSA graphs.
2    Copyright (C) 2004 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
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 2, or (at your option)
9 any later version.
10
11 GCC is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14 GNU General Public License 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
18 the Free Software Foundation, 59 Temple Place - Suite 330,
19 Boston, MA 02111-1307, USA.  */
20
21 #include "config.h"
22 #include "system.h"
23 #include "coretypes.h"
24 #include "tm.h"
25 #include "tree.h"
26 #include "flags.h"
27 #include "rtl.h"
28 #include "tm_p.h"
29 #include "ggc.h"
30 #include "basic-block.h"
31 #include "output.h"
32 #include "errors.h"
33 #include "expr.h"
34 #include "function.h"
35 #include "diagnostic.h"
36 #include "tree-flow.h"
37 #include "tree-dump.h"
38 #include "tree-pass.h"
39
40 /* Given a block B, update the CFG and SSA graph to reflect redirecting
41    one or more in-edges to B to instead reach the destination of an
42    out-edge from B while preserving any side effects in B.
43
44    i.e., given A->B and B->C, change A->B to be A->C yet still preserve the
45    side effects of executing B.
46
47      1. Make a copy of B (including its outgoing edges and statements).  Call
48         the copy B'.  Note B' has no incoming edges or PHIs at this time.
49
50      2. Remove the control statement at the end of B' and all outgoing edges
51         except B'->C.
52
53      3. Add a new argument to each PHI in C with the same value as the existing
54         argument associated with edge B->C.  Associate the new PHI arguments
55         with the edge B'->C.
56
57      4. For each PHI in B, find or create a PHI in B' with an identical
58         PHI_RESULT.  Add an argument to the PHI in B' which as the same
59         value as the PHI in B associated with the edge A->B.  Associate
60         the new argument in the PHI in B' with the edge A->B.
61
62      5. Change the edge A->B to A->B'.
63
64         5a. This automatically deletes any PHI arguments associated with the
65             edge A->B in B.
66
67         5b. This automatically associates each new argument added in step 4
68             with the edge A->B'.
69
70      6. Repeat for other incoming edges into B.
71
72      7. Put the duplicated resources in B and all the B' blocks into SSA form.
73
74    Note that block duplication can be minimized by first collecting the
75    the set of unique destination blocks that the incoming edges should
76    be threaded to.  Block duplication can be further minimized by using 
77    B instead of creating B' for one destination if all edges into B are
78    going to be threaded to a successor of B.  */
79
80
81 /* Main data structure recording information regarding B's duplicate
82    blocks.  */
83
84 struct redirection_data
85 {
86   /* A duplicate of B with the trailing control statement removed and which
87      targets a single successor of B.  */
88   basic_block dup_block;
89
90   /* An outgoing edge from B.  DUP_BLOCK will have OUTGOING_EDGE->dest as
91      its single successor.  */
92   edge outgoing_edge;
93 };
94
95 /* Main data structure to hold information for duplicates of BB.  */
96 static varray_type redirection_data;
97
98 /* For each PHI node in BB, find or create a PHI node in NEW_BB for the
99    same PHI_RESULT.  Add an argument to the PHI node in NEW_BB which
100    corresponds to the same PHI argument associated with edge E in BB.  */
101
102 static void
103 copy_phis_to_block (basic_block new_bb, basic_block bb, edge e)
104 {
105   tree phi, arg;
106
107   /* Walk over every PHI in BB.  */
108   for (phi = phi_nodes (bb); phi; phi = PHI_CHAIN (phi))
109     {
110       tree new_phi;
111
112       /* First try to find a PHI node in NEW_BB which has the same
113          PHI_RESULT as the PHI from BB we are currently processing.  */
114       for (new_phi = phi_nodes (new_bb); new_phi;
115            new_phi = PHI_CHAIN (new_phi))
116         if (PHI_RESULT (new_phi) == PHI_RESULT (phi))
117           break;
118
119       /* If we did not find a suitable PHI in NEW_BB, create one.  */
120       if (!new_phi)
121         new_phi = create_phi_node (PHI_RESULT (phi), new_bb);
122
123       /* Extract the argument corresponding to E from the current PHI
124          node in BB.  */
125       arg = PHI_ARG_DEF_TREE (phi, phi_arg_from_edge (phi, e));
126
127       /* Now add that same argument to the new PHI node in block NEW_BB.  */
128       add_phi_arg (&new_phi, arg, e);
129     }
130 }
131
132 /* Remove the last statement in block BB which must be a COND_EXPR or
133    SWITCH_EXPR.  Also remove all outgoing edges except the edge which
134    reaches DEST_BB.
135
136    This is only used by jump threading which knows the last statement in
137    BB should be a COND_EXPR or SWITCH_EXPR.  If the block ends with any other
138    statement, then we abort.  */
139
140 static void
141 remove_last_stmt_and_useless_edges (basic_block bb, basic_block dest_bb)
142 {
143   block_stmt_iterator bsi;
144   edge e, next;
145
146   bsi = bsi_last (bb);
147
148   gcc_assert (TREE_CODE (bsi_stmt (bsi)) == COND_EXPR
149               || TREE_CODE (bsi_stmt (bsi)) == SWITCH_EXPR);
150
151   bsi_remove (&bsi);
152
153   next = NULL;
154   for (e = bb->succ; e; e = next)
155     {
156       next = e->succ_next;
157
158       if (e->dest != dest_bb)
159         ssa_remove_edge (e);
160     }
161
162   /* BB now has a single outgoing edge. We need to update the flags for
163      that single outgoing edge.  */
164   bb->succ->flags &= ~(EDGE_TRUE_VALUE | EDGE_FALSE_VALUE);
165   bb->succ->flags |= EDGE_FALLTHRU;
166 }
167
168 /* Create a duplicate of BB which only reaches the destination of the edge
169    stored in RD.  Record the duplicate block in RD.  */
170
171 static void
172 create_block_for_threading (basic_block bb, struct redirection_data *rd)
173 {
174   tree phi;
175   edge e;
176
177   /* We can use the generic block duplication code and simply remove
178      the stuff we do not need.  */
179   rd->dup_block = duplicate_block (bb, NULL);
180
181   /* Zero out the profile, since the block is unreachable for now.  */
182   rd->dup_block->frequency = 0;
183   rd->dup_block->count = 0;
184
185   /* The call to duplicate_block will copy everything, including the
186      useless COND_EXPR or SWITCH_EXPR at the end of the block.  We just remove
187      the useless COND_EXPR or SWITCH_EXPR here rather than having a
188      specialized block copier.  */
189   remove_last_stmt_and_useless_edges (rd->dup_block, rd->outgoing_edge->dest);
190
191   for (e = rd->dup_block->succ; e; e = e->succ_next)
192     e->count = 0;
193
194   /* If there are any PHI nodes at the destination of the outgoing edge
195      from the duplicate block, then we will need to add a new argument
196      to them.  The argument should have the same value as the argument
197      associated with the outgoing edge stored in RD.  */
198   for (phi = phi_nodes (rd->dup_block->succ->dest); phi;
199        phi = PHI_CHAIN (phi))
200     {
201       int indx = phi_arg_from_edge (phi, rd->outgoing_edge);
202       add_phi_arg (&phi, PHI_ARG_DEF_TREE (phi, indx), rd->dup_block->succ);
203     }
204 }
205
206 /* BB is a block which ends with a COND_EXPR or SWITCH_EXPR and when BB
207    is reached via one or more specific incoming edges, we know which
208    outgoing edge from BB will be traversed.
209
210    We want to redirect those incoming edges to the target of the 
211    appropriate outgoing edge.  Doing so avoids a conditional branch
212    and may expose new optimization opportunities.  Note that we have
213    to update dominator tree and SSA graph after such changes.
214
215    The key to keeping the SSA graph update manageable is to duplicate
216    the side effects occurring in BB so that those side effects still
217    occur on the paths which bypass BB after redirecting edges.
218
219    We accomplish this by creating duplicates of BB and arranging for
220    the duplicates to unconditionally pass control to one specific
221    successor of BB.  We then revector the incoming edges into BB to
222    the appropriate duplicate of BB.
223
224    BB and its duplicates will have assignments to the same set of
225    SSA_NAMEs.  Right now, we just call into rewrite_ssa_into_ssa
226    to update the SSA graph for those names.
227
228    We are also going to experiment with a true incremental update
229    scheme for the duplicated resources.  Of of the interesting
230    properties we can exploit here is that all the resources set
231    in BB will have the same IDFS, so we have one IDFS computation
232    per block with incoming threaded edges, which can lower the
233    cost of the true incremental update algorithm.  */
234
235 static void
236 thread_block (basic_block bb)
237 {
238   /* E is an incoming edge into BB that we may or may not want to
239      redirect to a duplicate of BB.  */
240   edge e;
241
242   /* The next edge in a predecessor list.  Used in loops where E->pred_next
243      may change within the loop.  */
244   edge next;
245
246   /* ALL indicates whether or not all incoming edges into BB should
247      be threaded to a duplicate of BB.  */
248   bool all = true;
249
250   unsigned int i;
251
252   VARRAY_GENERIC_PTR_INIT (redirection_data, 2, "redirection data");
253
254   /* Look at each incoming edge into BB.  Record each unique outgoing
255      edge that we want to thread an incoming edge to.  Also note if
256      all incoming edges are threaded or not.  */
257   for (e = bb->pred; e; e = e->pred_next)
258     {
259       if (!e->aux)
260         {
261           all = false;
262         }
263       else
264         {
265           unsigned int i;
266
267           /* See if we can find an entry for the destination of this
268              threaded edge that has already been recorded.  */
269           for (i = 0; i < VARRAY_ACTIVE_SIZE (redirection_data); i++)
270             {
271               struct redirection_data *rd;
272               edge e2;
273
274               rd = VARRAY_GENERIC_PTR (redirection_data, i);
275               e2 = e->aux;
276
277               if (e2->dest == rd->outgoing_edge->dest)
278                 break;
279             }
280
281           /* If the loop did not terminate early, then we have a new
282              destination for the incoming threaded edges.  Record it.  */
283           if (i == VARRAY_ACTIVE_SIZE (redirection_data))
284             {
285               struct redirection_data *rd;
286
287               rd = ggc_alloc_cleared (sizeof (struct redirection_data));
288               rd->outgoing_edge = e->aux;
289               VARRAY_PUSH_GENERIC_PTR (redirection_data, rd);
290             }
291         }
292     }
293
294   /* Now create duplicates of BB.  Note that if all incoming edges are
295      threaded, then BB is going to become unreachable.  In that case
296      we use BB for one of the duplicates rather than wasting memory
297      duplicating BB.  Thus the odd starting condition for the loop.  */
298   for (i = (all ? 1 : 0); i < VARRAY_ACTIVE_SIZE (redirection_data); i++)
299     {
300       struct redirection_data *rd = VARRAY_GENERIC_PTR (redirection_data, i);
301       create_block_for_threading (bb, rd);
302     }
303
304   /* The loop above created the duplicate blocks (and the statements
305      within the duplicate blocks).  This loop creates PHI nodes for the
306      duplicated blocks and redirects the incoming edges into BB to reach
307      the duplicates of BB.
308
309      Note that redirecting the edge will change e->pred_next, so we have
310      to hold e->pred_next in a temporary. 
311
312      If this turns out to be a performance problem, then we could create
313      a list of incoming edges associated with each entry in 
314      REDIRECTION_DATA and walk over that list of edges instead.  */
315   next = NULL;
316   for (e = bb->pred; e; e = next)
317     {
318       edge new_dest = e->aux;
319
320       next = e->pred_next;
321
322       /* E was not threaded, then there is nothing to do.  */
323       if (!new_dest)
324         continue;
325
326       /* Go ahead and clear E->aux.  It's not needed anymore and failure
327          to clear it will cause all kinds of unpleasant problems later.  */
328       e->aux = NULL;
329
330       /* We know E is an edge we want to thread.  Find the entry associated
331          with E's new destination in the REDIRECTION_DATA array.  */
332       for (i = 0; i < VARRAY_ACTIVE_SIZE (redirection_data); i++)
333         {
334           struct redirection_data *rd;
335
336           rd = VARRAY_GENERIC_PTR (redirection_data, i);
337
338           /* We have found the right entry if the outgoing edge in this
339              entry matches E's new destination.  Note that if we have not
340              created a duplicate block (rd->dup_block is NULL), then we
341              are going to re-use BB as a duplicate and we do not need
342              to create PHI nodes or redirect the edge.  */
343           if (rd->outgoing_edge == new_dest && rd->dup_block)
344             {
345               edge e2;
346               copy_phis_to_block (rd->dup_block, bb, e);
347
348               if (dump_file && (dump_flags & TDF_DETAILS))
349                 fprintf (dump_file, "  Threaded jump %d --> %d to %d\n",
350                          e->src->index, e->dest->index, rd->dup_block->index);
351
352               e2 = redirect_edge_and_branch (e, rd->dup_block);
353               PENDING_STMT (e2) = NULL;
354
355               if ((dump_file && (dump_flags & TDF_DETAILS))
356                   && e->src != e2->src)
357               fprintf (dump_file, "    basic block %d created\n",
358                        e2->src->index);
359               break;
360             }
361         }
362     }
363
364   /* If all the incoming edges where threaded, then we used BB as one
365      of the duplicate blocks.  We need to fixup BB in that case so that
366      it no longer has a COND_EXPR or SWITCH_EXPR and reaches one destination
367      unconditionally.  */
368   if (all)
369     {
370       struct redirection_data *rd;
371
372       rd = VARRAY_GENERIC_PTR (redirection_data, 0);
373
374       if (dump_file && (dump_flags & TDF_DETAILS))
375         fprintf (dump_file, "  Threaded jump %d --> %d to %d\n",
376                  bb->pred->src->index, bb->index, bb->succ->dest->index);
377
378       remove_last_stmt_and_useless_edges (bb, rd->outgoing_edge->dest);
379     }
380
381   /* Done with this block.  Clear REDIRECTION_DATA.  */
382   VARRAY_CLEAR (redirection_data);
383 }
384
385 /* Walk through all blocks and thread incoming edges to the block's 
386    destinations as requested.  This is the only entry point into this
387    file.
388
389    Blocks which have one or more incoming edges have INCOMING_EDGE_THREADED
390    set in the block's annotation.
391    this routine.
392
393    Each edge that should be threaded has the new destination edge stored in
394    the original edge's AUX field.
395
396    This routine (or one of its callees) will clear INCOMING_EDGE_THREADED
397    in the block annotations and the AUX field in the edges.
398
399    It is the caller's responsibility to fix the dominance information
400    and rewrite duplicated SSA_NAMEs back into SSA form.
401
402    Returns true if one or more edges were threaded, false otherwise.   */
403
404 bool
405 thread_through_all_blocks (void)
406 {
407   basic_block bb;
408   bool retval = false;
409
410   FOR_EACH_BB (bb)
411     {
412       if (bb_ann (bb)->incoming_edge_threaded)
413         {
414           thread_block (bb);
415           retval = true;
416           bb_ann (bb)->incoming_edge_threaded = false;
417         }
418     }
419   return retval;
420 }