7b868acdf79dc9d804f33461bce0c17fbe557e6e
[libfirm] / ir / ir / irgopt.c
1 /* Coyright (C) 1998 - 2000 by Universitaet Karlsruhe
2 ** All rights reserved.
3 **
4 ** Author: Christian Schaefer
5 **
6 ** Optimizations for a whole ir graph, i.e., a procedure.
7 */
8
9 /* $Id$ */
10
11 #ifdef HAVE_CONFIG_H
12 # include <config.h>
13 #endif
14
15 # include <assert.h>
16
17 # include "irgopt.h"
18 # include "irnode_t.h"
19 # include "irgraph_t.h"
20 # include "iropt_t.h"
21 # include "irgwalk.h"
22 # include "ircons.h"
23 # include "misc.h"
24 # include "irgmod.h"
25
26 # include "pset.h"
27
28 /* Defined in iropt.c */
29 pset *new_identities (void);
30 void  del_identities (pset *value_table);
31 void  add_identities   (pset *value_table, ir_node *node);
32
33 #if 0  /* Warum ist das hier nochmal definiert?
34           Hat's nicht gelinkt wegen typeO tities - tity ?? */
35 /* To fill the hash table */
36 void
37 add_identity (pset *value_table, ir_node *n) {
38   /* identify_remember (value_table, n);*/
39 }
40 #endif
41
42 /********************************************************************/
43 /* apply optimizations of iropt to all nodes.                       */
44 /********************************************************************/
45
46 void init_link (ir_node *n, void *env) {
47   set_irn_link(n, NULL);
48 }
49
50 void
51 optimize_in_place_wrapper (ir_node *n, void *env) {
52   int i;
53   ir_node *optimized;
54
55   /* optimize all sons after recursion, i.e., the sons' sons are
56      optimized already. */
57   for (i = -1; i < get_irn_arity(n); i++) {
58     optimized = optimize_in_place_2(get_irn_n(n, i));
59     set_irn_n(n, i, optimized);
60   }
61 }
62
63 void
64 local_optimize_graph (ir_graph *irg) {
65   ir_graph *rem = current_ir_graph;
66   current_ir_graph = irg;
67
68   /* Handle graph state */
69   assert(get_irg_phase_state(irg) != phase_building);
70   if (get_opt_global_cse())
71     set_irg_pinned(current_ir_graph, floats);
72   if (get_irg_outs_state(current_ir_graph) == outs_consistent)
73     set_irg_outs_inconsistent(current_ir_graph);
74
75   /* Clean the value_table in irg for the cse. */
76   del_identities(irg->value_table);
77   irg->value_table = new_identities();
78
79   /* walk over the graph */
80   irg_walk(irg->end, init_link, optimize_in_place_wrapper, NULL);
81
82   current_ir_graph = rem;
83 }
84
85 /********************************************************************/
86 /* Routines for dead node elimination / copying garbage collection  */
87 /* of the obstack.                                                  */
88 /********************************************************************/
89
90 /* Remeber the new node in the old node by using a field all nodes have. */
91 inline void
92 set_new_node (ir_node *old, ir_node *new)
93 {
94   old->link = new;
95 }
96
97 /* Get this new node, before the old node is forgotton.*/
98 inline ir_node *
99 get_new_node (ir_node * n)
100 {
101   return n->link;
102 }
103
104
105 /* We use the block_visited flag to mark that we have computed the
106    number of useful predecessors for this block.
107    Further we encode the new arity in this flag in the old blocks.
108    Remembering the arity is useful, as it saves a lot of pointer
109    accesses.  This function is called for all Phi and Block nodes
110    in a Block. */
111 inline int
112 compute_new_arity(ir_node *b) {
113   int i, res;
114   int irg_v, block_v;
115
116   irg_v = get_irg_block_visited(current_ir_graph);
117   block_v = get_Block_block_visited(b);
118   if (block_v >= irg_v) {
119     /* we computed the number of preds for this block and saved it in the
120        block_v flag */
121     return block_v - irg_v;
122   } else {
123     /* compute the number of good predecessors */
124     res = get_irn_arity(b);
125     for (i = 0; i < get_irn_arity(b); i++)
126       if (get_irn_opcode(get_irn_n(b, i)) == iro_Bad) res--;
127     /* save it in the flag. */
128     set_Block_block_visited(b, irg_v + res);
129     return res;
130   }
131 }
132
133 /* Copies the node to the new obstack. The Ins of the new node point to
134    the predecessors on the old obstack.  For block/phi nodes not all
135    predecessors might be copied.  n->link points to the new node.
136    For Phi and Block nodes the function allocates in-arrays with an arity
137    only for useful predecessors.  The arity is determined by counting
138    the non-bad predecessors of the block. */
139 void
140 copy_node (ir_node *n, void *env) {
141   ir_node *nn, *block;
142   int new_arity;
143
144   if (get_irn_opcode(n) == iro_Block) {
145     block = NULL;
146     new_arity = compute_new_arity(n);
147   } else {
148     block = get_nodes_Block(n);
149     if (get_irn_opcode(n) == iro_Phi) {
150       new_arity = compute_new_arity(block);
151     } else {
152       new_arity = get_irn_arity(n);
153     }
154   }
155   nn = new_ir_node(current_ir_graph,
156                    block,
157                    get_irn_op(n),
158                    get_irn_mode(n),
159                    new_arity,
160                    get_irn_in(n));
161   /* Copy the attributes.  These might point to additional data.  If this
162      was allocated on the old obstack the pointers now are dangling.  This
163      frees e.g. the memory of the graph_arr allocated in new_immBlock. */
164   copy_attrs(n, nn);
165   set_new_node(n, nn);
166
167   /*  printf("\n old node: "); DDMSG2(n);
168       printf(" new node: "); DDMSG2(nn); */
169
170 }
171
172 /* Copies new predecessors of old node to new node remembered in link.
173    Spare the Bad predecessors of Phi and Block nodes. */
174 void
175 copy_preds (ir_node *n, void *env) {
176   ir_node *nn, *block, *on;
177   int i, j;
178
179   nn = get_new_node(n);
180
181   /* printf("\n old node: "); DDMSG2(n);
182      printf(" new node: "); DDMSG2(nn);
183      printf(" arities: old: %d, new: %d\n", get_irn_arity(n), get_irn_arity(nn)); */
184
185   if (get_irn_opcode(n) == iro_Block) {
186     /* Don't copy Bad nodes. */
187     j = 0;
188     for (i = 0; i < get_irn_arity(n); i++)
189       if (get_irn_opcode(get_irn_n(n, i)) != iro_Bad) {
190         set_irn_n (nn, j, get_new_node(get_irn_n(n, i)));
191         j++;
192       }
193     /* repair the block visited flag from above misuse. Repair it in both
194        graphs so that the old one can still be used. */
195     set_Block_block_visited(nn, 0);
196     set_Block_block_visited(n, 0);
197     /* Local optimization could not merge two subsequent blocks if
198        in array contained Bads.  Now it's possible.
199        We don't call optimize_in_place as it requires
200        that the fields in ir_graph are set properly. */
201     if (get_Block_n_cfgpreds(nn) == 1
202         && get_irn_op(get_Block_cfgpred(nn, 0)) == op_Jmp)
203       exchange(nn, get_nodes_Block(get_Block_cfgpred(nn, 0)));
204   } else if (get_irn_opcode(n) == iro_Phi) {
205     /* Don't copy node if corresponding predecessor in block is Bad.
206        The Block itself should not be Bad. */
207     block = get_nodes_Block(n);
208     set_irn_n (nn, -1, get_new_node(block));
209     j = 0;
210     for (i = 0; i < get_irn_arity(n); i++)
211       if (get_irn_opcode(get_irn_n(block, i)) != iro_Bad) {
212         set_irn_n (nn, j, get_new_node(get_irn_n(n, i)));
213         j++;
214       }
215     /* If the pre walker reached this Phi after the post walker visited the
216        block block_visited is > 0. */
217     set_Block_block_visited(get_nodes_Block(n), 0);
218     /* Compacting the Phi's ins might generate Phis with only one
219        predecessor. */
220     if (get_irn_arity(n) == 1)
221       exchange(n, get_irn_n(n, 0));
222   } else {
223     for (i = -1; i < get_irn_arity(n); i++)
224       set_irn_n (nn, i, get_new_node(get_irn_n(n, i)));
225   }
226   /* Now the new node is complete.  We can add it to the hash table for cse. */
227   add_identities (current_ir_graph->value_table, nn);
228 }
229
230 /* Copies the graph resucsively, compacts the keepalive of the end node. */
231 void
232 copy_graph () {
233   ir_node *oe, *ne; /* old end, new end */
234   ir_node *ka; /* keep alive */
235   int i;
236
237   oe = get_irg_end(current_ir_graph);
238   /* copy the end node by hand, allocate dynamic in array! */
239   ne = new_ir_node(current_ir_graph,
240                    NULL,
241                    op_End,
242                    mode_X,
243                    -1,
244                    NULL);
245   /* Copy the attributes.  Well, there might be some in the future... */
246   copy_attrs(oe, ne);
247   set_new_node(oe, ne);
248
249   /* copy the live nodes */
250   irg_walk(get_nodes_Block(oe), copy_node, copy_preds, NULL);
251   /* copy_preds for the end node ... */
252   set_nodes_Block(ne, get_new_node(get_nodes_Block(oe)));
253
254   /** ... and now the keep alives. **/
255   /* First pick the not marked block nodes and walk them.  We must pick these
256      first as else we will oversee blocks reachable from Phis. */
257   for (i = 0; i < get_irn_arity(oe); i++) {
258     ka = get_irn_n(oe, i);
259     if ((get_irn_op(ka) == op_Block) &&
260         (get_irn_visited(ka) < get_irg_visited(current_ir_graph))) {
261       /* We must keep the block alive and copy everything reachable */
262       set_irg_visited(current_ir_graph, get_irg_visited(current_ir_graph)-1);
263       irg_walk(ka, copy_node, copy_preds, NULL);
264       add_End_keepalive(ne, get_new_node(ka));
265     }
266   }
267
268   /* Now pick the Phis.  Here we will keep all! */
269   for (i = 0; i < get_irn_arity(oe); i++) {
270     ka = get_irn_n(oe, i);
271     if ((get_irn_op(ka) == op_Phi)) {
272       if (get_irn_visited(ka) < get_irg_visited(current_ir_graph)) {
273         /* We didn't copy the Phi yet.  */
274         set_irg_visited(current_ir_graph, get_irg_visited(current_ir_graph)-1);
275         irg_walk(ka, copy_node, copy_preds, NULL);
276       }
277       add_End_keepalive(ne, get_new_node(ka));
278     }
279   }
280 }
281
282 /* Copies the graph reachable from current_ir_graph->end to the obstack
283    in current_ir_graph and fixes the environment.
284    Then fixes the fields in current_ir_graph containing nodes of the
285    graph.  */
286 void
287 copy_graph_env () {
288   /* Not all nodes remembered in current_ir_graph might be reachable
289      from the end node.  Assure their link is set to NULL, so that
290      we can test whether new nodes have been computed. */
291   set_irn_link(get_irg_frame  (current_ir_graph), NULL);
292   set_irn_link(get_irg_globals(current_ir_graph), NULL);
293   set_irn_link(get_irg_args   (current_ir_graph), NULL);
294
295   /* we use the block walk flag for removing Bads from Blocks ins. */
296   inc_irg_block_visited(current_ir_graph);
297
298   /* copy the graph */
299   copy_graph();
300
301   /* fix the fields in current_ir_graph */
302   free_End(get_irg_end(current_ir_graph));
303   set_irg_end        (current_ir_graph, get_new_node(get_irg_end(current_ir_graph)));
304   set_irg_end_block  (current_ir_graph, get_new_node(get_irg_end_block(current_ir_graph)));
305   if (get_irn_link(get_irg_frame(current_ir_graph)) == NULL) {
306     copy_node (get_irg_frame(current_ir_graph), NULL);
307     copy_preds(get_irg_frame(current_ir_graph), NULL);
308   }
309   if (get_irn_link(get_irg_globals(current_ir_graph)) == NULL) {
310     copy_node (get_irg_globals(current_ir_graph), NULL);
311     copy_preds(get_irg_globals(current_ir_graph), NULL);
312   }
313   if (get_irn_link(get_irg_args(current_ir_graph)) == NULL) {
314     copy_node (get_irg_args(current_ir_graph), NULL);
315     copy_preds(get_irg_args(current_ir_graph), NULL);
316   }
317   set_irg_start  (current_ir_graph, get_new_node(get_irg_start(current_ir_graph)));
318
319   set_irg_start_block(current_ir_graph,
320                       get_new_node(get_irg_start_block(current_ir_graph)));
321   set_irg_frame  (current_ir_graph, get_new_node(get_irg_frame(current_ir_graph)));
322   set_irg_globals(current_ir_graph, get_new_node(get_irg_globals(current_ir_graph)));
323   set_irg_args   (current_ir_graph, get_new_node(get_irg_args(current_ir_graph)));
324   if (get_irn_link(get_irg_bad(current_ir_graph)) == NULL) {
325     copy_node(get_irg_bad(current_ir_graph), NULL);
326     copy_preds(get_irg_bad(current_ir_graph), NULL);
327   }
328   set_irg_bad(current_ir_graph, get_new_node(get_irg_bad(current_ir_graph)));
329 }
330
331 /* Copies all reachable nodes to a new obstack.  Removes bad inputs
332    from block nodes and the corresponding inputs from Phi nodes.
333    Merges single exit blocks with single entry blocks and removes
334    1-input Phis.
335    Adds all new nodes to a new hash table for cse.  Does not
336    perform cse, so the hash table might contain common subexpressions. */
337 /* Amroq call this emigrate() */
338 void
339 dead_node_elimination(ir_graph *irg) {
340   ir_graph *rem;
341   struct obstack *graveyard_obst = NULL;
342   struct obstack *rebirth_obst   = NULL;
343
344   /* Remember external state of current_ir_graph. */
345   rem = current_ir_graph;
346   current_ir_graph = irg;
347
348   /* Handle graph state */
349   assert(get_irg_phase_state(current_ir_graph) != phase_building);
350   free_outs(current_ir_graph);
351
352   if (get_optimize() && get_opt_dead_node_elimination()) {
353
354     /* A quiet place, where the old obstack can rest in peace,
355        until it will be cremated. */
356     graveyard_obst = irg->obst;
357
358     /* A new obstack, where the reachable nodes will be copied to. */
359     rebirth_obst = (struct obstack *) xmalloc (sizeof (struct obstack));
360     current_ir_graph->obst = rebirth_obst;
361     obstack_init (current_ir_graph->obst);
362
363     /* We also need a new hash table for cse */
364     del_identities (irg->value_table);
365     irg->value_table = new_identities ();
366
367     /* Copy the graph from the old to the new obstack */
368     copy_graph_env();
369
370     /* Free memory from old unoptimized obstack */
371     obstack_free(graveyard_obst, 0);  /* First empty the obstack ... */
372     xfree (graveyard_obst);           /* ... then free it.           */
373   }
374
375   current_ir_graph = rem;
376 }
377
378 /**********************************************************************/
379 /*  Funcionality for inlining                                         */
380 /**********************************************************************/
381
382 /* Copy node for inlineing.  Copies the node by calling copy_node and
383    then updates the entity if it's a local one.  env must be a pointer
384    to the frame type of the procedure. The new entities must be in
385    the link field of the entities. */
386 void
387 copy_node_inline (ir_node *n, void *env) {
388   ir_node *new;
389   type *frame_tp = (type *)env;
390
391   copy_node(n, NULL);
392   if (get_irn_op(n) == op_Sel) {
393     new = get_new_node (n);
394     assert(get_irn_op(new) == op_Sel);
395     if (get_entity_owner(get_Sel_entity(n)) == frame_tp) {
396       set_Sel_entity(new, get_entity_link(get_Sel_entity(n)));
397     }
398   }
399 }
400
401 void inline_method(ir_node *call, ir_graph *called_graph) {
402   ir_node *pre_call;
403   ir_node *post_call, *post_bl;
404   ir_node *in[5];
405   ir_node *end, *end_bl;
406   ir_node **res_pred;
407   ir_node **cf_pred;
408   ir_node *ret, *phi;
409   ir_node *cf_op, *bl;
410   int arity, n_ret, n_exc, n_res, i, j;
411   type *called_frame, *caller_frame;
412
413   if (!get_opt_inline()) return;
414
415   /* Handle graph state */
416   assert(get_irg_phase_state(current_ir_graph) != phase_building);
417   if (get_irg_outs_state(current_ir_graph) == outs_consistent)
418     set_irg_outs_inconsistent(current_ir_graph);
419
420   /** Check preconditions **/
421   assert(get_irn_op(call) == op_Call);
422   assert(get_Call_type(call) == get_entity_type(get_irg_ent(called_graph)));
423   assert(get_type_tpop(get_Call_type(call)) == type_method);
424   if (called_graph == current_ir_graph) return;
425
426   /** Part the Call node into two nodes.  Pre_call collects the parameters of
427   the procedure and later replaces the Start node of the called graph.
428   Post_call is the old Call node and collects the results of the called
429   graph. Both will end up being a tuple.  **/
430   post_bl = get_nodes_Block(call);
431   set_irg_current_block(current_ir_graph, post_bl);
432   /* XxMxPxP of Start + parameter of Call */
433   in[0] = new_Jmp();
434   in[1] = get_Call_mem(call);
435   in[2] = get_irg_frame(current_ir_graph);
436   in[3] = get_irg_globals(current_ir_graph);
437   in[4] = new_Tuple (get_Call_n_params(call),
438                      get_Call_param_arr(call));
439   pre_call = new_Tuple(5, in);
440   post_call = call;
441
442   /** Part the block of the Call node into two blocks.
443       The new block gets the ins of the old block, pre_call and all its
444       predecessors and all Phi nodes. **/
445   part_block(pre_call);
446
447   /** Prepare state for dead node elimination **/
448   /* Visited flags in calling irg must be >= flag in called irg.
449      Else walker and arity computation will not work. */
450   if (get_irg_visited(current_ir_graph) <= get_irg_visited(called_graph))
451     set_irg_visited(current_ir_graph, get_irg_visited(called_graph)+1);   /***/
452   if (get_irg_block_visited(current_ir_graph)< get_irg_block_visited(called_graph))
453     set_irg_block_visited(current_ir_graph, get_irg_block_visited(called_graph));
454   /* Set pre_call as new Start node in link field of the start node of
455       calling graph and pre_calls block as new block for the start block
456       of calling graph.
457       Further mark these nodes so that they are not visited by the
458       copying. */
459   set_irn_link(get_irg_start(called_graph), pre_call);
460   set_irn_visited(get_irg_start(called_graph),
461                   get_irg_visited(current_ir_graph));/***/
462   set_irn_link(get_irg_start_block(called_graph),
463                get_nodes_Block(pre_call));
464   set_irn_visited(get_irg_start_block(called_graph),
465                   get_irg_visited(current_ir_graph));  /***/
466
467   /* Initialize for compaction of in arrays */
468   inc_irg_block_visited(current_ir_graph);
469   /*
470   set_Block_block_visited(get_irg_start_block(called_graph),
471                         get_irg_block_visited(current_ir_graph) +1 +1); /* count for self edge */
472
473   /*** Replicate local entities of the called_graph ***/
474   /* copy the entities. */
475   called_frame = get_irg_frame_type(called_graph);
476   for (i = 0; i < get_class_n_member(called_frame); i++) {
477     entity *new_ent, *old_ent;
478     old_ent = get_class_member(called_frame, i);
479     new_ent = copy_entity_own(old_ent, get_cur_frame_type());
480     set_entity_link(old_ent, new_ent);
481   }
482
483   /* visited is > than that of called graph.  With this trick visited will
484      remain unchanged so that an outer walker, e.g., searching the call nodes
485      to inline, calling this inline will not visit the inlined nodes. */
486   set_irg_visited(current_ir_graph, get_irg_visited(current_ir_graph)-1);
487
488   /** Performing dead node elimination inlines the graph **/
489   /* Copies the nodes to the obstack of current_ir_graph. Updates links to new
490      entities. */
491   /* @@@ endless loops are not copied!! */
492   irg_walk(get_irg_end(called_graph), copy_node_inline, copy_preds,
493            get_irg_frame_type(called_graph));
494
495   /* Repair called_graph */
496   set_irg_visited(called_graph, get_irg_visited(current_ir_graph));
497   set_irg_block_visited(called_graph, get_irg_block_visited(current_ir_graph));
498   set_Block_block_visited(get_irg_start_block(called_graph), 0);
499
500   /*** Merge the end of the inlined procedure with the call site ***/
501   /* We will turn the old Call node into a Tuple with the following
502      predecessors:
503      -1:  Block of Tuple.
504      0: Phi of all Memories of Return statements.
505      1: Jmp from new Block that merges the control flow from all exception
506         predecessors of the old end block.
507      2: Tuple of all arguments.
508      3: Phi of Exception memories.
509   */
510
511   /** Precompute some values **/
512   end_bl = get_new_node(get_irg_end_block(called_graph));
513   end = get_new_node(get_irg_end(called_graph));
514   arity = get_irn_arity(end_bl);    /* arity = n_exc + n_ret  */
515   n_res = get_method_n_res(get_Call_type(call));
516
517   res_pred = (ir_node **) malloc ((n_res) * sizeof (ir_node *));
518   cf_pred = (ir_node **) malloc (arity * sizeof (ir_node *));
519
520   set_irg_current_block(current_ir_graph, post_bl); /* just to make sure */
521
522   /** archive keepalives **/
523   for (i = 0; i < get_irn_arity(end); i++)
524     add_End_keepalive(get_irg_end(current_ir_graph), get_irn_n(end, i));
525   /* The new end node will die, but the in array is not on the obstack ... */
526   free_End(end);
527
528   /** Collect control flow from Return blocks to post_calls block. Replace
529       Return nodes by Jump nodes. **/
530   n_ret = 0;
531   for (i = 0; i < arity; i++) {
532     ir_node *ret;
533     ret = get_irn_n(end_bl, i);
534     if (get_irn_op(ret) == op_Return) {
535       cf_pred[n_ret] = new_r_Jmp(current_ir_graph, get_nodes_Block(ret));
536       n_ret++;
537     }
538   }
539   set_irn_in(post_bl, n_ret, cf_pred);
540
541   /** Collect results from Return nodes to post_call. Post_call is
542       turned into a tuple. **/
543   turn_into_tuple(post_call, 4);
544   /* First the Memory-Phi */
545   n_ret = 0;
546   for (i = 0; i < arity; i++) {
547     ret = get_irn_n(end_bl, i);
548     if (get_irn_op(ret) == op_Return) {
549       cf_pred[n_ret] = get_Return_mem(ret);
550       n_ret++;
551     }
552   }
553   phi = new_Phi(n_ret, cf_pred, mode_M);
554   set_Tuple_pred(call, 0, phi);
555   set_irn_link(phi, get_irn_link(post_bl));  /* Conserve Phi-list for further inlinings */
556   set_irn_link(post_bl, phi);
557   /* Now the real results */
558   if (n_res > 0) {
559     for (j = 0; j < n_res; j++) {
560       n_ret = 0;
561       for (i = 0; i < arity; i++) {
562         ret = get_irn_n(end_bl, i);
563         if (get_irn_op(ret) == op_Return) {
564           cf_pred[n_ret] = get_Return_res(ret, j);
565           n_ret++;
566         }
567       }
568       phi = new_Phi(n_ret, cf_pred, get_irn_mode(cf_pred[0]));
569       res_pred[j] = phi;
570       set_irn_link(phi, get_irn_link(post_bl));  /* Conserve Phi-list for further inlinings */
571       set_irn_link(post_bl, phi);
572     }
573     set_Tuple_pred(call, 2, new_Tuple(n_res, res_pred));
574   } else {
575     set_Tuple_pred(call, 2, new_Bad());
576   }
577   /* Finally the exception control flow.  We need to add a Phi node to
578      collect the memory containing the exception objects.  Further we need
579      to add another block to get a correct representation of this Phi.  To
580      this block we add a Jmp that resolves into the X output of the Call
581      when the Call is turned into a tuple. */
582   n_exc = 0;
583   for (i = 0; i < arity; i++) {
584     ir_node *ret;
585     ret = get_irn_n(end_bl, i);
586     if (is_fragile_op(skip_Proj(ret)) || (get_irn_op(skip_Proj(ret)) == op_Raise)) {
587       cf_pred[n_exc] = ret;
588       n_exc++;
589     }
590   }
591   if (n_exc > 0) {
592     new_Block(n_exc, cf_pred);      /* whatch it: current_block is changed! */
593     set_Tuple_pred(call, 1, new_Jmp());
594     /* The Phi for the memories with the exception objects */
595     n_exc = 0;
596     for (i = 0; i < arity; i++) {
597       ir_node *ret;
598       ret = skip_Proj(get_irn_n(end_bl, i));
599       if (get_irn_op(ret) == op_Call) {
600         cf_pred[n_exc] = new_r_Proj(current_ir_graph, get_nodes_Block(ret), ret, mode_M, 3);
601         n_exc++;
602       } else if (is_fragile_op(ret)) {
603         /* We rely that all cfops have the memory output at the same position. */
604         cf_pred[n_exc] = new_r_Proj(current_ir_graph, get_nodes_Block(ret), ret, mode_M, 0);
605         n_exc++;
606       } else if (get_irn_op(ret) == op_Raise) {
607         cf_pred[n_exc] = new_r_Proj(current_ir_graph, get_nodes_Block(ret), ret, mode_M, 1);
608         n_exc++;
609       }
610     }
611     set_Tuple_pred(call, 3, new_Phi(n_exc, cf_pred, mode_M));
612   } else {
613     set_Tuple_pred(call, 1, new_Bad());
614     set_Tuple_pred(call, 3, new_Bad());
615   }
616   free(res_pred);
617   free(cf_pred);
618
619   /*** Correct the control flow to the end node.
620        If the exception control flow from the Call directly branched to the
621        end block we now have the following control flow predecessor pattern:
622        ProjX -> Tuple -> Jmp.
623        We must remove the Jmp along with it's empty block and add Jmp's
624        predecessors as predecessors of this end block. ***/
625   /* find the problematic predecessor of the end block. */
626   end_bl = get_irg_end_block(current_ir_graph);
627   for (i = 0; i < get_Block_n_cfgpreds(end_bl); i++) {
628     cf_op = get_Block_cfgpred(end_bl, i);
629     if (get_irn_op(cf_op) == op_Proj) {
630       cf_op = get_Proj_pred(cf_op);
631       if (get_irn_op(cf_op) == op_Tuple) {
632         cf_op = get_Tuple_pred(cf_op, 1);
633         assert(get_irn_op(cf_op) == op_Jmp);
634         break;
635       }
636     }
637   }
638   /* repair */
639   if (i < get_Block_n_cfgpreds(end_bl)) {
640     bl = get_nodes_Block(cf_op);
641     arity = get_Block_n_cfgpreds(end_bl) + get_Block_n_cfgpreds(bl) - 1;
642     cf_pred = (ir_node **) malloc (arity * sizeof (ir_node *));
643     for (j = 0; j < i; j++)
644       cf_pred[j] = get_Block_cfgpred(end_bl, j);
645     for (j = j; j < i + get_Block_n_cfgpreds(bl); j++)
646       cf_pred[j] = get_Block_cfgpred(bl, j-i);
647     for (j = j; j < arity; j++)
648       cf_pred[j] = get_Block_cfgpred(end_bl, j-get_Block_n_cfgpreds(bl) +1);
649     set_irn_in(end_bl, arity, cf_pred);
650     free(cf_pred);
651   }
652 }