OSDN Git Service

2009-09-13 Richard Guenther <rguenther@suse.de>
[pf3gnuchains/gcc-fork.git] / gcc / tree-eh.c
1 /* Exception handling semantics and decomposition for trees.
2    Copyright (C) 2003, 2004, 2005, 2006, 2007, 2008, 2009
3    Free Software Foundation, Inc.
4
5 This file is part of GCC.
6
7 GCC is free software; you can redistribute it and/or modify
8 it under the terms of the GNU General Public License as published by
9 the Free Software Foundation; either version 3, or (at your option)
10 any later version.
11
12 GCC is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15 GNU General Public License for more details.
16
17 You should have received a copy of the GNU General Public License
18 along with GCC; see the file COPYING3.  If not see
19 <http://www.gnu.org/licenses/>.  */
20
21 #include "config.h"
22 #include "system.h"
23 #include "coretypes.h"
24 #include "tm.h"
25 #include "tree.h"
26 #include "rtl.h"
27 #include "tm_p.h"
28 #include "flags.h"
29 #include "function.h"
30 #include "except.h"
31 #include "tree-flow.h"
32 #include "tree-dump.h"
33 #include "tree-inline.h"
34 #include "tree-iterator.h"
35 #include "tree-pass.h"
36 #include "timevar.h"
37 #include "langhooks.h"
38 #include "ggc.h"
39 #include "toplev.h"
40 #include "gimple.h"
41
42 /* In some instances a tree and a gimple need to be stored in a same table,
43    i.e. in hash tables. This is a structure to do this. */
44 typedef union {tree *tp; tree t; gimple g;} treemple;
45
46 /* Nonzero if we are using EH to handle cleanups.  */
47 static int using_eh_for_cleanups_p = 0;
48
49 void
50 using_eh_for_cleanups (void)
51 {
52   using_eh_for_cleanups_p = 1;
53 }
54
55 /* Misc functions used in this file.  */
56
57 /* Compare and hash for any structure which begins with a canonical
58    pointer.  Assumes all pointers are interchangeable, which is sort
59    of already assumed by gcc elsewhere IIRC.  */
60
61 static int
62 struct_ptr_eq (const void *a, const void *b)
63 {
64   const void * const * x = (const void * const *) a;
65   const void * const * y = (const void * const *) b;
66   return *x == *y;
67 }
68
69 static hashval_t
70 struct_ptr_hash (const void *a)
71 {
72   const void * const * x = (const void * const *) a;
73   return (size_t)*x >> 4;
74 }
75
76
77 /* Remember and lookup EH region data for arbitrary statements.
78    Really this means any statement that could_throw_p.  We could
79    stuff this information into the stmt_ann data structure, but:
80
81    (1) We absolutely rely on this information being kept until
82    we get to rtl.  Once we're done with lowering here, if we lose
83    the information there's no way to recover it!
84
85    (2) There are many more statements that *cannot* throw as
86    compared to those that can.  We should be saving some amount
87    of space by only allocating memory for those that can throw.  */
88
89 static void
90 record_stmt_eh_region (struct eh_region_d *region, gimple t)
91 {
92   if (!region)
93     return;
94
95   add_stmt_to_eh_region (t, get_eh_region_number (region));
96 }
97
98
99 /* Add statement T in function IFUN to EH region NUM.  */
100
101 void
102 add_stmt_to_eh_region_fn (struct function *ifun, gimple t, int num)
103 {
104   struct throw_stmt_node *n;
105   void **slot;
106
107   gcc_assert (num >= 0);
108   gcc_assert (gimple_code (t) != GIMPLE_RESX);
109
110   n = GGC_NEW (struct throw_stmt_node);
111   n->stmt = t;
112   n->region_nr = num;
113
114   if (!get_eh_throw_stmt_table (ifun))
115     set_eh_throw_stmt_table (ifun, htab_create_ggc (31, struct_ptr_hash,
116                                                     struct_ptr_eq,
117                                                     ggc_free));
118
119   slot = htab_find_slot (get_eh_throw_stmt_table (ifun), n, INSERT);
120   gcc_assert (!*slot);
121   *slot = n;
122 }
123
124
125 /* Add statement T in the current function (cfun) to EH region number
126    NUM.  */
127
128 void
129 add_stmt_to_eh_region (gimple t, int num)
130 {
131   add_stmt_to_eh_region_fn (cfun, t, num);
132 }
133
134
135 /* Remove statement T in function IFUN from the EH region holding it.  */
136
137 bool
138 remove_stmt_from_eh_region_fn (struct function *ifun, gimple t)
139 {
140   struct throw_stmt_node dummy;
141   void **slot;
142
143   if (!get_eh_throw_stmt_table (ifun))
144     return false;
145
146   dummy.stmt = t;
147   slot = htab_find_slot (get_eh_throw_stmt_table (ifun), &dummy,
148                         NO_INSERT);
149   if (slot)
150     {
151       htab_clear_slot (get_eh_throw_stmt_table (ifun), slot);
152       return true;
153     }
154   else
155     return false;
156 }
157
158
159 /* Remove statement T in the current function (cfun) from the EH
160    region holding it.  */
161
162 bool
163 remove_stmt_from_eh_region (gimple t)
164 {
165   return remove_stmt_from_eh_region_fn (cfun, t);
166 }
167
168 /* Determine if statement T is inside an EH region in function IFUN.
169    Return the EH region number if found, return -2 if IFUN does not
170    have an EH table and -1 if T could not be found in IFUN's EH region
171    table.  */
172
173 int
174 lookup_stmt_eh_region_fn (struct function *ifun, gimple t)
175 {
176   struct throw_stmt_node *p, n;
177
178   if (!get_eh_throw_stmt_table (ifun))
179     return -2;
180
181   n.stmt = t;
182   p = (struct throw_stmt_node *) htab_find (get_eh_throw_stmt_table (ifun), &n);
183   return (p ? p->region_nr : -1);
184 }
185
186
187 /* Determine if statement T is inside an EH region in the current
188    function (cfun).  Return the EH region number if found, return -2
189    if cfun does not have an EH table and -1 if T could not be found in
190    cfun's EH region table.  */
191
192 int
193 lookup_stmt_eh_region (gimple t)
194 {
195   /* We can get called from initialized data when -fnon-call-exceptions
196      is on; prevent crash.  */
197   if (!cfun)
198     return -1;
199
200   return lookup_stmt_eh_region_fn (cfun, t);
201 }
202
203
204 /* Determine if expression T is inside an EH region in the current
205    function (cfun).  Return the EH region number if found, return -2
206    if IFUN does not have an EH table and -1 if T could not be found in
207    IFUN's EH region table.  */
208
209 int
210 lookup_expr_eh_region (tree t)
211 {
212   /* We can get called from initialized data when -fnon-call-exceptions
213      is on; prevent crash.  */
214   if (!cfun)
215     return -1;
216
217   if (!get_eh_throw_stmt_table (cfun))
218     return -2;
219
220   if (t && EXPR_P (t))
221     {
222       tree_ann_common_t ann = tree_common_ann (t);
223       if (ann)
224         return (int) ann->rn;
225     }
226
227   return -1;
228 }
229
230
231 /* First pass of EH node decomposition.  Build up a tree of GIMPLE_TRY_FINALLY
232    nodes and LABEL_DECL nodes.  We will use this during the second phase to
233    determine if a goto leaves the body of a TRY_FINALLY_EXPR node.  */
234
235 struct finally_tree_node
236 {
237   /* When storing a GIMPLE_TRY, we have to record a gimple.  However
238      when deciding whether a GOTO to a certain LABEL_DECL (which is a
239      tree) leaves the TRY block, its necessary to record a tree in
240      this field.  Thus a treemple is used. */
241   treemple child; 
242   gimple parent;
243 };
244
245 /* Note that this table is *not* marked GTY.  It is short-lived.  */
246 static htab_t finally_tree;
247
248 static void
249 record_in_finally_tree (treemple child, gimple parent)
250 {
251   struct finally_tree_node *n;
252   void **slot;
253
254   n = XNEW (struct finally_tree_node);
255   n->child = child;
256   n->parent = parent;
257
258   slot = htab_find_slot (finally_tree, n, INSERT);
259   gcc_assert (!*slot);
260   *slot = n;
261 }
262
263 static void
264 collect_finally_tree (gimple stmt, gimple region);
265
266 /* Go through the gimple sequence.  Works with collect_finally_tree to 
267    record all GIMPLE_LABEL and GIMPLE_TRY statements. */
268
269 static void
270 collect_finally_tree_1 (gimple_seq seq, gimple region)
271 {
272   gimple_stmt_iterator gsi;
273
274   for (gsi = gsi_start (seq); !gsi_end_p (gsi); gsi_next (&gsi))
275     collect_finally_tree (gsi_stmt (gsi), region);
276 }
277
278 static void
279 collect_finally_tree (gimple stmt, gimple region)
280 {
281   treemple temp;
282
283   switch (gimple_code (stmt))
284     {
285     case GIMPLE_LABEL:
286       temp.t = gimple_label_label (stmt);
287       record_in_finally_tree (temp, region);
288       break;
289
290     case GIMPLE_TRY:
291       if (gimple_try_kind (stmt) == GIMPLE_TRY_FINALLY)
292         {
293           temp.g = stmt;
294           record_in_finally_tree (temp, region);
295           collect_finally_tree_1 (gimple_try_eval (stmt), stmt);
296           collect_finally_tree_1 (gimple_try_cleanup (stmt), region);
297         }
298       else if (gimple_try_kind (stmt) == GIMPLE_TRY_CATCH)
299         {
300           collect_finally_tree_1 (gimple_try_eval (stmt), region);
301           collect_finally_tree_1 (gimple_try_cleanup (stmt), region);
302         }
303       break;
304
305     case GIMPLE_CATCH:
306       collect_finally_tree_1 (gimple_catch_handler (stmt), region);
307       break;
308
309     case GIMPLE_EH_FILTER:
310       collect_finally_tree_1 (gimple_eh_filter_failure (stmt), region);
311       break;
312
313     default:
314       /* A type, a decl, or some kind of statement that we're not
315          interested in.  Don't walk them.  */
316       break;
317     }
318 }
319
320
321 /* Use the finally tree to determine if a jump from START to TARGET
322    would leave the try_finally node that START lives in.  */
323
324 static bool
325 outside_finally_tree (treemple start, gimple target)
326 {
327   struct finally_tree_node n, *p;
328
329   do
330     {
331       n.child = start;
332       p = (struct finally_tree_node *) htab_find (finally_tree, &n);
333       if (!p)
334         return true;
335       start.g = p->parent;
336     }
337   while (start.g != target);
338
339   return false;
340 }
341
342 /* Second pass of EH node decomposition.  Actually transform the GIMPLE_TRY
343    nodes into a set of gotos, magic labels, and eh regions.
344    The eh region creation is straight-forward, but frobbing all the gotos
345    and such into shape isn't.  */
346
347 /* The GOTO_QUEUE is is an array of GIMPLE_GOTO and GIMPLE_RETURN
348    statements that are seen to escape this GIMPLE_TRY_FINALLY node.
349    The idea is to record a gimple statement for everything except for
350    the conditionals, which get their labels recorded. Since labels are
351    of type 'tree', we need this node to store both gimple and tree
352    objects.  REPL_STMT is the sequence used to replace the goto/return
353    statement.  CONT_STMT is used to store the statement that allows
354    the return/goto to jump to the original destination. */
355
356 struct goto_queue_node
357 {
358   treemple stmt;
359   gimple_seq repl_stmt;
360   gimple cont_stmt;
361   int index;
362   /* This is used when index >= 0 to indicate that stmt is a label (as
363      opposed to a goto stmt).  */
364   int is_label;
365 };
366
367 /* State of the world while lowering.  */
368
369 struct leh_state
370 {
371   /* What's "current" while constructing the eh region tree.  These
372      correspond to variables of the same name in cfun->eh, which we
373      don't have easy access to.  */
374   struct eh_region_d *cur_region;
375
376   /* Processing of TRY_FINALLY requires a bit more state.  This is
377      split out into a separate structure so that we don't have to
378      copy so much when processing other nodes.  */
379   struct leh_tf_state *tf;
380 };
381
382 struct leh_tf_state
383 {
384   /* Pointer to the GIMPLE_TRY_FINALLY node under discussion.  The
385      try_finally_expr is the original GIMPLE_TRY_FINALLY.  We need to retain
386      this so that outside_finally_tree can reliably reference the tree used
387      in the collect_finally_tree data structures.  */
388   gimple try_finally_expr;
389   gimple top_p;
390   /* While lowering a top_p usually it is expanded into multiple statements,
391      thus we need the following field to store them. */
392   gimple_seq top_p_seq;
393
394   /* The state outside this try_finally node.  */
395   struct leh_state *outer;
396
397   /* The exception region created for it.  */
398   struct eh_region_d *region;
399
400   /* The goto queue.  */
401   struct goto_queue_node *goto_queue;
402   size_t goto_queue_size;
403   size_t goto_queue_active;
404
405   /* Pointer map to help in searching goto_queue when it is large.  */
406   struct pointer_map_t *goto_queue_map;
407
408   /* The set of unique labels seen as entries in the goto queue.  */
409   VEC(tree,heap) *dest_array;
410
411   /* A label to be added at the end of the completed transformed
412      sequence.  It will be set if may_fallthru was true *at one time*,
413      though subsequent transformations may have cleared that flag.  */
414   tree fallthru_label;
415
416   /* A label that has been registered with except.c to be the
417      landing pad for this try block.  */
418   tree eh_label;
419
420   /* True if it is possible to fall out the bottom of the try block.
421      Cleared if the fallthru is converted to a goto.  */
422   bool may_fallthru;
423
424   /* True if any entry in goto_queue is a GIMPLE_RETURN.  */
425   bool may_return;
426
427   /* True if the finally block can receive an exception edge.
428      Cleared if the exception case is handled by code duplication.  */
429   bool may_throw;
430 };
431
432 static gimple_seq lower_eh_filter (struct leh_state *, gimple);
433
434 /* Search for STMT in the goto queue.  Return the replacement,
435    or null if the statement isn't in the queue.  */
436
437 #define LARGE_GOTO_QUEUE 20
438
439 static void lower_eh_constructs_1 (struct leh_state *state, gimple_seq seq);
440
441 static gimple_seq
442 find_goto_replacement (struct leh_tf_state *tf, treemple stmt)
443 {
444   unsigned int i;
445   void **slot;
446
447   if (tf->goto_queue_active < LARGE_GOTO_QUEUE)
448     {
449       for (i = 0; i < tf->goto_queue_active; i++)
450         if ( tf->goto_queue[i].stmt.g == stmt.g)
451           return tf->goto_queue[i].repl_stmt;
452       return NULL;
453     }
454
455   /* If we have a large number of entries in the goto_queue, create a
456      pointer map and use that for searching.  */
457
458   if (!tf->goto_queue_map)
459     {
460       tf->goto_queue_map = pointer_map_create ();
461       for (i = 0; i < tf->goto_queue_active; i++)
462         {
463           slot = pointer_map_insert (tf->goto_queue_map,
464                                      tf->goto_queue[i].stmt.g);
465           gcc_assert (*slot == NULL);
466           *slot = &tf->goto_queue[i];
467         }
468     }
469
470   slot = pointer_map_contains (tf->goto_queue_map, stmt.g);
471   if (slot != NULL)
472     return (((struct goto_queue_node *) *slot)->repl_stmt);
473
474   return NULL;
475 }
476
477 /* A subroutine of replace_goto_queue_1.  Handles the sub-clauses of a
478    lowered GIMPLE_COND.  If, by chance, the replacement is a simple goto,
479    then we can just splat it in, otherwise we add the new stmts immediately
480    after the GIMPLE_COND and redirect.  */
481
482 static void
483 replace_goto_queue_cond_clause (tree *tp, struct leh_tf_state *tf,
484                                 gimple_stmt_iterator *gsi)
485 {
486   tree label;
487   gimple_seq new_seq;
488   treemple temp;
489   location_t loc = gimple_location (gsi_stmt (*gsi));
490
491   temp.tp = tp;
492   new_seq = find_goto_replacement (tf, temp);
493   if (!new_seq)
494     return;
495
496   if (gimple_seq_singleton_p (new_seq)
497       && gimple_code (gimple_seq_first_stmt (new_seq)) == GIMPLE_GOTO)
498     {
499       *tp = gimple_goto_dest (gimple_seq_first_stmt (new_seq));
500       return;
501     }
502
503   label = create_artificial_label (loc);
504   /* Set the new label for the GIMPLE_COND */
505   *tp = label;
506
507   gsi_insert_after (gsi, gimple_build_label (label), GSI_CONTINUE_LINKING);
508   gsi_insert_seq_after (gsi, gimple_seq_copy (new_seq), GSI_CONTINUE_LINKING);
509 }
510
511 /* The real work of replace_goto_queue.  Returns with TSI updated to
512    point to the next statement.  */
513
514 static void replace_goto_queue_stmt_list (gimple_seq, struct leh_tf_state *);
515
516 static void
517 replace_goto_queue_1 (gimple stmt, struct leh_tf_state *tf,
518                       gimple_stmt_iterator *gsi)
519 {
520   gimple_seq seq;
521   treemple temp;
522   temp.g = NULL;
523
524   switch (gimple_code (stmt))
525     {
526     case GIMPLE_GOTO:
527     case GIMPLE_RETURN:
528       temp.g = stmt;
529       seq = find_goto_replacement (tf, temp);
530       if (seq)
531         {
532           gsi_insert_seq_before (gsi, gimple_seq_copy (seq), GSI_SAME_STMT);
533           gsi_remove (gsi, false);
534           return;
535         }
536       break;
537
538     case GIMPLE_COND:
539       replace_goto_queue_cond_clause (gimple_op_ptr (stmt, 2), tf, gsi);
540       replace_goto_queue_cond_clause (gimple_op_ptr (stmt, 3), tf, gsi);
541       break;
542
543     case GIMPLE_TRY:
544       replace_goto_queue_stmt_list (gimple_try_eval (stmt), tf);
545       replace_goto_queue_stmt_list (gimple_try_cleanup (stmt), tf);
546       break;
547     case GIMPLE_CATCH:
548       replace_goto_queue_stmt_list (gimple_catch_handler (stmt), tf);
549       break;
550     case GIMPLE_EH_FILTER:
551       replace_goto_queue_stmt_list (gimple_eh_filter_failure (stmt), tf);
552       break;
553
554     default:
555       /* These won't have gotos in them.  */
556       break;
557     }
558
559   gsi_next (gsi);
560 }
561
562 /* A subroutine of replace_goto_queue.  Handles GIMPLE_SEQ.  */
563
564 static void
565 replace_goto_queue_stmt_list (gimple_seq seq, struct leh_tf_state *tf)
566 {
567   gimple_stmt_iterator gsi = gsi_start (seq);
568
569   while (!gsi_end_p (gsi))
570     replace_goto_queue_1 (gsi_stmt (gsi), tf, &gsi);
571 }
572
573 /* Replace all goto queue members.  */
574
575 static void
576 replace_goto_queue (struct leh_tf_state *tf)
577 {
578   if (tf->goto_queue_active == 0)
579     return;
580   replace_goto_queue_stmt_list (tf->top_p_seq, tf);
581 }
582
583 /* Add a new record to the goto queue contained in TF. NEW_STMT is the
584    data to be added, IS_LABEL indicates whether NEW_STMT is a label or
585    a gimple return. */
586
587 static void
588 record_in_goto_queue (struct leh_tf_state *tf,
589                       treemple new_stmt,
590                       int index,
591                       bool is_label)
592 {
593   size_t active, size;
594   struct goto_queue_node *q;
595
596   gcc_assert (!tf->goto_queue_map);
597
598   active = tf->goto_queue_active;
599   size = tf->goto_queue_size;
600   if (active >= size)
601     {
602       size = (size ? size * 2 : 32);
603       tf->goto_queue_size = size;
604       tf->goto_queue
605          = XRESIZEVEC (struct goto_queue_node, tf->goto_queue, size);
606     }
607
608   q = &tf->goto_queue[active];
609   tf->goto_queue_active = active + 1;
610
611   memset (q, 0, sizeof (*q));
612   q->stmt = new_stmt;
613   q->index = index;
614   q->is_label = is_label;
615 }
616
617 /* Record the LABEL label in the goto queue contained in TF.
618    TF is not null.  */
619
620 static void
621 record_in_goto_queue_label (struct leh_tf_state *tf, treemple stmt, tree label)
622 {
623   int index;
624   treemple temp, new_stmt;
625
626   if (!label)
627     return;
628
629   /* Computed and non-local gotos do not get processed.  Given
630      their nature we can neither tell whether we've escaped the
631      finally block nor redirect them if we knew.  */
632   if (TREE_CODE (label) != LABEL_DECL)
633     return;
634
635   /* No need to record gotos that don't leave the try block.  */
636   temp.t = label;
637   if (!outside_finally_tree (temp, tf->try_finally_expr))
638     return;
639
640   if (! tf->dest_array)
641     {
642       tf->dest_array = VEC_alloc (tree, heap, 10);
643       VEC_quick_push (tree, tf->dest_array, label);
644       index = 0;
645     }
646   else
647     {
648       int n = VEC_length (tree, tf->dest_array);
649       for (index = 0; index < n; ++index)
650         if (VEC_index (tree, tf->dest_array, index) == label)
651           break;
652       if (index == n)
653         VEC_safe_push (tree, heap, tf->dest_array, label);
654     }
655
656   /* In the case of a GOTO we want to record the destination label,
657      since with a GIMPLE_COND we have an easy access to the then/else
658      labels. */
659   new_stmt = stmt;
660   record_in_goto_queue (tf, new_stmt, index, true);
661
662 }
663
664 /* For any GIMPLE_GOTO or GIMPLE_RETURN, decide whether it leaves a try_finally
665    node, and if so record that fact in the goto queue associated with that
666    try_finally node.  */
667
668 static void
669 maybe_record_in_goto_queue (struct leh_state *state, gimple stmt)
670 {
671   struct leh_tf_state *tf = state->tf;
672   treemple new_stmt;
673
674   if (!tf)
675     return;
676
677   switch (gimple_code (stmt))
678     {
679     case GIMPLE_COND:
680       new_stmt.tp = gimple_op_ptr (stmt, 2);
681       record_in_goto_queue_label (tf, new_stmt, gimple_cond_true_label (stmt));
682       new_stmt.tp = gimple_op_ptr (stmt, 3);
683       record_in_goto_queue_label (tf, new_stmt, gimple_cond_false_label (stmt));
684       break;
685     case GIMPLE_GOTO:
686       new_stmt.g = stmt;
687       record_in_goto_queue_label (tf, new_stmt, gimple_goto_dest (stmt));
688       break;
689
690     case GIMPLE_RETURN:
691       tf->may_return = true;
692       new_stmt.g = stmt;
693       record_in_goto_queue (tf, new_stmt, -1, false);
694       break;
695
696     default:
697       gcc_unreachable ();
698     }
699 }
700
701
702 #ifdef ENABLE_CHECKING
703 /* We do not process GIMPLE_SWITCHes for now.  As long as the original source
704    was in fact structured, and we've not yet done jump threading, then none
705    of the labels will leave outer GIMPLE_TRY_FINALLY nodes. Verify this.  */
706
707 static void
708 verify_norecord_switch_expr (struct leh_state *state, gimple switch_expr)
709 {
710   struct leh_tf_state *tf = state->tf;
711   size_t i, n;
712
713   if (!tf)
714     return;
715
716   n = gimple_switch_num_labels (switch_expr);
717
718   for (i = 0; i < n; ++i)
719     {
720       treemple temp;
721       tree lab = CASE_LABEL (gimple_switch_label (switch_expr, i));
722       temp.t = lab;
723       gcc_assert (!outside_finally_tree (temp, tf->try_finally_expr));
724     }
725 }
726 #else
727 #define verify_norecord_switch_expr(state, switch_expr)
728 #endif
729
730 /* Redirect a RETURN_EXPR pointed to by STMT_P to FINLAB.  Place in CONT_P
731    whatever is needed to finish the return.  If MOD is non-null, insert it
732    before the new branch.  RETURN_VALUE_P is a cache containing a temporary
733    variable to be used in manipulating the value returned from the function.  */
734
735 static void
736 do_return_redirection (struct goto_queue_node *q, tree finlab, gimple_seq mod,
737                        tree *return_value_p)
738 {
739   tree ret_expr;
740   gimple x;
741
742   /* In the case of a return, the queue node must be a gimple statement. */
743   gcc_assert (!q->is_label);
744
745   ret_expr = gimple_return_retval (q->stmt.g);
746
747   if (ret_expr)
748     {
749       if (!*return_value_p)
750         *return_value_p = ret_expr;
751       else
752         gcc_assert (*return_value_p == ret_expr);
753       q->cont_stmt = q->stmt.g;
754       /* The nasty part about redirecting the return value is that the
755          return value itself is to be computed before the FINALLY block
756          is executed.  e.g.
757
758                 int x;
759                 int foo (void)
760                 {
761                   x = 0;
762                   try {
763                     return x;
764                   } finally {
765                     x++;
766                   }
767                 }
768
769           should return 0, not 1.  Arrange for this to happen by copying
770           computed the return value into a local temporary.  This also
771           allows us to redirect multiple return statements through the
772           same destination block; whether this is a net win or not really
773           depends, I guess, but it does make generation of the switch in
774           lower_try_finally_switch easier.  */
775
776       if (TREE_CODE (ret_expr) == RESULT_DECL)
777         {
778           if (!*return_value_p)
779             *return_value_p = ret_expr;
780           else
781             gcc_assert (*return_value_p == ret_expr);
782           q->cont_stmt = q->stmt.g;
783         }
784       else
785           gcc_unreachable ();
786     }
787   else
788       /* If we don't return a value, all return statements are the same.  */
789       q->cont_stmt = q->stmt.g;
790
791   if (!q->repl_stmt)
792     q->repl_stmt = gimple_seq_alloc ();
793
794   if (mod)
795     gimple_seq_add_seq (&q->repl_stmt, mod);
796
797   x = gimple_build_goto (finlab);
798   gimple_seq_add_stmt (&q->repl_stmt, x);
799 }
800
801 /* Similar, but easier, for GIMPLE_GOTO.  */
802
803 static void
804 do_goto_redirection (struct goto_queue_node *q, tree finlab, gimple_seq mod,
805                      struct leh_tf_state *tf)
806 {
807   gimple x;
808
809   gcc_assert (q->is_label);
810   if (!q->repl_stmt)
811     q->repl_stmt = gimple_seq_alloc ();
812
813   q->cont_stmt = gimple_build_goto (VEC_index (tree, tf->dest_array,q->index));
814
815   if (mod)
816     gimple_seq_add_seq (&q->repl_stmt, mod);
817
818   x = gimple_build_goto (finlab);
819   gimple_seq_add_stmt (&q->repl_stmt, x);
820 }
821
822 /* We want to transform
823         try { body; } catch { stuff; }
824    to
825         body; goto over; lab: stuff; over:
826
827    TP is a GIMPLE_TRY node.  LAB is the label that
828    should be placed before the second operand, or NULL.  OVER is
829    an existing label that should be put at the exit, or NULL.  */
830
831 static gimple_seq
832 frob_into_branch_around (gimple tp, tree lab, tree over)
833 {
834   gimple x;
835   gimple_seq cleanup, result;
836   location_t loc = gimple_location (tp);
837
838   cleanup = gimple_try_cleanup (tp);
839   result = gimple_try_eval (tp);
840
841   if (gimple_seq_may_fallthru (result))
842     {
843       if (!over)
844         over = create_artificial_label (loc);
845       x = gimple_build_goto (over);
846       gimple_seq_add_stmt (&result, x);
847     }
848
849   if (lab)
850     {
851       x = gimple_build_label (lab);
852       gimple_seq_add_stmt (&result, x);
853     }
854
855   gimple_seq_add_seq (&result, cleanup);
856
857   if (over)
858     {
859       x = gimple_build_label (over);
860       gimple_seq_add_stmt (&result, x);
861     }
862   return result;
863 }
864
865 /* A subroutine of lower_try_finally.  Duplicate the tree rooted at T.
866    Make sure to record all new labels found.  */
867
868 static gimple_seq
869 lower_try_finally_dup_block (gimple_seq seq, struct leh_state *outer_state)
870 {
871   gimple region = NULL;
872   gimple_seq new_seq;
873
874   new_seq = copy_gimple_seq_and_replace_locals (seq);
875
876   if (outer_state->tf)
877     region = outer_state->tf->try_finally_expr;
878   collect_finally_tree_1 (new_seq, region);
879
880   return new_seq;
881 }
882
883 /* A subroutine of lower_try_finally.  Create a fallthru label for
884    the given try_finally state.  The only tricky bit here is that
885    we have to make sure to record the label in our outer context.  */
886
887 static tree
888 lower_try_finally_fallthru_label (struct leh_tf_state *tf)
889 {
890   tree label = tf->fallthru_label;
891   treemple temp;
892
893   if (!label)
894     {
895       label = create_artificial_label (gimple_location (tf->try_finally_expr));
896       tf->fallthru_label = label;
897       if (tf->outer->tf)
898         {
899           temp.t = label;
900           record_in_finally_tree (temp, tf->outer->tf->try_finally_expr);
901         }
902     }
903   return label;
904 }
905
906 /* A subroutine of lower_try_finally.  If lang_protect_cleanup_actions
907    returns non-null, then the language requires that the exception path out
908    of a try_finally be treated specially.  To wit: the code within the
909    finally block may not itself throw an exception.  We have two choices here.
910    First we can duplicate the finally block and wrap it in a must_not_throw
911    region.  Second, we can generate code like
912
913         try {
914           finally_block;
915         } catch {
916           if (fintmp == eh_edge)
917             protect_cleanup_actions;
918         }
919
920    where "fintmp" is the temporary used in the switch statement generation
921    alternative considered below.  For the nonce, we always choose the first
922    option.
923
924    THIS_STATE may be null if this is a try-cleanup, not a try-finally.  */
925
926 static void
927 honor_protect_cleanup_actions (struct leh_state *outer_state,
928                                struct leh_state *this_state,
929                                struct leh_tf_state *tf)
930 {
931   gimple protect_cleanup_actions;
932   gimple_stmt_iterator gsi;
933   bool finally_may_fallthru;
934   gimple_seq finally;
935   gimple x;
936
937   /* First check for nothing to do.  */
938   if (lang_protect_cleanup_actions)
939     protect_cleanup_actions = lang_protect_cleanup_actions ();
940   else
941     protect_cleanup_actions = NULL;
942
943   finally = gimple_try_cleanup (tf->top_p);
944
945   /* If the EH case of the finally block can fall through, this may be a
946      structure of the form
947         try {
948           try {
949             throw ...;
950           } cleanup {
951             try {
952               throw ...;
953             } catch (...) {
954             }
955           }
956         } catch (...) {
957           yyy;
958         }
959     E.g. with an inline destructor with an embedded try block.  In this
960     case we must save the runtime EH data around the nested exception.
961
962     This complication means that any time the previous runtime data might
963     be used (via fallthru from the finally) we handle the eh case here,
964     whether or not protect_cleanup_actions is active.  */
965
966   finally_may_fallthru = gimple_seq_may_fallthru (finally);
967   if (!finally_may_fallthru && !protect_cleanup_actions)
968     return;
969
970   /* Duplicate the FINALLY block.  Only need to do this for try-finally,
971      and not for cleanups.  */
972   if (this_state)
973     finally = lower_try_finally_dup_block (finally, outer_state);
974
975   /* If this cleanup consists of a TRY_CATCH_EXPR with TRY_CATCH_IS_CLEANUP
976      set, the handler of the TRY_CATCH_EXPR is another cleanup which ought
977      to be in an enclosing scope, but needs to be implemented at this level
978      to avoid a nesting violation (see wrap_temporary_cleanups in
979      cp/decl.c).  Since it's logically at an outer level, we should call
980      terminate before we get to it, so strip it away before adding the
981      MUST_NOT_THROW filter.  */
982   gsi = gsi_start (finally);
983   x = gsi_stmt (gsi);
984   if (protect_cleanup_actions
985       && gimple_code (x) == GIMPLE_TRY
986       && gimple_try_kind (x) == GIMPLE_TRY_CATCH
987       && gimple_try_catch_is_cleanup (x))
988     {
989       gsi_insert_seq_before (&gsi, gimple_try_eval (x), GSI_SAME_STMT);
990       gsi_remove (&gsi, false);
991     }
992
993   /* Resume execution after the exception.  Adding this now lets
994      lower_eh_filter not add unnecessary gotos, as it is clear that
995      we never fallthru from this copy of the finally block.  */
996   if (finally_may_fallthru)
997     {
998       tree save_eptr, save_filt;
999       tree tmp;
1000
1001       save_eptr = create_tmp_var (ptr_type_node, "save_eptr");
1002       save_filt = create_tmp_var (integer_type_node, "save_filt");
1003
1004       gsi = gsi_start (finally);
1005       tmp = build0 (EXC_PTR_EXPR, ptr_type_node);
1006       x = gimple_build_assign (save_eptr, tmp);
1007       gsi_insert_before (&gsi, x, GSI_CONTINUE_LINKING);
1008
1009       tmp = build0 (FILTER_EXPR, integer_type_node);
1010       x = gimple_build_assign (save_filt, tmp);
1011       gsi_insert_before (&gsi, x, GSI_CONTINUE_LINKING);
1012
1013       gsi = gsi_last (finally);
1014       tmp = build0 (EXC_PTR_EXPR, ptr_type_node);
1015       x = gimple_build_assign (tmp, save_eptr);
1016       gsi_insert_after (&gsi, x, GSI_CONTINUE_LINKING);
1017
1018       tmp = build0 (FILTER_EXPR, integer_type_node);
1019       x = gimple_build_assign (tmp, save_filt);
1020       gsi_insert_after (&gsi, x, GSI_CONTINUE_LINKING);
1021
1022       x = gimple_build_resx (get_eh_region_number (tf->region));
1023       gsi_insert_after (&gsi, x, GSI_CONTINUE_LINKING);
1024     }
1025
1026   /* Wrap the block with protect_cleanup_actions as the action.  */
1027   if (protect_cleanup_actions)
1028     {
1029       gimple_seq seq = NULL, failure = NULL;
1030
1031       gimple_seq_add_stmt (&failure, protect_cleanup_actions);
1032       x = gimple_build_eh_filter (NULL, failure);
1033       gimple_eh_filter_set_must_not_throw (x, 1);
1034
1035       gimple_seq_add_stmt (&seq, x);
1036       x = gimple_build_try (finally, seq, GIMPLE_TRY_CATCH);
1037       finally = lower_eh_filter (outer_state, x);
1038     }
1039   else
1040     lower_eh_constructs_1 (outer_state, finally);
1041
1042   /* Hook this up to the end of the existing try block.  If we
1043      previously fell through the end, we'll have to branch around.
1044      This means adding a new goto, and adding it to the queue.  */
1045
1046   gsi = gsi_last (gimple_try_eval (tf->top_p));
1047
1048   if (tf->may_fallthru)
1049     {
1050       tree tmp;
1051       tmp = lower_try_finally_fallthru_label (tf);
1052       x = gimple_build_goto (tmp);
1053       gsi_insert_after (&gsi, x, GSI_CONTINUE_LINKING);
1054
1055       if (this_state)
1056         maybe_record_in_goto_queue (this_state, x);
1057
1058       tf->may_fallthru = false;
1059     }
1060
1061   x = gimple_build_label (tf->eh_label);
1062   gsi_insert_after (&gsi, x, GSI_CONTINUE_LINKING);
1063   gsi_insert_seq_after (&gsi, finally, GSI_CONTINUE_LINKING);
1064
1065   /* Having now been handled, EH isn't to be considered with
1066      the rest of the outgoing edges.  */
1067   tf->may_throw = false;
1068 }
1069
1070 /* A subroutine of lower_try_finally.  We have determined that there is
1071    no fallthru edge out of the finally block.  This means that there is
1072    no outgoing edge corresponding to any incoming edge.  Restructure the
1073    try_finally node for this special case.  */
1074
1075 static void
1076 lower_try_finally_nofallthru (struct leh_state *state,
1077                               struct leh_tf_state *tf)
1078 {
1079   tree lab, return_val;
1080   gimple x;
1081   gimple_seq finally;
1082   struct goto_queue_node *q, *qe;
1083
1084   if (tf->may_throw)
1085     lab = tf->eh_label;
1086   else
1087     lab = create_artificial_label (gimple_location (tf->try_finally_expr));
1088
1089   /* We expect that tf->top_p is a GIMPLE_TRY. */
1090   finally = gimple_try_cleanup (tf->top_p);
1091   tf->top_p_seq = gimple_try_eval (tf->top_p);
1092
1093   x = gimple_build_label (lab);
1094   gimple_seq_add_stmt (&tf->top_p_seq, x);
1095
1096   return_val = NULL;
1097   q = tf->goto_queue;
1098   qe = q + tf->goto_queue_active;
1099   for (; q < qe; ++q)
1100     if (q->index < 0)
1101       do_return_redirection (q, lab, NULL, &return_val);
1102     else
1103       do_goto_redirection (q, lab, NULL, tf);
1104
1105   replace_goto_queue (tf);
1106
1107   lower_eh_constructs_1 (state, finally);
1108   gimple_seq_add_seq (&tf->top_p_seq, finally);
1109 }
1110
1111 /* A subroutine of lower_try_finally.  We have determined that there is
1112    exactly one destination of the finally block.  Restructure the
1113    try_finally node for this special case.  */
1114
1115 static void
1116 lower_try_finally_onedest (struct leh_state *state, struct leh_tf_state *tf)
1117 {
1118   struct goto_queue_node *q, *qe;
1119   gimple x;
1120   gimple_seq finally;
1121   tree finally_label;
1122   location_t loc = gimple_location (tf->try_finally_expr);
1123
1124   finally = gimple_try_cleanup (tf->top_p);
1125   tf->top_p_seq = gimple_try_eval (tf->top_p);
1126
1127   lower_eh_constructs_1 (state, finally);
1128
1129   if (tf->may_throw)
1130     {
1131       /* Only reachable via the exception edge.  Add the given label to
1132          the head of the FINALLY block.  Append a RESX at the end.  */
1133
1134       x = gimple_build_label (tf->eh_label);
1135       gimple_seq_add_stmt (&tf->top_p_seq, x);
1136
1137       gimple_seq_add_seq (&tf->top_p_seq, finally);
1138
1139       x = gimple_build_resx (get_eh_region_number (tf->region));
1140
1141       gimple_seq_add_stmt (&tf->top_p_seq, x);
1142
1143       return;
1144     }
1145
1146   if (tf->may_fallthru)
1147     {
1148       /* Only reachable via the fallthru edge.  Do nothing but let
1149          the two blocks run together; we'll fall out the bottom.  */
1150       gimple_seq_add_seq (&tf->top_p_seq, finally);
1151       return;
1152     }
1153
1154   finally_label = create_artificial_label (loc);
1155   x = gimple_build_label (finally_label);
1156   gimple_seq_add_stmt (&tf->top_p_seq, x);
1157
1158   gimple_seq_add_seq (&tf->top_p_seq, finally);
1159
1160   q = tf->goto_queue;
1161   qe = q + tf->goto_queue_active;
1162
1163   if (tf->may_return)
1164     {
1165       /* Reachable by return expressions only.  Redirect them.  */
1166       tree return_val = NULL;
1167       for (; q < qe; ++q)
1168         do_return_redirection (q, finally_label, NULL, &return_val);
1169       replace_goto_queue (tf);
1170     }
1171   else
1172     {
1173       /* Reachable by goto expressions only.  Redirect them.  */
1174       for (; q < qe; ++q)
1175         do_goto_redirection (q, finally_label, NULL, tf);
1176       replace_goto_queue (tf);
1177
1178       if (VEC_index (tree, tf->dest_array, 0) == tf->fallthru_label)
1179         {
1180           /* Reachable by goto to fallthru label only.  Redirect it
1181              to the new label (already created, sadly), and do not
1182              emit the final branch out, or the fallthru label.  */
1183           tf->fallthru_label = NULL;
1184           return;
1185         }
1186     }
1187
1188   /* Place the original return/goto to the original destination
1189      immediately after the finally block. */
1190   x = tf->goto_queue[0].cont_stmt;
1191   gimple_seq_add_stmt (&tf->top_p_seq, x);
1192   maybe_record_in_goto_queue (state, x);
1193 }
1194
1195 /* A subroutine of lower_try_finally.  There are multiple edges incoming
1196    and outgoing from the finally block.  Implement this by duplicating the
1197    finally block for every destination.  */
1198
1199 static void
1200 lower_try_finally_copy (struct leh_state *state, struct leh_tf_state *tf)
1201 {
1202   gimple_seq finally;
1203   gimple_seq new_stmt;
1204   gimple_seq seq;
1205   gimple x;
1206   tree tmp;
1207   location_t tf_loc = gimple_location (tf->try_finally_expr);
1208
1209   finally = gimple_try_cleanup (tf->top_p);
1210   tf->top_p_seq = gimple_try_eval (tf->top_p);
1211   new_stmt = NULL;
1212
1213   if (tf->may_fallthru)
1214     {
1215       seq = lower_try_finally_dup_block (finally, state);
1216       lower_eh_constructs_1 (state, seq);
1217       gimple_seq_add_seq (&new_stmt, seq);
1218
1219       tmp = lower_try_finally_fallthru_label (tf);
1220       x = gimple_build_goto (tmp);
1221       gimple_seq_add_stmt (&new_stmt, x);
1222     }
1223
1224   if (tf->may_throw)
1225     {
1226       x = gimple_build_label (tf->eh_label);
1227       gimple_seq_add_stmt (&new_stmt, x);
1228
1229       seq = lower_try_finally_dup_block (finally, state);
1230       lower_eh_constructs_1 (state, seq);
1231       gimple_seq_add_seq (&new_stmt, seq);
1232
1233       x = gimple_build_resx (get_eh_region_number (tf->region));
1234       gimple_seq_add_stmt (&new_stmt, x);
1235     }
1236
1237   if (tf->goto_queue)
1238     {
1239       struct goto_queue_node *q, *qe;
1240       tree return_val = NULL;
1241       int return_index, index;
1242       struct labels_s
1243       {
1244         struct goto_queue_node *q;
1245         tree label;
1246       } *labels;
1247
1248       return_index = VEC_length (tree, tf->dest_array);
1249       labels = XCNEWVEC (struct labels_s, return_index + 1);
1250
1251       q = tf->goto_queue;
1252       qe = q + tf->goto_queue_active;
1253       for (; q < qe; q++)
1254         {
1255           index = q->index < 0 ? return_index : q->index;
1256
1257           if (!labels[index].q)
1258             labels[index].q = q;
1259         }
1260
1261       for (index = 0; index < return_index + 1; index++)
1262         {
1263           tree lab;
1264
1265           q = labels[index].q;
1266           if (! q)
1267             continue;
1268
1269           lab = labels[index].label
1270             = create_artificial_label (tf_loc);
1271
1272           if (index == return_index)
1273             do_return_redirection (q, lab, NULL, &return_val);
1274           else
1275             do_goto_redirection (q, lab, NULL, tf);
1276
1277           x = gimple_build_label (lab);
1278           gimple_seq_add_stmt (&new_stmt, x);
1279
1280           seq = lower_try_finally_dup_block (finally, state);
1281           lower_eh_constructs_1 (state, seq);
1282           gimple_seq_add_seq (&new_stmt, seq);
1283
1284           gimple_seq_add_stmt (&new_stmt, q->cont_stmt);
1285           maybe_record_in_goto_queue (state, q->cont_stmt);
1286         }
1287
1288       for (q = tf->goto_queue; q < qe; q++)
1289         {
1290           tree lab;
1291
1292           index = q->index < 0 ? return_index : q->index;
1293
1294           if (labels[index].q == q)
1295             continue;
1296
1297           lab = labels[index].label;
1298
1299           if (index == return_index)
1300             do_return_redirection (q, lab, NULL, &return_val);
1301           else
1302             do_goto_redirection (q, lab, NULL, tf);
1303         }
1304         
1305       replace_goto_queue (tf);
1306       free (labels);
1307     }
1308
1309   /* Need to link new stmts after running replace_goto_queue due
1310      to not wanting to process the same goto stmts twice.  */
1311   gimple_seq_add_seq (&tf->top_p_seq, new_stmt);
1312 }
1313
1314 /* A subroutine of lower_try_finally.  There are multiple edges incoming
1315    and outgoing from the finally block.  Implement this by instrumenting
1316    each incoming edge and creating a switch statement at the end of the
1317    finally block that branches to the appropriate destination.  */
1318
1319 static void
1320 lower_try_finally_switch (struct leh_state *state, struct leh_tf_state *tf)
1321 {
1322   struct goto_queue_node *q, *qe;
1323   tree return_val = NULL;
1324   tree finally_tmp, finally_label;
1325   int return_index, eh_index, fallthru_index;
1326   int nlabels, ndests, j, last_case_index;
1327   tree last_case;
1328   VEC (tree,heap) *case_label_vec;
1329   gimple_seq switch_body;
1330   gimple x;
1331   tree tmp;
1332   gimple switch_stmt;
1333   gimple_seq finally;
1334   struct pointer_map_t *cont_map = NULL;
1335   /* The location of the TRY_FINALLY stmt.  */
1336   location_t tf_loc = gimple_location (tf->try_finally_expr);
1337   /* The location of the finally block.  */
1338   location_t finally_loc;
1339
1340   switch_body = gimple_seq_alloc ();
1341
1342   /* Mash the TRY block to the head of the chain.  */
1343   finally = gimple_try_cleanup (tf->top_p);
1344   tf->top_p_seq = gimple_try_eval (tf->top_p);
1345
1346   /* The location of the finally is either the last stmt in the finally
1347      block or the location of the TRY_FINALLY itself.  */
1348   finally_loc = gimple_seq_last_stmt (tf->top_p_seq) != NULL ?
1349     gimple_location (gimple_seq_last_stmt (tf->top_p_seq))
1350     : tf_loc;
1351
1352   /* Lower the finally block itself.  */
1353   lower_eh_constructs_1 (state, finally);
1354
1355   /* Prepare for switch statement generation.  */
1356   nlabels = VEC_length (tree, tf->dest_array);
1357   return_index = nlabels;
1358   eh_index = return_index + tf->may_return;
1359   fallthru_index = eh_index + tf->may_throw;
1360   ndests = fallthru_index + tf->may_fallthru;
1361
1362   finally_tmp = create_tmp_var (integer_type_node, "finally_tmp");
1363   finally_label = create_artificial_label (finally_loc);
1364
1365   /* We use VEC_quick_push on case_label_vec throughout this function,
1366      since we know the size in advance and allocate precisely as muce
1367      space as needed.  */
1368   case_label_vec = VEC_alloc (tree, heap, ndests);
1369   last_case = NULL;
1370   last_case_index = 0;
1371
1372   /* Begin inserting code for getting to the finally block.  Things
1373      are done in this order to correspond to the sequence the code is
1374      layed out.  */
1375
1376   if (tf->may_fallthru)
1377     {
1378       x = gimple_build_assign (finally_tmp, build_int_cst (integer_type_node,
1379                                                            fallthru_index));
1380       gimple_seq_add_stmt (&tf->top_p_seq, x);
1381
1382       if (tf->may_throw)
1383         {
1384           x = gimple_build_goto (finally_label);
1385           gimple_seq_add_stmt (&tf->top_p_seq, x);
1386         }
1387
1388
1389       last_case = build3 (CASE_LABEL_EXPR, void_type_node,
1390                           build_int_cst (NULL_TREE, fallthru_index), NULL,
1391                           create_artificial_label (tf_loc));
1392       VEC_quick_push (tree, case_label_vec, last_case);
1393       last_case_index++;
1394
1395       x = gimple_build_label (CASE_LABEL (last_case));
1396       gimple_seq_add_stmt (&switch_body, x);
1397
1398       tmp = lower_try_finally_fallthru_label (tf);
1399       x = gimple_build_goto (tmp);
1400       gimple_seq_add_stmt (&switch_body, x);
1401     }
1402
1403   if (tf->may_throw)
1404     {
1405       x = gimple_build_label (tf->eh_label);
1406       gimple_seq_add_stmt (&tf->top_p_seq, x);
1407
1408       x = gimple_build_assign (finally_tmp, build_int_cst (integer_type_node,
1409                                                            eh_index));
1410       gimple_seq_add_stmt (&tf->top_p_seq, x);
1411
1412       last_case = build3 (CASE_LABEL_EXPR, void_type_node,
1413                           build_int_cst (NULL_TREE, eh_index), NULL,
1414                           create_artificial_label (tf_loc));
1415       VEC_quick_push (tree, case_label_vec, last_case);
1416       last_case_index++;
1417
1418       x = gimple_build_label (CASE_LABEL (last_case));
1419       gimple_seq_add_stmt (&switch_body, x);
1420       x = gimple_build_resx (get_eh_region_number (tf->region));
1421       gimple_seq_add_stmt (&switch_body, x);
1422     }
1423
1424   x = gimple_build_label (finally_label);
1425   gimple_seq_add_stmt (&tf->top_p_seq, x);
1426
1427   gimple_seq_add_seq (&tf->top_p_seq, finally);
1428
1429   /* Redirect each incoming goto edge.  */
1430   q = tf->goto_queue;
1431   qe = q + tf->goto_queue_active;
1432   j = last_case_index + tf->may_return;
1433   /* Prepare the assignments to finally_tmp that are executed upon the
1434      entrance through a particular edge. */
1435   for (; q < qe; ++q)
1436     {
1437       gimple_seq mod;
1438       int switch_id;
1439       unsigned int case_index;
1440
1441       mod = gimple_seq_alloc ();
1442
1443       if (q->index < 0)
1444         {
1445           x = gimple_build_assign (finally_tmp,
1446                                    build_int_cst (integer_type_node,
1447                                                   return_index));
1448           gimple_seq_add_stmt (&mod, x);
1449           do_return_redirection (q, finally_label, mod, &return_val);
1450           switch_id = return_index;
1451         }
1452       else
1453         {
1454           x = gimple_build_assign (finally_tmp,
1455                                    build_int_cst (integer_type_node, q->index));
1456           gimple_seq_add_stmt (&mod, x);
1457           do_goto_redirection (q, finally_label, mod, tf);
1458           switch_id = q->index;
1459         }
1460
1461       case_index = j + q->index;
1462       if (VEC_length (tree, case_label_vec) <= case_index
1463           || !VEC_index (tree, case_label_vec, case_index))
1464         {
1465           tree case_lab;
1466           void **slot;
1467           case_lab = build3 (CASE_LABEL_EXPR, void_type_node,
1468                              build_int_cst (NULL_TREE, switch_id), NULL,
1469                              NULL);
1470           /* We store the cont_stmt in the pointer map, so that we can recover
1471              it in the loop below.  We don't create the new label while
1472              walking the goto_queue because pointers don't offer a stable 
1473              order.  */
1474           if (!cont_map)
1475             cont_map = pointer_map_create ();
1476           slot = pointer_map_insert (cont_map, case_lab);
1477           *slot = q->cont_stmt;
1478           VEC_quick_push (tree, case_label_vec, case_lab);
1479         }
1480     }
1481   for (j = last_case_index; j < last_case_index + nlabels; j++)
1482     {
1483       tree label;
1484       gimple cont_stmt;
1485       void **slot;
1486
1487       last_case = VEC_index (tree, case_label_vec, j);
1488
1489       gcc_assert (last_case);
1490       gcc_assert (cont_map);
1491
1492       slot = pointer_map_contains (cont_map, last_case);
1493       /* As the comment above suggests, CASE_LABEL (last_case) was just a
1494          placeholder, it does not store an actual label, yet. */
1495       gcc_assert (slot);
1496       cont_stmt = *(gimple *) slot;
1497
1498       label = create_artificial_label (tf_loc);
1499       CASE_LABEL (last_case) = label;
1500
1501       x = gimple_build_label (label);
1502       gimple_seq_add_stmt (&switch_body, x);
1503       gimple_seq_add_stmt (&switch_body, cont_stmt);
1504       maybe_record_in_goto_queue (state, cont_stmt);
1505     }
1506   if (cont_map)
1507     pointer_map_destroy (cont_map);
1508
1509   replace_goto_queue (tf);
1510
1511   /* Make sure that the last case is the default label, as one is required.
1512      Then sort the labels, which is also required in GIMPLE.  */
1513   CASE_LOW (last_case) = NULL;
1514   sort_case_labels (case_label_vec);
1515
1516   /* Build the switch statement, setting last_case to be the default
1517      label.  */
1518   switch_stmt = gimple_build_switch_vec (finally_tmp, last_case,
1519                                          case_label_vec);
1520   gimple_set_location (switch_stmt, finally_loc);
1521
1522   /* Need to link SWITCH_STMT after running replace_goto_queue
1523      due to not wanting to process the same goto stmts twice.  */
1524   gimple_seq_add_stmt (&tf->top_p_seq, switch_stmt);
1525   gimple_seq_add_seq (&tf->top_p_seq, switch_body);
1526 }
1527
1528 /* Decide whether or not we are going to duplicate the finally block.
1529    There are several considerations.
1530
1531    First, if this is Java, then the finally block contains code
1532    written by the user.  It has line numbers associated with it,
1533    so duplicating the block means it's difficult to set a breakpoint.
1534    Since controlling code generation via -g is verboten, we simply
1535    never duplicate code without optimization.
1536
1537    Second, we'd like to prevent egregious code growth.  One way to
1538    do this is to estimate the size of the finally block, multiply
1539    that by the number of copies we'd need to make, and compare against
1540    the estimate of the size of the switch machinery we'd have to add.  */
1541
1542 static bool
1543 decide_copy_try_finally (int ndests, gimple_seq finally)
1544 {
1545   int f_estimate, sw_estimate;
1546
1547   if (!optimize)
1548     return false;
1549
1550   /* Finally estimate N times, plus N gotos.  */
1551   f_estimate = count_insns_seq (finally, &eni_size_weights);
1552   f_estimate = (f_estimate + 1) * ndests;
1553
1554   /* Switch statement (cost 10), N variable assignments, N gotos.  */
1555   sw_estimate = 10 + 2 * ndests;
1556
1557   /* Optimize for size clearly wants our best guess.  */
1558   if (optimize_function_for_size_p (cfun))
1559     return f_estimate < sw_estimate;
1560
1561   /* ??? These numbers are completely made up so far.  */
1562   if (optimize > 1)
1563     return f_estimate < 100 || f_estimate < sw_estimate * 2;
1564   else
1565     return f_estimate < 40 || f_estimate * 2 < sw_estimate * 3;
1566 }
1567
1568
1569 /* A subroutine of lower_eh_constructs_1.  Lower a GIMPLE_TRY_FINALLY nodes
1570    to a sequence of labels and blocks, plus the exception region trees
1571    that record all the magic.  This is complicated by the need to
1572    arrange for the FINALLY block to be executed on all exits.  */
1573
1574 static gimple_seq
1575 lower_try_finally (struct leh_state *state, gimple tp)
1576 {
1577   struct leh_tf_state this_tf;
1578   struct leh_state this_state;
1579   int ndests;
1580   location_t tf_loc = gimple_location (tp);
1581
1582   /* Process the try block.  */
1583
1584   memset (&this_tf, 0, sizeof (this_tf));
1585   this_tf.try_finally_expr = tp;
1586   this_tf.top_p = tp;
1587   this_tf.outer = state;
1588   if (using_eh_for_cleanups_p)
1589     this_tf.region
1590       = gen_eh_region_cleanup (state->cur_region);
1591   else
1592     this_tf.region = NULL;
1593
1594   this_state.cur_region = this_tf.region;
1595   this_state.tf = &this_tf;
1596
1597   lower_eh_constructs_1 (&this_state, gimple_try_eval(tp));
1598
1599   /* Determine if the try block is escaped through the bottom.  */
1600   this_tf.may_fallthru = gimple_seq_may_fallthru (gimple_try_eval (tp));
1601
1602   /* Determine if any exceptions are possible within the try block.  */
1603   if (using_eh_for_cleanups_p)
1604     this_tf.may_throw = get_eh_region_may_contain_throw (this_tf.region);
1605   if (this_tf.may_throw)
1606     {
1607       this_tf.eh_label = create_artificial_label (tf_loc);
1608       set_eh_region_tree_label (this_tf.region, this_tf.eh_label);
1609       honor_protect_cleanup_actions (state, &this_state, &this_tf);
1610     }
1611
1612   /* Determine how many edges (still) reach the finally block.  Or rather,
1613      how many destinations are reached by the finally block.  Use this to
1614      determine how we process the finally block itself.  */
1615
1616   ndests = VEC_length (tree, this_tf.dest_array);
1617   ndests += this_tf.may_fallthru;
1618   ndests += this_tf.may_return;
1619   ndests += this_tf.may_throw;
1620
1621   /* If the FINALLY block is not reachable, dike it out.  */
1622   if (ndests == 0)
1623     {
1624       gimple_seq_add_seq (&this_tf.top_p_seq, gimple_try_eval (tp));
1625       gimple_try_set_cleanup (tp, NULL);
1626     }
1627   /* If the finally block doesn't fall through, then any destination
1628      we might try to impose there isn't reached either.  There may be
1629      some minor amount of cleanup and redirection still needed.  */
1630   else if (!gimple_seq_may_fallthru (gimple_try_cleanup (tp)))
1631     lower_try_finally_nofallthru (state, &this_tf);
1632
1633   /* We can easily special-case redirection to a single destination.  */
1634   else if (ndests == 1)
1635     lower_try_finally_onedest (state, &this_tf);
1636   else if (decide_copy_try_finally (ndests, gimple_try_cleanup (tp)))
1637     lower_try_finally_copy (state, &this_tf);
1638   else
1639     lower_try_finally_switch (state, &this_tf);
1640
1641   /* If someone requested we add a label at the end of the transformed
1642      block, do so.  */
1643   if (this_tf.fallthru_label)
1644     {
1645       /* This must be reached only if ndests == 0. */
1646       gimple x = gimple_build_label (this_tf.fallthru_label);
1647       gimple_seq_add_stmt (&this_tf.top_p_seq, x);
1648     }
1649
1650   VEC_free (tree, heap, this_tf.dest_array);
1651   if (this_tf.goto_queue)
1652     free (this_tf.goto_queue);
1653   if (this_tf.goto_queue_map)
1654     pointer_map_destroy (this_tf.goto_queue_map);
1655
1656   return this_tf.top_p_seq;
1657 }
1658
1659 /* A subroutine of lower_eh_constructs_1.  Lower a GIMPLE_TRY_CATCH with a
1660    list of GIMPLE_CATCH to a sequence of labels and blocks, plus the
1661    exception region trees that records all the magic.  */
1662
1663 static gimple_seq
1664 lower_catch (struct leh_state *state, gimple tp)
1665 {
1666   struct eh_region_d *try_region;
1667   struct leh_state this_state;
1668   gimple_stmt_iterator gsi;
1669   tree out_label;
1670   location_t try_catch_loc = gimple_location (tp);
1671
1672   try_region = gen_eh_region_try (state->cur_region);
1673   this_state.cur_region = try_region;
1674   this_state.tf = state->tf;
1675
1676   lower_eh_constructs_1 (&this_state, gimple_try_eval (tp));
1677
1678   if (!get_eh_region_may_contain_throw (try_region))
1679     {
1680       return gimple_try_eval (tp);
1681     }
1682
1683   out_label = NULL;
1684   for (gsi = gsi_start (gimple_try_cleanup (tp)); !gsi_end_p (gsi); )
1685     {
1686       struct eh_region_d *catch_region;
1687       tree eh_label;
1688       gimple x, gcatch;
1689
1690       gcatch = gsi_stmt (gsi);
1691       catch_region = gen_eh_region_catch (try_region,
1692                                           gimple_catch_types (gcatch));
1693
1694       this_state.cur_region = catch_region;
1695       lower_eh_constructs_1 (&this_state, gimple_catch_handler (gcatch));
1696
1697       eh_label = create_artificial_label (try_catch_loc);
1698       set_eh_region_tree_label (catch_region, eh_label);
1699
1700       x = gimple_build_label (eh_label);
1701       gsi_insert_before (&gsi, x, GSI_SAME_STMT);
1702
1703       if (gimple_seq_may_fallthru (gimple_catch_handler (gcatch)))
1704         {
1705           if (!out_label)
1706             out_label = create_artificial_label (try_catch_loc);
1707
1708           x = gimple_build_goto (out_label);
1709           gimple_seq_add_stmt (gimple_catch_handler_ptr (gcatch), x);
1710         }
1711
1712       gsi_insert_seq_before (&gsi, gimple_catch_handler (gcatch),
1713                              GSI_SAME_STMT);
1714       gsi_remove (&gsi, false);
1715     }
1716
1717   return frob_into_branch_around (tp, NULL, out_label);
1718 }
1719
1720 /* A subroutine of lower_eh_constructs_1.  Lower a GIMPLE_TRY with a
1721    GIMPLE_EH_FILTER to a sequence of labels and blocks, plus the exception
1722    region trees that record all the magic.  */
1723
1724 static gimple_seq
1725 lower_eh_filter (struct leh_state *state, gimple tp)
1726 {
1727   struct leh_state this_state;
1728   struct eh_region_d *this_region;
1729   gimple inner;
1730   tree eh_label;
1731
1732   inner = gimple_seq_first_stmt (gimple_try_cleanup (tp));
1733
1734   if (gimple_eh_filter_must_not_throw (inner))
1735     this_region = gen_eh_region_must_not_throw (state->cur_region);
1736   else
1737     this_region = gen_eh_region_allowed (state->cur_region,
1738                                          gimple_eh_filter_types (inner));
1739   this_state = *state;
1740   this_state.cur_region = this_region;
1741
1742   lower_eh_constructs_1 (&this_state, gimple_try_eval (tp));
1743
1744   if (!get_eh_region_may_contain_throw (this_region))
1745     {
1746       return gimple_try_eval (tp);
1747     }
1748
1749   lower_eh_constructs_1 (state, gimple_eh_filter_failure (inner));
1750   gimple_try_set_cleanup (tp, gimple_eh_filter_failure (inner));
1751
1752   eh_label = create_artificial_label (gimple_location (inner));
1753   set_eh_region_tree_label (this_region, eh_label);
1754
1755   return frob_into_branch_around (tp, eh_label, NULL);
1756 }
1757
1758 /* Implement a cleanup expression.  This is similar to try-finally,
1759    except that we only execute the cleanup block for exception edges.  */
1760
1761 static gimple_seq
1762 lower_cleanup (struct leh_state *state, gimple tp)
1763 {
1764   struct leh_state this_state;
1765   struct eh_region_d *this_region;
1766   struct leh_tf_state fake_tf;
1767   gimple_seq result;
1768
1769   /* If not using eh, then exception-only cleanups are no-ops.  */
1770   if (!flag_exceptions)
1771     {
1772       result = gimple_try_eval (tp);
1773       lower_eh_constructs_1 (state, result);
1774       return result;
1775     }
1776
1777   this_region = gen_eh_region_cleanup (state->cur_region);
1778   this_state = *state;
1779   this_state.cur_region = this_region;
1780
1781   lower_eh_constructs_1 (&this_state, gimple_try_eval (tp));
1782
1783   if (!get_eh_region_may_contain_throw (this_region))
1784     {
1785       return gimple_try_eval (tp);
1786     }
1787
1788   /* Build enough of a try-finally state so that we can reuse
1789      honor_protect_cleanup_actions.  */
1790   memset (&fake_tf, 0, sizeof (fake_tf));
1791   fake_tf.top_p = fake_tf.try_finally_expr = tp;
1792   fake_tf.outer = state;
1793   fake_tf.region = this_region;
1794   fake_tf.may_fallthru = gimple_seq_may_fallthru (gimple_try_eval (tp));
1795   fake_tf.may_throw = true;
1796
1797   fake_tf.eh_label = create_artificial_label (gimple_location (tp));
1798   set_eh_region_tree_label (this_region, fake_tf.eh_label);
1799
1800   honor_protect_cleanup_actions (state, NULL, &fake_tf);
1801
1802   if (fake_tf.may_throw)
1803     {
1804       /* In this case honor_protect_cleanup_actions had nothing to do,
1805          and we should process this normally.  */
1806       lower_eh_constructs_1 (state, gimple_try_cleanup (tp));
1807       result = frob_into_branch_around (tp, fake_tf.eh_label,
1808                                        fake_tf.fallthru_label);
1809     }
1810   else
1811     {
1812       /* In this case honor_protect_cleanup_actions did nearly all of
1813          the work.  All we have left is to append the fallthru_label.  */
1814
1815       result = gimple_try_eval (tp);
1816       if (fake_tf.fallthru_label)
1817         {
1818           gimple x = gimple_build_label (fake_tf.fallthru_label);
1819           gimple_seq_add_stmt (&result, x);
1820         }
1821     }
1822   return result;
1823 }
1824
1825
1826
1827 /* Main loop for lowering eh constructs. Also moves gsi to the next 
1828    statement. */
1829
1830 static void
1831 lower_eh_constructs_2 (struct leh_state *state, gimple_stmt_iterator *gsi)
1832 {
1833   gimple_seq replace;
1834   gimple x;
1835   gimple stmt = gsi_stmt (*gsi);
1836
1837   switch (gimple_code (stmt))
1838     {
1839     case GIMPLE_CALL:
1840     case GIMPLE_ASSIGN:
1841       /* If the stmt can throw use a new temporary for the assignment
1842          to a LHS.  This makes sure the old value of the LHS is
1843          available on the EH edge.  */
1844       if (stmt_could_throw_p (stmt)
1845           && gimple_has_lhs (stmt)
1846           && !tree_could_throw_p (gimple_get_lhs (stmt))
1847           && is_gimple_reg_type (TREE_TYPE (gimple_get_lhs (stmt))))
1848         {
1849           tree lhs = gimple_get_lhs (stmt);
1850           tree tmp = create_tmp_var (TREE_TYPE (lhs), NULL);
1851           gimple s = gimple_build_assign (lhs, tmp);
1852           gimple_set_location (s, gimple_location (stmt));
1853           gimple_set_block (s, gimple_block (stmt));
1854           gimple_set_lhs (stmt, tmp);
1855           if (TREE_CODE (TREE_TYPE (tmp)) == COMPLEX_TYPE
1856               || TREE_CODE (TREE_TYPE (tmp)) == VECTOR_TYPE)
1857             DECL_GIMPLE_REG_P (tmp) = 1;
1858           gsi_insert_after (gsi, s, GSI_SAME_STMT);
1859         }
1860       /* Look for things that can throw exceptions, and record them.  */
1861       if (state->cur_region && stmt_could_throw_p (stmt))
1862         {
1863           record_stmt_eh_region (state->cur_region, stmt);
1864           note_eh_region_may_contain_throw (state->cur_region);
1865         }
1866       break;
1867
1868     case GIMPLE_COND:
1869     case GIMPLE_GOTO:
1870     case GIMPLE_RETURN:
1871       maybe_record_in_goto_queue (state, stmt);
1872       break;
1873
1874     case GIMPLE_SWITCH:
1875       verify_norecord_switch_expr (state, stmt);
1876       break;
1877
1878     case GIMPLE_TRY:
1879       if (gimple_try_kind (stmt) == GIMPLE_TRY_FINALLY)
1880         replace = lower_try_finally (state, stmt);
1881       else
1882         {
1883           x = gimple_seq_first_stmt (gimple_try_cleanup (stmt));
1884           switch (gimple_code (x))
1885             {
1886             case GIMPLE_CATCH:
1887               replace = lower_catch (state, stmt);
1888               break;
1889             case GIMPLE_EH_FILTER:
1890               replace = lower_eh_filter (state, stmt);
1891               break;
1892             default:
1893               replace = lower_cleanup (state, stmt);
1894               break;
1895             }
1896         }
1897
1898       /* Remove the old stmt and insert the transformed sequence
1899          instead. */
1900       gsi_insert_seq_before (gsi, replace, GSI_SAME_STMT);
1901       gsi_remove (gsi, true);
1902
1903       /* Return since we don't want gsi_next () */
1904       return;
1905
1906     default:
1907       /* A type, a decl, or some kind of statement that we're not
1908          interested in.  Don't walk them.  */
1909       break;
1910     }
1911
1912   gsi_next (gsi);
1913 }
1914
1915 /* A helper to unwrap a gimple_seq and feed stmts to lower_eh_constructs_2. */
1916
1917 static void
1918 lower_eh_constructs_1 (struct leh_state *state, gimple_seq seq)
1919 {
1920   gimple_stmt_iterator gsi;
1921   for (gsi = gsi_start (seq); !gsi_end_p (gsi);)
1922     lower_eh_constructs_2 (state, &gsi);
1923 }
1924
1925 static unsigned int
1926 lower_eh_constructs (void)
1927 {
1928   struct leh_state null_state;
1929
1930   gimple_seq bodyp = gimple_body (current_function_decl);
1931
1932   finally_tree = htab_create (31, struct_ptr_hash, struct_ptr_eq, free);
1933
1934   collect_finally_tree_1 (bodyp, NULL);
1935
1936   memset (&null_state, 0, sizeof (null_state));
1937   lower_eh_constructs_1 (&null_state, bodyp);
1938
1939   htab_delete (finally_tree);
1940
1941   collect_eh_region_array ();
1942
1943   /* If this function needs a language specific EH personality routine
1944      and the frontend didn't already set one do so now.  */
1945   if (function_needs_eh_personality (cfun) == eh_personality_lang
1946       && !DECL_FUNCTION_PERSONALITY (current_function_decl))
1947     DECL_FUNCTION_PERSONALITY (current_function_decl)
1948       = lang_hooks.eh_personality ();
1949
1950   return 0;
1951 }
1952
1953 struct gimple_opt_pass pass_lower_eh =
1954 {
1955  {
1956   GIMPLE_PASS,
1957   "eh",                                 /* name */
1958   NULL,                                 /* gate */
1959   lower_eh_constructs,                  /* execute */
1960   NULL,                                 /* sub */
1961   NULL,                                 /* next */
1962   0,                                    /* static_pass_number */
1963   TV_TREE_EH,                           /* tv_id */
1964   PROP_gimple_lcf,                      /* properties_required */
1965   PROP_gimple_leh,                      /* properties_provided */
1966   0,                                    /* properties_destroyed */
1967   0,                                    /* todo_flags_start */
1968   TODO_dump_func                        /* todo_flags_finish */
1969  }
1970 };
1971
1972 \f
1973 /* Construct EH edges for STMT.  */
1974
1975 static void
1976 make_eh_edge (struct eh_region_d *region, void *data)
1977 {
1978   gimple stmt;
1979   tree lab;
1980   basic_block src, dst;
1981
1982   stmt = (gimple) data;
1983   lab = get_eh_region_tree_label (region);
1984
1985   src = gimple_bb (stmt);
1986   dst = label_to_block (lab);
1987
1988   make_edge (src, dst, EDGE_EH);
1989 }
1990
1991 /* See if STMT is call that might be inlined.  */
1992
1993 static bool
1994 inlinable_call_p (gimple stmt)
1995 {
1996   tree decl;
1997   if (gimple_code (stmt) != GIMPLE_CALL)
1998     return false;
1999   if (cfun->after_inlining)
2000     return false;
2001   /* Indirect calls can be propagated to direct call
2002      and inlined.  */
2003   decl = gimple_call_fndecl (stmt);
2004   if (!decl)
2005     return true;
2006   if (cgraph_function_flags_ready
2007       && cgraph_function_body_availability (cgraph_node (decl))
2008       < AVAIL_OVERWRITABLE)
2009     return false;
2010   return !DECL_UNINLINABLE (decl);
2011 }
2012
2013 void
2014 make_eh_edges (gimple stmt)
2015 {
2016   int region_nr;
2017   bool is_resx;
2018   bool inlinable = false;
2019   basic_block bb;
2020
2021   if (gimple_code (stmt) == GIMPLE_RESX)
2022     {
2023       region_nr = gimple_resx_region (stmt);
2024       is_resx = true;
2025     }
2026   else
2027     {
2028       region_nr = lookup_stmt_eh_region (stmt);
2029       if (region_nr < 0)
2030         return;
2031       is_resx = false;
2032       inlinable = inlinable_call_p (stmt);
2033     }
2034
2035   foreach_reachable_handler (region_nr, is_resx, inlinable, make_eh_edge, stmt);
2036
2037   /* Make CFG profile more consistent assuming that exception will resume to first
2038      available EH handler.  In practice this makes little difference, but we get
2039      fewer consistency errors in the dumps.  */
2040   bb = gimple_bb (stmt);
2041   if (is_resx && EDGE_COUNT (bb->succs))
2042     EDGE_SUCC (bb, 0)->probability = REG_BR_PROB_BASE;
2043 }
2044
2045 /* Redirect EH edge E to NEW_BB.  */
2046
2047 edge
2048 redirect_eh_edge (edge e, basic_block new_bb)
2049 {
2050   gimple stmt = gsi_stmt (gsi_last_bb (e->src));
2051   int region_nr, new_region_nr;
2052   bool is_resx;
2053   bool inlinable = false;
2054   tree label = gimple_block_label (new_bb);
2055   struct eh_region_d *r;
2056
2057   if (gimple_code (stmt) == GIMPLE_RESX)
2058     {
2059       region_nr = gimple_resx_region (stmt);
2060       is_resx = true;
2061     }
2062   else
2063     {
2064       region_nr = lookup_stmt_eh_region (stmt);
2065       gcc_assert (region_nr >= 0);
2066       is_resx = false;
2067       inlinable = inlinable_call_p (stmt);
2068     }
2069
2070   if (dump_file && (dump_flags & TDF_DETAILS))
2071     fprintf (dump_file, "Redirecting EH edge %i->%i to %i, region %i, resx %i\n",
2072              e->src->index, e->dest->index, new_bb->index, region_nr, is_resx);
2073   r = redirect_eh_edge_to_label (e, label, is_resx, inlinable, region_nr);
2074   new_region_nr = get_eh_region_number (r);
2075   if (new_region_nr != region_nr)
2076     {
2077       if (is_resx)
2078         gimple_resx_set_region (stmt, new_region_nr);
2079       else
2080         {
2081           remove_stmt_from_eh_region (stmt);
2082           add_stmt_to_eh_region (stmt, new_region_nr);
2083         }
2084     }
2085   e = ssa_redirect_edge (e, new_bb);
2086   return e;
2087 }
2088
2089 static bool mark_eh_edge_found_error;
2090
2091 /* Mark edge make_eh_edge would create for given region by setting it aux
2092    field, output error if something goes wrong.  */
2093
2094 static void
2095 mark_eh_edge (struct eh_region_d *region, void *data)
2096 {
2097   gimple stmt;
2098   tree lab;
2099   basic_block src, dst;
2100   edge e;
2101
2102   stmt = (gimple) data;
2103   lab = get_eh_region_tree_label (region);
2104
2105   src = gimple_bb (stmt);
2106   dst = label_to_block (lab);
2107
2108   e = find_edge (src, dst);
2109   if (!e)
2110     {
2111       error ("EH edge %i->%i is missing", src->index, dst->index);
2112       mark_eh_edge_found_error = true;
2113     }
2114   else if (!(e->flags & EDGE_EH))
2115     {
2116       error ("EH edge %i->%i miss EH flag", src->index, dst->index);
2117       mark_eh_edge_found_error = true;
2118     }
2119   else if (e->aux)
2120     {
2121       /* ??? might not be mistake.  */
2122       error ("EH edge %i->%i has duplicated regions", src->index, dst->index);
2123       mark_eh_edge_found_error = true;
2124     }
2125   else
2126     e->aux = (void *)1;
2127 }
2128
2129 /* Verify that BB containing STMT as the last statement, has precisely the
2130    edges that make_eh_edges would create.  */
2131
2132 bool
2133 verify_eh_edges (gimple stmt)
2134 {
2135   int region_nr;
2136   bool is_resx;
2137   basic_block bb = gimple_bb (stmt);
2138   edge_iterator ei;
2139   edge e;
2140   bool inlinable = false;
2141
2142   FOR_EACH_EDGE (e, ei, bb->succs)
2143     gcc_assert (!e->aux);
2144   mark_eh_edge_found_error = false;
2145   if (gimple_code (stmt) == GIMPLE_RESX)
2146     {
2147       region_nr = gimple_resx_region (stmt);
2148       is_resx = true;
2149     }
2150   else
2151     {
2152       region_nr = lookup_stmt_eh_region (stmt);
2153       if (region_nr < 0)
2154         {
2155           FOR_EACH_EDGE (e, ei, bb->succs)
2156             if (e->flags & EDGE_EH)
2157               {
2158                 error ("BB %i can not throw but has EH edges", bb->index);
2159                 return true;
2160               }
2161            return false;
2162         }
2163       if (!stmt_could_throw_p (stmt))
2164         {
2165           error ("BB %i last statement has incorrectly set region", bb->index);
2166           return true;
2167         }
2168       inlinable = inlinable_call_p (stmt);
2169       is_resx = false;
2170     }
2171
2172   foreach_reachable_handler (region_nr, is_resx, inlinable, mark_eh_edge, stmt);
2173   FOR_EACH_EDGE (e, ei, bb->succs)
2174     {
2175       if ((e->flags & EDGE_EH) && !e->aux)
2176         {
2177           error ("unnecessary EH edge %i->%i", bb->index, e->dest->index);
2178           mark_eh_edge_found_error = true;
2179           return true;
2180         }
2181       e->aux = NULL;
2182     }
2183
2184   return mark_eh_edge_found_error;
2185 }
2186
2187 \f
2188 /* Helper function for operation_could_trap_p and stmt_could_throw_p.  */
2189
2190 bool
2191 operation_could_trap_helper_p (enum tree_code op,
2192                                bool fp_operation,
2193                                bool honor_trapv,
2194                                bool honor_nans,
2195                                bool honor_snans,
2196                                tree divisor,
2197                                bool *handled)
2198 {
2199   *handled = true;
2200   switch (op)
2201     {
2202     case TRUNC_DIV_EXPR:
2203     case CEIL_DIV_EXPR:
2204     case FLOOR_DIV_EXPR:
2205     case ROUND_DIV_EXPR:
2206     case EXACT_DIV_EXPR:
2207     case CEIL_MOD_EXPR:
2208     case FLOOR_MOD_EXPR:
2209     case ROUND_MOD_EXPR:
2210     case TRUNC_MOD_EXPR:
2211     case RDIV_EXPR:
2212       if (honor_snans || honor_trapv)
2213         return true;
2214       if (fp_operation)
2215         return flag_trapping_math;
2216       if (!TREE_CONSTANT (divisor) || integer_zerop (divisor))
2217         return true;
2218       return false;
2219
2220     case LT_EXPR:
2221     case LE_EXPR:
2222     case GT_EXPR:
2223     case GE_EXPR:
2224     case LTGT_EXPR:
2225       /* Some floating point comparisons may trap.  */
2226       return honor_nans;
2227
2228     case EQ_EXPR:
2229     case NE_EXPR:
2230     case UNORDERED_EXPR:
2231     case ORDERED_EXPR:
2232     case UNLT_EXPR:
2233     case UNLE_EXPR:
2234     case UNGT_EXPR:
2235     case UNGE_EXPR:
2236     case UNEQ_EXPR:
2237       return honor_snans;
2238
2239     case CONVERT_EXPR:
2240     case FIX_TRUNC_EXPR:
2241       /* Conversion of floating point might trap.  */
2242       return honor_nans;
2243
2244     case NEGATE_EXPR:
2245     case ABS_EXPR:
2246     case CONJ_EXPR:
2247       /* These operations don't trap with floating point.  */
2248       if (honor_trapv)
2249         return true;
2250       return false;
2251
2252     case PLUS_EXPR:
2253     case MINUS_EXPR:
2254     case MULT_EXPR:
2255       /* Any floating arithmetic may trap.  */
2256       if (fp_operation && flag_trapping_math)
2257         return true;
2258       if (honor_trapv)
2259         return true;
2260       return false;
2261
2262     default:
2263       /* Any floating arithmetic may trap.  */
2264       if (fp_operation && flag_trapping_math)
2265         return true;
2266
2267       *handled = false;
2268       return false;
2269     }
2270 }
2271
2272 /* Return true if operation OP may trap.  FP_OPERATION is true if OP is applied
2273    on floating-point values.  HONOR_TRAPV is true if OP is applied on integer
2274    type operands that may trap.  If OP is a division operator, DIVISOR contains
2275    the value of the divisor.  */
2276
2277 bool
2278 operation_could_trap_p (enum tree_code op, bool fp_operation, bool honor_trapv,
2279                         tree divisor)
2280 {
2281   bool honor_nans = (fp_operation && flag_trapping_math
2282                      && !flag_finite_math_only);
2283   bool honor_snans = fp_operation && flag_signaling_nans != 0;
2284   bool handled;
2285
2286   if (TREE_CODE_CLASS (op) != tcc_comparison
2287       && TREE_CODE_CLASS (op) != tcc_unary
2288       && TREE_CODE_CLASS (op) != tcc_binary)
2289     return false;
2290
2291   return operation_could_trap_helper_p (op, fp_operation, honor_trapv,
2292                                         honor_nans, honor_snans, divisor,
2293                                         &handled);
2294 }
2295
2296 /* Return true if EXPR can trap, as in dereferencing an invalid pointer
2297    location or floating point arithmetic.  C.f. the rtl version, may_trap_p.
2298    This routine expects only GIMPLE lhs or rhs input.  */
2299
2300 bool
2301 tree_could_trap_p (tree expr)
2302 {
2303   enum tree_code code;
2304   bool fp_operation = false;
2305   bool honor_trapv = false;
2306   tree t, base, div = NULL_TREE;
2307
2308   if (!expr)
2309     return false;
2310  
2311   code = TREE_CODE (expr);
2312   t = TREE_TYPE (expr);
2313
2314   if (t)
2315     {
2316       if (COMPARISON_CLASS_P (expr))
2317         fp_operation = FLOAT_TYPE_P (TREE_TYPE (TREE_OPERAND (expr, 0)));
2318       else
2319         fp_operation = FLOAT_TYPE_P (t);
2320       honor_trapv = INTEGRAL_TYPE_P (t) && TYPE_OVERFLOW_TRAPS (t);
2321     }
2322
2323   if (TREE_CODE_CLASS (code) == tcc_binary)
2324     div = TREE_OPERAND (expr, 1);
2325   if (operation_could_trap_p (code, fp_operation, honor_trapv, div))
2326     return true;
2327
2328  restart:
2329   switch (code)
2330     {
2331     case TARGET_MEM_REF:
2332       /* For TARGET_MEM_REFs use the information based on the original
2333          reference.  */
2334       expr = TMR_ORIGINAL (expr);
2335       code = TREE_CODE (expr);
2336       goto restart;
2337
2338     case COMPONENT_REF:
2339     case REALPART_EXPR:
2340     case IMAGPART_EXPR:
2341     case BIT_FIELD_REF:
2342     case VIEW_CONVERT_EXPR:
2343     case WITH_SIZE_EXPR:
2344       expr = TREE_OPERAND (expr, 0);
2345       code = TREE_CODE (expr);
2346       goto restart;
2347
2348     case ARRAY_RANGE_REF:
2349       base = TREE_OPERAND (expr, 0);
2350       if (tree_could_trap_p (base))
2351         return true;
2352
2353       if (TREE_THIS_NOTRAP (expr))
2354         return false;
2355
2356       return !range_in_array_bounds_p (expr);
2357
2358     case ARRAY_REF:
2359       base = TREE_OPERAND (expr, 0);
2360       if (tree_could_trap_p (base))
2361         return true;
2362
2363       if (TREE_THIS_NOTRAP (expr))
2364         return false;
2365
2366       return !in_array_bounds_p (expr);
2367
2368     case INDIRECT_REF:
2369     case ALIGN_INDIRECT_REF:
2370     case MISALIGNED_INDIRECT_REF:
2371       return !TREE_THIS_NOTRAP (expr);
2372
2373     case ASM_EXPR:
2374       return TREE_THIS_VOLATILE (expr);
2375
2376
2377     case CALL_EXPR:
2378       t = get_callee_fndecl (expr);
2379       /* Assume that calls to weak functions may trap.  */
2380       if (!t || !DECL_P (t) || DECL_WEAK (t))
2381         return true;
2382       return false;
2383
2384     default:
2385       return false;
2386     }
2387 }
2388
2389
2390 /* Helper for stmt_could_throw_p.  Return true if STMT (assumed to be a
2391    an assignment or a conditional) may throw.  */
2392
2393 static bool
2394 stmt_could_throw_1_p (gimple stmt)
2395 {
2396   enum tree_code code = gimple_expr_code (stmt);
2397   bool honor_nans = false;
2398   bool honor_snans = false;
2399   bool fp_operation = false;
2400   bool honor_trapv = false;
2401   tree t;
2402   size_t i;
2403   bool handled, ret;
2404
2405   if (TREE_CODE_CLASS (code) == tcc_comparison
2406       || TREE_CODE_CLASS (code) == tcc_unary
2407       || TREE_CODE_CLASS (code) == tcc_binary)
2408     {
2409       t = gimple_expr_type (stmt);
2410       fp_operation = FLOAT_TYPE_P (t);
2411       if (fp_operation)
2412         {
2413           honor_nans = flag_trapping_math && !flag_finite_math_only;
2414           honor_snans = flag_signaling_nans != 0;
2415         }
2416       else if (INTEGRAL_TYPE_P (t) && TYPE_OVERFLOW_TRAPS (t))
2417         honor_trapv = true;
2418     }
2419
2420   /* Check if the main expression may trap.  */
2421   t = is_gimple_assign (stmt) ? gimple_assign_rhs2 (stmt) : NULL;
2422   ret = operation_could_trap_helper_p (code, fp_operation, honor_trapv,
2423                                        honor_nans, honor_snans, t,
2424                                        &handled);
2425   if (handled)
2426     return ret;
2427
2428   /* If the expression does not trap, see if any of the individual operands may
2429      trap.  */
2430   for (i = 0; i < gimple_num_ops (stmt); i++)
2431     if (tree_could_trap_p (gimple_op (stmt, i)))
2432       return true;
2433
2434   return false;
2435 }
2436
2437
2438 /* Return true if statement STMT could throw an exception.  */
2439
2440 bool
2441 stmt_could_throw_p (gimple stmt)
2442 {
2443   enum gimple_code code;
2444
2445   if (!flag_exceptions)
2446     return false;
2447
2448   /* The only statements that can throw an exception are assignments,
2449      conditionals, calls and asms.  */
2450   code = gimple_code (stmt);
2451   if (code != GIMPLE_ASSIGN
2452       && code != GIMPLE_COND
2453       && code != GIMPLE_CALL
2454       && code != GIMPLE_ASM)
2455     return false;
2456
2457   /* If exceptions can only be thrown by function calls and STMT is not a
2458      GIMPLE_CALL, the statement cannot throw.  */
2459   if (!flag_non_call_exceptions && code != GIMPLE_CALL)
2460     return false;
2461
2462   if (code == GIMPLE_ASSIGN || code == GIMPLE_COND)
2463     return stmt_could_throw_1_p (stmt);
2464   else if (is_gimple_call (stmt))
2465     return (gimple_call_flags (stmt) & ECF_NOTHROW) == 0;
2466   else if (gimple_code (stmt) == GIMPLE_ASM)
2467     return (gimple_asm_volatile_p (stmt));
2468   else
2469     gcc_unreachable ();
2470
2471   return false;
2472 }
2473
2474
2475 /* Return true if expression T could throw an exception.  */
2476
2477 bool
2478 tree_could_throw_p (tree t)
2479 {
2480   if (!flag_exceptions)
2481     return false;
2482   if (TREE_CODE (t) == MODIFY_EXPR)
2483     {
2484       if (flag_non_call_exceptions
2485           && tree_could_trap_p (TREE_OPERAND (t, 0)))
2486         return true;
2487       t = TREE_OPERAND (t, 1);
2488     }
2489
2490   if (TREE_CODE (t) == WITH_SIZE_EXPR)
2491     t = TREE_OPERAND (t, 0);
2492   if (TREE_CODE (t) == CALL_EXPR)
2493     return (call_expr_flags (t) & ECF_NOTHROW) == 0;
2494   if (flag_non_call_exceptions)
2495     return tree_could_trap_p (t);
2496   return false;
2497 }
2498
2499 /* Return true if STMT can throw an exception that is not caught within
2500    the current function (CFUN).  */
2501
2502 bool
2503 stmt_can_throw_external (gimple stmt)
2504 {
2505   int region_nr;
2506   bool is_resx = false;
2507   bool inlinable_call = false;
2508
2509   if (!stmt_could_throw_p (stmt))
2510     return false;
2511
2512   if (gimple_code (stmt) == GIMPLE_RESX)
2513     {
2514       region_nr = gimple_resx_region (stmt);
2515       is_resx = true;
2516     }
2517   else
2518     region_nr = lookup_stmt_eh_region (stmt);
2519
2520   if (region_nr < 0)
2521     return true;
2522
2523   return can_throw_external_1 (region_nr, is_resx, inlinable_call);
2524 }
2525
2526 /* Return true if STMT can throw an exception that is caught within
2527    the current function (CFUN).  */
2528
2529 bool
2530 stmt_can_throw_internal (gimple stmt)
2531 {
2532   int region_nr;
2533   bool is_resx = false;
2534   bool inlinable_call = false;
2535
2536   if (gimple_code (stmt) == GIMPLE_RESX)
2537     {
2538       region_nr = gimple_resx_region (stmt);
2539       is_resx = true;
2540     }
2541   else
2542     {
2543       region_nr = lookup_stmt_eh_region (stmt);
2544       inlinable_call = inlinable_call_p (stmt);
2545     }
2546
2547   if (region_nr < 0)
2548     return false;
2549
2550   return can_throw_internal_1 (region_nr, is_resx, inlinable_call);
2551 }
2552
2553
2554 /* Given a statement OLD_STMT and a new statement NEW_STMT that has replaced
2555    OLD_STMT in the function, remove OLD_STMT from the EH table and put NEW_STMT
2556    in the table if it should be in there.  Return TRUE if a replacement was
2557    done that my require an EH edge purge.  */
2558
2559 bool 
2560 maybe_clean_or_replace_eh_stmt (gimple old_stmt, gimple new_stmt) 
2561 {
2562   int region_nr = lookup_stmt_eh_region (old_stmt);
2563
2564   if (region_nr >= 0)
2565     {
2566       bool new_stmt_could_throw = stmt_could_throw_p (new_stmt);
2567
2568       if (new_stmt == old_stmt && new_stmt_could_throw)
2569         return false;
2570
2571       remove_stmt_from_eh_region (old_stmt);
2572       if (new_stmt_could_throw)
2573         {
2574           add_stmt_to_eh_region (new_stmt, region_nr);
2575           return false;
2576         }
2577       else
2578         return true;
2579     }
2580
2581   return false;
2582 }
2583 \f
2584 /* Returns TRUE if oneh and twoh are exception handlers (gimple_try_cleanup of
2585    GIMPLE_TRY) that are similar enough to be considered the same.  Currently
2586    this only handles handlers consisting of a single call, as that's the
2587    important case for C++: a destructor call for a particular object showing
2588    up in multiple handlers.  */
2589
2590 static bool
2591 same_handler_p (gimple_seq oneh, gimple_seq twoh)
2592 {
2593   gimple_stmt_iterator gsi;
2594   gimple ones, twos;
2595   unsigned int ai;
2596
2597   gsi = gsi_start (oneh);
2598   if (!gsi_one_before_end_p (gsi))
2599     return false;
2600   ones = gsi_stmt (gsi);
2601
2602   gsi = gsi_start (twoh);
2603   if (!gsi_one_before_end_p (gsi))
2604     return false;
2605   twos = gsi_stmt (gsi);
2606
2607   if (!is_gimple_call (ones)
2608       || !is_gimple_call (twos)
2609       || gimple_call_lhs (ones)
2610       || gimple_call_lhs (twos)
2611       || gimple_call_chain (ones)
2612       || gimple_call_chain (twos)
2613       || !operand_equal_p (gimple_call_fn (ones), gimple_call_fn (twos), 0)
2614       || gimple_call_num_args (ones) != gimple_call_num_args (twos))
2615     return false;
2616
2617   for (ai = 0; ai < gimple_call_num_args (ones); ++ai)
2618     if (!operand_equal_p (gimple_call_arg (ones, ai),
2619                           gimple_call_arg (twos, ai), 0))
2620       return false;
2621
2622   return true;
2623 }
2624
2625 /* Optimize
2626     try { A() } finally { try { ~B() } catch { ~A() } }
2627     try { ... } finally { ~A() }
2628    into
2629     try { A() } catch { ~B() }
2630     try { ~B() ... } finally { ~A() }
2631
2632    This occurs frequently in C++, where A is a local variable and B is a
2633    temporary used in the initializer for A.  */
2634
2635 static void
2636 optimize_double_finally (gimple one, gimple two)
2637 {
2638   gimple oneh;
2639   gimple_stmt_iterator gsi;
2640
2641   gsi = gsi_start (gimple_try_cleanup (one));
2642   if (!gsi_one_before_end_p (gsi))
2643     return;
2644
2645   oneh = gsi_stmt (gsi);
2646   if (gimple_code (oneh) != GIMPLE_TRY
2647       || gimple_try_kind (oneh) != GIMPLE_TRY_CATCH)
2648     return;
2649
2650   if (same_handler_p (gimple_try_cleanup (oneh), gimple_try_cleanup (two)))
2651     {
2652       gimple_seq seq = gimple_try_eval (oneh);
2653
2654       gimple_try_set_cleanup (one, seq);
2655       gimple_try_set_kind (one, GIMPLE_TRY_CATCH);
2656       seq = copy_gimple_seq_and_replace_locals (seq);
2657       gimple_seq_add_seq (&seq, gimple_try_eval (two));
2658       gimple_try_set_eval (two, seq);
2659     }
2660 }
2661
2662 /* Perform EH refactoring optimizations that are simpler to do when code
2663    flow has been lowered but EH structures haven't.  */
2664
2665 static void
2666 refactor_eh_r (gimple_seq seq)
2667 {
2668   gimple_stmt_iterator gsi;
2669   gimple one, two;
2670
2671   one = NULL;
2672   two = NULL;
2673   gsi = gsi_start (seq);
2674   while (1)
2675     {
2676       one = two;
2677       if (gsi_end_p (gsi))
2678         two = NULL;
2679       else
2680         two = gsi_stmt (gsi);
2681       if (one
2682           && two
2683           && gimple_code (one) == GIMPLE_TRY
2684           && gimple_code (two) == GIMPLE_TRY
2685           && gimple_try_kind (one) == GIMPLE_TRY_FINALLY
2686           && gimple_try_kind (two) == GIMPLE_TRY_FINALLY)
2687         optimize_double_finally (one, two);
2688       if (one)
2689         switch (gimple_code (one))
2690           {
2691           case GIMPLE_TRY:
2692             refactor_eh_r (gimple_try_eval (one));
2693             refactor_eh_r (gimple_try_cleanup (one));
2694             break;
2695           case GIMPLE_CATCH:
2696             refactor_eh_r (gimple_catch_handler (one));
2697             break;
2698           case GIMPLE_EH_FILTER:
2699             refactor_eh_r (gimple_eh_filter_failure (one));
2700             break;
2701           default:
2702             break;
2703           }
2704       if (two)
2705         gsi_next (&gsi);
2706       else
2707         break;
2708     }
2709 }
2710
2711 static unsigned
2712 refactor_eh (void)
2713 {
2714   refactor_eh_r (gimple_body (current_function_decl));
2715   return 0;
2716 }
2717
2718 struct gimple_opt_pass pass_refactor_eh =
2719 {
2720  {
2721   GIMPLE_PASS,
2722   "ehopt",                              /* name */
2723   NULL,                                 /* gate */
2724   refactor_eh,                          /* execute */
2725   NULL,                                 /* sub */
2726   NULL,                                 /* next */
2727   0,                                    /* static_pass_number */
2728   TV_TREE_EH,                           /* tv_id */
2729   PROP_gimple_lcf,                      /* properties_required */
2730   0,                                    /* properties_provided */
2731   0,                                    /* properties_destroyed */
2732   0,                                    /* todo_flags_start */
2733   TODO_dump_func                        /* todo_flags_finish */
2734  }
2735 };
2736
2737 /* Walk statements, see what regions are really references and remove unreachable ones.  */
2738
2739 static void
2740 tree_remove_unreachable_handlers (void)
2741 {
2742   sbitmap reachable, contains_stmt;
2743   VEC(int,heap) * label_to_region;
2744   basic_block bb;
2745
2746   label_to_region = label_to_region_map ();
2747   reachable = sbitmap_alloc (num_eh_regions ());
2748   sbitmap_zero (reachable);
2749   contains_stmt = sbitmap_alloc (num_eh_regions ());
2750   sbitmap_zero (contains_stmt);
2751
2752   FOR_EACH_BB (bb)
2753   {
2754     gimple_stmt_iterator gsi;
2755     int region;
2756     bool has_eh_preds = bb_has_eh_pred (bb);
2757
2758     for (gsi = gsi_start_bb (bb); !gsi_end_p (gsi); gsi_next (&gsi))
2759       {
2760         gimple stmt = gsi_stmt (gsi);
2761
2762         if (gimple_code (stmt) == GIMPLE_LABEL && has_eh_preds)
2763           {
2764             int uid = LABEL_DECL_UID (gimple_label_label (stmt));
2765             int region;
2766
2767             for (region = VEC_index (int, label_to_region, uid);
2768                  region; region = get_next_region_sharing_label (region))
2769               SET_BIT (reachable, region);
2770           }
2771         if (gimple_code (stmt) == GIMPLE_RESX)
2772           SET_BIT (reachable,
2773                    VEC_index (eh_region, cfun->eh->region_array,
2774                               gimple_resx_region (stmt))->region_number);
2775         if ((region = lookup_stmt_eh_region (stmt)) >= 0)
2776           SET_BIT (contains_stmt, region);
2777       }
2778   }
2779
2780   if (dump_file)
2781     {
2782       fprintf (dump_file, "Before removal of unreachable regions:\n");
2783       dump_eh_tree (dump_file, cfun);
2784       fprintf (dump_file, "Reachable regions: ");
2785       dump_sbitmap_file (dump_file, reachable);
2786       fprintf (dump_file, "Regions containing insns: ");
2787       dump_sbitmap_file (dump_file, contains_stmt);
2788     }
2789
2790   remove_unreachable_regions (reachable, contains_stmt);
2791   sbitmap_free (reachable);
2792   sbitmap_free (contains_stmt);
2793   VEC_free (int, heap, label_to_region);
2794   if (dump_file)
2795     {
2796       fprintf (dump_file, "\n\nAfter removal of unreachable regions:\n");
2797       dump_eh_tree (dump_file, cfun);
2798       fprintf (dump_file, "\n\n");
2799     }
2800 }
2801
2802 /* Pattern match emtpy EH receiver looking like:
2803   
2804    save_filt.6352_662 = [filter_expr] <<<filter object>>>;
2805    save_eptr.6351_663 = [exc_ptr_expr] <<<exception object>>>;
2806    <<<exception object>>> = save_eptr.6351_663;
2807    <<<filter object>>> = save_filt.6352_662;
2808    resx 1
2809
2810    And various minor variants after DCE or copy propagation.
2811  */
2812
2813 static int
2814 tree_empty_eh_handler_p (basic_block bb)
2815 {
2816   gimple_stmt_iterator gsi;
2817   int region;
2818   edge_iterator ei;
2819   edge e;
2820   use_operand_p imm_use;
2821   gimple use_stmt;
2822   bool found = false;
2823
2824   gsi = gsi_last_bb (bb);
2825
2826   /* RESX  */
2827   if (gsi_end_p (gsi))
2828     return 0;
2829   if (gimple_code (gsi_stmt (gsi)) != GIMPLE_RESX)
2830     return 0;
2831   region = gimple_resx_region (gsi_stmt (gsi));
2832
2833   /* filter_object set.  */
2834   gsi_prev_nondebug (&gsi);
2835   if (gsi_end_p (gsi))
2836     return 0;
2837   if (gimple_code (gsi_stmt (gsi)) == GIMPLE_ASSIGN)
2838     {
2839       tree filter_tmp;
2840       tree exc_ptr_tmp;
2841
2842       if (TREE_CODE (gimple_assign_lhs (gsi_stmt (gsi))) != FILTER_EXPR)
2843         return 0;
2844       filter_tmp = gimple_assign_rhs1 (gsi_stmt (gsi));
2845
2846       /* filter_object set.  */
2847       gsi_prev_nondebug (&gsi);
2848       if (gsi_end_p (gsi))
2849         return 0;
2850       if (gimple_code (gsi_stmt (gsi)) != GIMPLE_ASSIGN)
2851         return 0;
2852       if (TREE_CODE (gimple_assign_lhs (gsi_stmt (gsi))) != EXC_PTR_EXPR)
2853         return 0;
2854       exc_ptr_tmp = gimple_assign_rhs1 (gsi_stmt (gsi));
2855
2856       /* exc_ptr get.  */
2857       if (TREE_CODE (exc_ptr_tmp) != EXC_PTR_EXPR)
2858         {
2859           gsi_prev_nondebug (&gsi);
2860           if (gsi_end_p (gsi))
2861             return 0;
2862           if (gimple_code (gsi_stmt (gsi)) != GIMPLE_ASSIGN)
2863             return 0;
2864           if (TREE_CODE (gimple_assign_rhs1 (gsi_stmt (gsi))) != EXC_PTR_EXPR)
2865             return 0;
2866           if (exc_ptr_tmp != gimple_assign_lhs (gsi_stmt (gsi)))
2867             return 0;
2868           if (!single_imm_use (exc_ptr_tmp, &imm_use, &use_stmt))
2869             return 0;
2870         }
2871
2872       /* filter_object get.  */
2873       if (TREE_CODE (filter_tmp) != FILTER_EXPR)
2874         {
2875           gsi_prev_nondebug (&gsi);
2876           if (gsi_end_p (gsi))
2877             return 0;
2878           if (gimple_code (gsi_stmt (gsi)) != GIMPLE_ASSIGN)
2879             return 0;
2880           if (TREE_CODE (gimple_assign_rhs1 (gsi_stmt (gsi))) != FILTER_EXPR)
2881             return 0;
2882           if (filter_tmp != gimple_assign_lhs (gsi_stmt (gsi)))
2883             return 0;
2884           if (!single_imm_use (filter_tmp, &imm_use, &use_stmt))
2885             return 0;
2886         }
2887
2888       /* label.  */
2889       gsi_prev_nondebug (&gsi);
2890       if (gsi_end_p (gsi))
2891         return 0;
2892     }
2893   if (gimple_code (gsi_stmt (gsi)) != GIMPLE_LABEL)
2894     return 0;
2895
2896   /* Be sure that there is at least on EH region reaching the block directly.
2897      After EH edge redirection, it is possible that block is reached by one handler
2898      but resumed by different.  */
2899   FOR_EACH_EDGE (e, ei, bb->preds)
2900     if ((e->flags & EDGE_EH))
2901       found = true;
2902   if (found)
2903     return region;
2904   return 0;
2905 }
2906
2907 /* Return true if it is possible to remove basic block BB and propagate
2908    through PHIs.  
2909
2910    This means that every PHI in BB has all uses such that they are PHIs
2911    of basic blocks reachable througt BB and they appears only in use
2912    reachable by the edge from BB to the block contianing the use.  
2913    
2914    This is same as in merge-phi code, but in slightly more general setting
2915    because BB can have multiple successors.  */
2916
2917 static bool
2918 all_phis_safe_to_merge (basic_block bb)
2919 {
2920   gimple_stmt_iterator si;
2921   bool ok = true;
2922
2923   for (si = gsi_start_phis (bb); !gsi_end_p (si); gsi_next (&si))
2924     {
2925       gimple phi = gsi_stmt (si);
2926       tree result = gimple_phi_result (phi);
2927       gimple stmt;
2928       use_operand_p imm_use;
2929       imm_use_iterator imm_iter;
2930
2931       /* If the PHI's result is never used, then we can just
2932          ignore it.  */
2933       if (has_zero_uses (result))
2934         continue;
2935       /* We can always rebuild virtuals if needed.  */
2936       if (!is_gimple_reg (result))
2937         continue;
2938       FOR_EACH_IMM_USE_STMT (stmt, imm_iter, result)
2939         {
2940           if (gimple_code (stmt) != GIMPLE_PHI)
2941             {
2942               if (dump_file && (dump_flags & TDF_DETAILS))
2943                 fprintf (dump_file,
2944                          "PHI result has use in non-PHI statement.\n");
2945               ok = false;
2946               BREAK_FROM_IMM_USE_STMT (imm_iter);
2947             }
2948           else
2949             FOR_EACH_IMM_USE_ON_STMT (imm_use, imm_iter)
2950               {
2951                edge e;
2952                e = gimple_phi_arg_edge (stmt, PHI_ARG_INDEX_FROM_USE (imm_use));
2953                if (e->src != bb)
2954                  {
2955                   if (dump_file && (dump_flags & TDF_DETAILS))
2956                     fprintf (dump_file, "PHI has use in PHI not reached from"
2957                              "empty cleanup itself.\n");
2958                   ok = false;
2959                   break;
2960                  }
2961               }
2962            if (!ok)
2963              BREAK_FROM_IMM_USE_STMT (imm_iter);
2964          }
2965        if (!ok)
2966          return false;
2967     }
2968   return ok;
2969 }
2970
2971 static bool dominance_info_invalidated;
2972
2973 /* Information to pass into make_eh_edge_and_update_phi.  */
2974
2975 struct update_info
2976 {
2977   basic_block bb_to_remove, bb;
2978   edge edge_to_remove;
2979 };
2980
2981 /* DATA points to update-info structure.
2982    Like make_eh_edge create EH edge from DATA->bb to basic block containing
2983    handler of REGION.  In addition also update PHI operands by copying
2984    operands from DATA->bb_to_remove.  */
2985
2986 static void
2987 make_eh_edge_and_update_phi (struct eh_region_d *region, void *data)
2988 {
2989   struct update_info *info = (struct update_info *) data;
2990   edge e, e2;
2991   tree lab;
2992   basic_block src, dst;
2993   gimple_stmt_iterator si;
2994
2995   lab = get_eh_region_tree_label (region);
2996
2997   src = info->bb;
2998   dst = label_to_block (lab);
2999
3000   e = find_edge (src, dst);
3001   if (e)
3002     {
3003       gcc_assert (e->flags & EDGE_EH);
3004       e->aux = e;
3005       return;
3006     }
3007   dominance_info_invalidated = true;
3008   e2 = find_edge (info->bb_to_remove, dst);
3009   e = make_edge (src, dst, EDGE_EH);
3010   e->aux = e;
3011   gcc_assert (e2);
3012   for (si = gsi_start_phis (dst); !gsi_end_p (si); gsi_next (&si))
3013     {
3014       gimple phi = gsi_stmt (si);
3015       tree use = USE_FROM_PTR (PHI_ARG_DEF_PTR_FROM_EDGE (phi, e2));
3016       gimple def = (TREE_CODE (use) == SSA_NAME
3017                     ? SSA_NAME_DEF_STMT (use) : NULL);
3018
3019       if (def && gimple_bb (def) == info->bb_to_remove)
3020         {
3021           use = USE_FROM_PTR (PHI_ARG_DEF_PTR_FROM_EDGE (def,
3022                                                          info->edge_to_remove));
3023           gcc_assert (info->bb_to_remove == info->edge_to_remove->dest);
3024           def = TREE_CODE (use) == SSA_NAME ? SSA_NAME_DEF_STMT (use) : NULL;
3025           gcc_assert (!def
3026                       || gimple_bb (def) != info->bb_to_remove
3027                       || !is_gimple_reg (use));
3028         }
3029       SET_USE (PHI_ARG_DEF_PTR_FROM_EDGE (phi, e), use);
3030     }
3031 }
3032
3033 /* Make EH edges corresponding to STMT while updating PHI nodes after removal
3034    empty cleanup BB_TO_REMOVE joined to BB containing STMT
3035    by EDGE_TO_REMOVE.
3036
3037    Return if EDGE_TO_REMOVE was really removed.  It might stay reachable when
3038    not all EH regions are cleaned up.  */
3039
3040 static bool
3041 update_eh_edges (gimple stmt, basic_block bb_to_remove, edge edge_to_remove)
3042 {
3043   int region_nr;
3044   bool is_resx;
3045   bool inlinable = false;
3046   struct update_info info;
3047   edge_iterator ei;
3048   edge e;
3049   int probability_sum = 0;
3050   bool removed = false;
3051
3052   info.bb_to_remove = bb_to_remove;
3053   info.bb = gimple_bb (stmt);
3054   info.edge_to_remove = edge_to_remove;
3055
3056   if (gimple_code (stmt) == GIMPLE_RESX)
3057     {
3058       region_nr = gimple_resx_region (stmt);
3059       is_resx = true;
3060     }
3061   else
3062     {
3063       region_nr = lookup_stmt_eh_region (stmt);
3064       is_resx = false;
3065       inlinable = inlinable_call_p (stmt);
3066     }
3067
3068   /* First add new edges as neccesary.  */
3069   foreach_reachable_handler (region_nr, is_resx, inlinable,
3070                              make_eh_edge_and_update_phi, &info);
3071
3072   /* And remove edges we didn't marked. */
3073   for (ei = ei_start (info.bb->succs); (e = ei_safe_edge (ei)); )
3074     {
3075       if ((e->flags & EDGE_EH) && !e->aux)
3076         {
3077           dominance_info_invalidated = true;
3078           if (e == edge_to_remove)
3079             removed = true;
3080           remove_edge (e);
3081         }
3082       else
3083         {
3084           e->aux = NULL;
3085           probability_sum += e->probability;
3086           ei_next (&ei);
3087         }
3088     }
3089
3090   /* Make CFG profile more consistent assuming that exception will resume to
3091      first available EH handler.  In practice this makes little difference, but
3092      we get fewer consistency errors in the dumps.  */
3093   if (is_resx && EDGE_COUNT (info.bb->succs) && !probability_sum)
3094     EDGE_SUCC (info.bb, 0)->probability = REG_BR_PROB_BASE;
3095   return removed;
3096 }
3097
3098 /* Look for basic blocks containing empty exception handler and remove them.
3099    This is similar to jump forwarding, just across EH edges.  */
3100
3101 static bool
3102 cleanup_empty_eh (basic_block bb, VEC(int,heap) * label_to_region)
3103 {
3104   int region;
3105   gimple_stmt_iterator si;
3106   edge_iterator ei;
3107
3108   /* When handler of EH region winds up to be empty, we can safely
3109      remove it.  This leads to inner EH regions to be redirected
3110      to outer one, if present in function. So we need to rebuild
3111      EH edges in all sources.   */
3112   if ((region = tree_empty_eh_handler_p (bb))
3113       && all_phis_safe_to_merge (bb))
3114     {
3115       edge e;
3116       bool found = false, removed_some = false, has_non_eh_preds = false;
3117       gimple_stmt_iterator gsi;
3118
3119       /* Look for all EH regions sharing label of this block.
3120          If they are not same as REGION, remove them and replace them
3121          by outer region of REGION.  Also note if REGION itself is one
3122          of them.  */
3123
3124       for (gsi = gsi_start_bb (bb); !gsi_end_p (gsi); gsi_next (&gsi))
3125         if (gimple_code (gsi_stmt (gsi)) == GIMPLE_LABEL)
3126           {
3127             int uid = LABEL_DECL_UID (gimple_label_label (gsi_stmt (gsi)));
3128             int r = VEC_index (int, label_to_region, uid);
3129             int next;
3130
3131             while (r)
3132               {
3133                 next = get_next_region_sharing_label (r);
3134                 if (r == region)
3135                   found = true;
3136                 else
3137                   {
3138                      removed_some = true;
3139                      remove_eh_region_and_replace_by_outer_of (r, region);
3140                      if (dump_file && (dump_flags & TDF_DETAILS))
3141                        fprintf (dump_file, "Empty EH handler %i removed and "
3142                                 "replaced by %i\n", r, region);
3143                   }
3144                 r = next;
3145               }
3146           }
3147         else
3148           break;
3149
3150       gcc_assert (found || removed_some);
3151       FOR_EACH_EDGE (e, ei, bb->preds)
3152         if (!(e->flags & EDGE_EH))
3153           has_non_eh_preds = true;
3154
3155       /* When block is empty EH cleanup, but it is reachable via non-EH code too,
3156          we can not remove the region it is resumed via, because doing so will
3157          lead to redirection of its RESX edges.
3158
3159          This case will be handled later after edge forwarding if the EH cleanup
3160          is really dead.  */
3161
3162       if (found && !has_non_eh_preds)
3163         {
3164            if (dump_file && (dump_flags & TDF_DETAILS))
3165              fprintf (dump_file, "Empty EH handler %i removed.\n", region);
3166           remove_eh_region (region);
3167         }
3168       else if (!removed_some)
3169         return false;
3170
3171       for (ei = ei_start (bb->preds); (e = ei_safe_edge (ei)); )
3172         {
3173           basic_block src = e->src;
3174           if (!(e->flags & EDGE_EH))
3175             {
3176               ei_next (&ei);
3177               continue;
3178             }
3179           if (stmt_can_throw_internal (last_stmt (src)))
3180             {
3181               if (!update_eh_edges (last_stmt (src), bb, e))
3182                 ei_next (&ei);
3183             }
3184           else
3185             remove_edge (e);
3186         }
3187
3188       /* Verify that we eliminated all uses of PHI we are going to remove.
3189          If we didn't, rebuild SSA on affected variable (this is allowed only
3190          for virtuals).  */
3191       for (si = gsi_start_phis (bb); !gsi_end_p (si); gsi_next (&si))
3192         {
3193           gimple phi = gsi_stmt (si);
3194           tree result = gimple_phi_result (phi);
3195           if (!has_zero_uses (result))
3196             {
3197               use_operand_p use_p;
3198               imm_use_iterator iter;
3199               gimple stmt;
3200
3201               FOR_EACH_IMM_USE_STMT (stmt, iter, result)
3202                 {
3203                   /* We have use, see if it won't disappear after
3204                      removing BB.  */
3205                   if (gimple_bb (stmt) == bb)
3206                     continue;
3207                   if (gimple_code (stmt) == GIMPLE_PHI)
3208                     {
3209                       bool bad = false;
3210
3211                       FOR_EACH_IMM_USE_ON_STMT (use_p, iter)
3212                         if (gimple_phi_arg_edge (stmt,
3213                                 PHI_ARG_INDEX_FROM_USE (use_p))->src != bb)
3214                           {
3215                             bad = true;
3216                             break;
3217                           }
3218
3219                       if (!bad)
3220                         continue;
3221                     }
3222
3223                   gcc_assert (!is_gimple_reg (result));
3224                   mark_sym_for_renaming (SSA_NAME_VAR (result));
3225                   /* As we are going to delete this block we will release all
3226                      defs which makes the immediate uses on use stmts invalid.
3227                      Avoid that by replacing all uses with the bare variable
3228                      and updating the stmts.  */
3229                   FOR_EACH_IMM_USE_ON_STMT (use_p, iter)
3230                     SET_USE (use_p, SSA_NAME_VAR (result));
3231                   update_stmt (stmt);
3232                 }
3233             }
3234         }
3235       if (!ei_safe_edge (ei_start (bb->preds)))
3236         delete_basic_block (bb);
3237       return true;
3238     }
3239   return false;
3240 }
3241
3242
3243 /* Perform cleanups and lowering of exception handling
3244     1) cleanups regions with handlers doing nothing are optimized out
3245     2) MUST_NOT_THROW regions that became dead because of 1) are optimized out
3246     3) Info about regions that are containing instructions, and regions
3247        reachable via local EH edges is collected
3248     4) Eh tree is pruned for regions no longer neccesary.
3249  */
3250
3251 static unsigned int
3252 cleanup_eh (void)
3253 {
3254   bool changed = false;
3255   basic_block bb;
3256   VEC(int,heap) * label_to_region;
3257   int i;
3258
3259   if (!cfun->eh)
3260     return 0;
3261   if (dump_file)
3262     {
3263       fprintf (dump_file, "Before cleanups:\n");
3264       dump_eh_tree (dump_file, cfun);
3265     }
3266
3267   if (optimize)
3268     {
3269       label_to_region = label_to_region_map ();
3270       dominance_info_invalidated = false;
3271       /* We cannot use FOR_EACH_BB, since the basic blocks may get removed.  */
3272       for (i = NUM_FIXED_BLOCKS; i < last_basic_block; i++)
3273         {
3274           bb = BASIC_BLOCK (i);
3275           if (bb)
3276             changed |= cleanup_empty_eh (bb, label_to_region);
3277         }
3278       VEC_free (int, heap, label_to_region);
3279       if (dominance_info_invalidated)
3280         {
3281           free_dominance_info (CDI_DOMINATORS);
3282           free_dominance_info (CDI_POST_DOMINATORS);
3283         }
3284
3285       /* Removing contained cleanup can render MUST_NOT_THROW regions empty.  */
3286       if (changed)
3287         delete_unreachable_blocks ();
3288     }
3289
3290   tree_remove_unreachable_handlers ();
3291   if (dump_file)
3292     {
3293       fprintf (dump_file, "After cleanups:\n");
3294       dump_eh_tree (dump_file, cfun);
3295     }
3296
3297   return (changed ? TODO_cleanup_cfg | TODO_update_ssa : 0);
3298 }
3299
3300 struct gimple_opt_pass pass_cleanup_eh = {
3301   {
3302    GIMPLE_PASS,
3303    "ehcleanup",                 /* name */
3304    NULL,                        /* gate */
3305    cleanup_eh,                  /* execute */
3306    NULL,                        /* sub */
3307    NULL,                        /* next */
3308    0,                           /* static_pass_number */
3309    TV_TREE_EH,                  /* tv_id */
3310    PROP_gimple_lcf,             /* properties_required */
3311    0,                           /* properties_provided */
3312    0,                           /* properties_destroyed */
3313    0,                           /* todo_flags_start */
3314    TODO_dump_func               /* todo_flags_finish */
3315    }
3316 };