OSDN Git Service

* config/arm/lib1funcs.asm (ARM_FUNC_ALIAS): Also alias _L__name.
[pf3gnuchains/gcc-fork.git] / gcc / tree-eh.c
1 /* Exception handling semantics and decomposition for trees.
2    Copyright (C) 2003 Free Software Foundation, Inc.
3
4 This file is part of GCC.
5
6 GCC is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 2, or (at your option)
9 any later version.
10
11 GCC is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14 GNU General Public License for more details.
15
16 You should have received a copy of the GNU General Public License
17 along with GCC; see the file COPYING.  If not, write to
18 the Free Software Foundation, 59 Temple Place - Suite 330,
19 Boston, MA 02111-1307, USA.  */
20
21 #include "config.h"
22 #include "system.h"
23 #include "coretypes.h"
24 #include "tm.h"
25 #include "tree.h"
26 #include "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
40 \f
41 /* Nonzero if we are using EH to handle cleanups.  */
42 static int using_eh_for_cleanups_p = 0;
43
44 void
45 using_eh_for_cleanups (void)
46 {
47   using_eh_for_cleanups_p = 1;
48 }
49 \f
50 /* Misc functions used in this file.  */
51
52 /* Compare and hash for any structure which begins with a canonical
53    pointer.  Assumes all pointers are interchangable, which is sort
54    of already assumed by gcc elsewhere IIRC.  */
55
56 static int
57 struct_ptr_eq (const void *a, const void *b)
58 {
59   const void * const * x = a;
60   const void * const * y = b;
61   return *x == *y;
62 }
63
64 static hashval_t
65 struct_ptr_hash (const void *a)
66 {
67   const void * const * x = a;
68   return (size_t)*x >> 4;
69 }
70
71 \f
72 /* Remember and lookup EH region data for arbitrary statements.
73    Really this means any statement that could_throw_p.  We could
74    stuff this information into the stmt_ann data structure, but:
75
76    (1) We absolutely rely on this information being kept until
77    we get to rtl.  Once we're done with lowering here, if we lose
78    the information there's no way to recover it!
79
80    (2) There are many more statements that *cannot* throw as 
81    compared to those that can.  We should be saving some amount
82    of space by only allocating memory for those that can throw.  */
83
84 struct throw_stmt_node GTY(())
85 {
86   tree stmt;
87   int region_nr;
88 };
89
90 static GTY((param_is (struct throw_stmt_node))) htab_t throw_stmt_table;
91
92 static void
93 record_stmt_eh_region (struct eh_region *region, tree t)
94 {
95   struct throw_stmt_node *n;
96   void **slot;
97
98   if (!region)
99     return;
100
101   n = ggc_alloc (sizeof (*n));
102   n->stmt = t;
103   n->region_nr = get_eh_region_number (region);
104
105   slot = htab_find_slot (throw_stmt_table, n, INSERT);
106   if (*slot)
107     abort ();
108   *slot = n;
109 }
110
111 void
112 add_stmt_to_eh_region (tree t, int num)
113 {
114   struct throw_stmt_node *n;
115   void **slot;
116
117   if (num < 0)
118     abort ();
119
120   n = ggc_alloc (sizeof (*n));
121   n->stmt = t;
122   n->region_nr = num;
123
124   slot = htab_find_slot (throw_stmt_table, n, INSERT);
125   if (*slot)
126     abort ();
127   *slot = n;
128 }
129
130 bool
131 remove_stmt_from_eh_region (tree t)
132 {
133   struct throw_stmt_node dummy;
134   void **slot;
135
136   if (!throw_stmt_table)
137     return false;
138
139   dummy.stmt = t;
140   slot = htab_find_slot (throw_stmt_table, &dummy, NO_INSERT);
141   if (slot)
142     {
143       htab_clear_slot (throw_stmt_table, slot);
144       return true;
145     }
146   else
147     return false;
148 }
149
150 int
151 lookup_stmt_eh_region (tree t)
152 {
153   struct throw_stmt_node *p, n;
154
155   if (!throw_stmt_table)
156     return -2;
157
158   n.stmt = t;
159   p = htab_find (throw_stmt_table, &n);
160
161   return (p ? p->region_nr : -1);
162 }
163
164
165 \f
166 /* First pass of EH node decomposition.  Build up a tree of TRY_FINALLY_EXPR
167    nodes and LABEL_DECL nodes.  We will use this during the second phase to
168    determine if a goto leaves the body of a TRY_FINALLY_EXPR node.  */
169
170 struct finally_tree_node
171 {
172   tree child, parent;
173 };
174
175 /* Note that this table is *not* marked GTY.  It is short-lived.  */
176 static htab_t finally_tree;
177
178 static void
179 record_in_finally_tree (tree child, tree parent)
180 {
181   struct finally_tree_node *n;
182   void **slot;
183
184   n = xmalloc (sizeof (*n));
185   n->child = child;
186   n->parent = parent;
187
188   slot = htab_find_slot (finally_tree, n, INSERT);
189   if (*slot)
190     abort ();
191   *slot = n;
192 }
193
194 static void
195 collect_finally_tree (tree t, tree region)
196 {
197  tailrecurse:
198   switch (TREE_CODE (t))
199     {
200     case LABEL_EXPR:
201       record_in_finally_tree (LABEL_EXPR_LABEL (t), region);
202       break;
203
204     case TRY_FINALLY_EXPR:
205       record_in_finally_tree (t, region);
206       collect_finally_tree (TREE_OPERAND (t, 0), t);
207       t = TREE_OPERAND (t, 1);
208       goto tailrecurse;
209
210     case TRY_CATCH_EXPR:
211       collect_finally_tree (TREE_OPERAND (t, 0), region);
212       t = TREE_OPERAND (t, 1);
213       goto tailrecurse;
214
215     case CATCH_EXPR:
216       t = CATCH_BODY (t);
217       goto tailrecurse;
218
219     case EH_FILTER_EXPR:
220       t = EH_FILTER_FAILURE (t);
221       goto tailrecurse;
222
223     case STATEMENT_LIST:
224       {
225         tree_stmt_iterator i;
226         for (i = tsi_start (t); !tsi_end_p (i); tsi_next (&i))
227           collect_finally_tree (tsi_stmt (i), region);
228       }
229       break;
230
231     default:
232       /* A type, a decl, or some kind of statement that we're not
233          interested in.  Don't walk them.  */
234       break;
235     }
236 }
237
238 /* Use the finally tree to determine if a jump from START to TARGET
239    would leave the try_finally node that START lives in.  */
240
241 static bool
242 outside_finally_tree (tree start, tree target)
243 {
244   struct finally_tree_node n, *p;
245
246   do
247     {
248       n.child = start;
249       p = htab_find (finally_tree, &n);
250       if (!p)
251         return true;
252       start = p->parent;
253     }
254   while (start != target);
255
256   return false;
257 }
258 \f
259 /* Second pass of EH node decomposition.  Actually transform the TRY_FINALLY
260    and TRY_CATCH nodes into a set of gotos, magic labels, and eh regions.
261    The eh region creation is straight-forward, but frobbing all the gotos
262    and such into shape isn't.  */
263
264 /* State of the world while lowering.  */
265
266 struct leh_state
267 {
268   /* What's "current" while constructing the eh region tree.  These 
269      correspond to variables of the same name in cfun->eh, which we
270      don't have easy access to.  */
271   struct eh_region *cur_region;
272   struct eh_region *prev_try;
273
274   /* Processing of TRY_FINALLY requires a bit more state.  This is
275      split out into a separate structure so that we don't have to
276      copy so much when processing other nodes.  */
277   struct leh_tf_state *tf;
278 };
279
280 struct leh_tf_state
281 {
282   /* Pointer to the TRY_FINALLY node under discussion.  The try_finally_expr
283      is the original TRY_FINALLY_EXPR.  We need to retain this so that 
284      outside_finally_tree can reliably reference the tree used in the
285      collect_finally_tree data structures.  */
286   tree try_finally_expr;
287   tree *top_p;
288
289   /* The state outside this try_finally node.  */
290   struct leh_state *outer;
291
292   /* The exception region created for it.  */
293   struct eh_region *region;
294
295   /* The GOTO_QUEUE is is an array of GOTO_EXPR and RETURN_EXPR statements
296      that are seen to escape this TRY_FINALLY_EXPR node.  */
297   struct goto_queue_node {
298     tree stmt;
299     tree repl_stmt;
300     tree cont_stmt;
301     int index;
302   } *goto_queue;
303   size_t goto_queue_size;
304   size_t goto_queue_active;
305
306   /* The set of unique labels seen as entries in the goto queue.  */
307   varray_type dest_array;
308
309   /* A label to be added at the end of the completed transformed
310      sequence.  It will be set if may_fallthru was true *at one time*,
311      though subsequent transformations may have cleared that flag.  */
312   tree fallthru_label;
313
314   /* A label that has been registered with except.c to be the 
315      landing pad for this try block.  */
316   tree eh_label;
317
318   /* True if it is possible to fall out the bottom of the try block.
319      Cleared if the fallthru is converted to a goto.  */
320   bool may_fallthru;
321
322   /* True if any entry in goto_queue is a RETURN_EXPR.  */
323   bool may_return;
324
325   /* True if the finally block can receive an exception edge.
326      Cleared if the exception case is handled by code duplication.  */
327   bool may_throw;
328 };
329
330 static void lower_eh_filter (struct leh_state *, tree *);
331 static void lower_eh_constructs_1 (struct leh_state *, tree *);
332
333 /* Comparison function for qsort/bsearch.  We're interested in 
334    searching goto queue elements for source statements.  */
335
336 static int
337 goto_queue_cmp (const void *x, const void *y)
338 {
339   tree a = ((const struct goto_queue_node *)x)->stmt;
340   tree b = ((const struct goto_queue_node *)y)->stmt;
341   return (a == b ? 0 : a < b ? -1 : 1);
342 }
343
344 /* Search for STMT in the goto queue.  Return the replacement,
345    or null if the statement isn't in the queue.  */
346
347 static tree
348 find_goto_replacement (struct leh_tf_state *tf, tree stmt)
349 {
350   struct goto_queue_node tmp, *ret;
351   tmp.stmt = stmt;
352   ret = bsearch (&tmp, tf->goto_queue, tf->goto_queue_active,
353                  sizeof (struct goto_queue_node), goto_queue_cmp);
354   return (ret ? ret->repl_stmt : NULL);
355 }
356
357 /* A subroutine of replace_goto_queue_1.  Handles the sub-clauses of a
358    lowered COND_EXPR.  If, by chance, the replacement is a simple goto,
359    then we can just splat it in, otherwise we add the new stmts immediately
360    after the COND_EXPR and redirect.  */
361
362 static void
363 replace_goto_queue_cond_clause (tree *tp, struct leh_tf_state *tf,
364                                 tree_stmt_iterator *tsi)
365 {
366   tree new, one, label;
367
368   new = find_goto_replacement (tf, *tp);
369   if (!new)
370     return;
371
372   one = expr_only (new);
373   if (one && TREE_CODE (one) == GOTO_EXPR)
374     {
375       *tp = one;
376       return;
377     }
378
379   label = build1 (LABEL_EXPR, void_type_node, NULL_TREE);
380   *tp = build_and_jump (&LABEL_EXPR_LABEL (label));
381
382   tsi_link_after (tsi, label, TSI_CONTINUE_LINKING);
383   tsi_link_after (tsi, new, TSI_CONTINUE_LINKING);
384 }
385
386 /* The real work of replace_goto_queue.  Returns with TSI updated to 
387    point to the next statement.  */
388
389 static void replace_goto_queue_stmt_list (tree, struct leh_tf_state *);
390
391 static void
392 replace_goto_queue_1 (tree t, struct leh_tf_state *tf, tree_stmt_iterator *tsi)
393 {
394   switch (TREE_CODE (t))
395     {
396     case GOTO_EXPR:
397     case RETURN_EXPR:
398       t = find_goto_replacement (tf, t);
399       if (t)
400         {
401           tsi_link_before (tsi, t, TSI_SAME_STMT);
402           tsi_delink (tsi);
403           return;
404         }
405       break;
406
407     case COND_EXPR:
408       replace_goto_queue_cond_clause (&COND_EXPR_THEN (t), tf, tsi);
409       replace_goto_queue_cond_clause (&COND_EXPR_ELSE (t), tf, tsi);
410       break;
411
412     case TRY_FINALLY_EXPR:
413     case TRY_CATCH_EXPR:
414       replace_goto_queue_stmt_list (TREE_OPERAND (t, 0), tf);
415       replace_goto_queue_stmt_list (TREE_OPERAND (t, 1), tf);
416       break;
417     case CATCH_EXPR:
418       replace_goto_queue_stmt_list (CATCH_BODY (t), tf);
419       break;
420     case EH_FILTER_EXPR:
421       replace_goto_queue_stmt_list (EH_FILTER_FAILURE (t), tf);
422       break;
423
424     case STATEMENT_LIST:
425       abort ();
426
427     default:
428       /* These won't have gotos in them.  */
429       break;
430     }
431
432   tsi_next (tsi);
433 }
434
435 /* A subroutine of replace_goto_queue.  Handles STATEMENT_LISTs.  */
436
437 static void
438 replace_goto_queue_stmt_list (tree t, struct leh_tf_state *tf)
439 {
440   tree_stmt_iterator i = tsi_start (t);
441   while (!tsi_end_p (i))
442     replace_goto_queue_1 (tsi_stmt (i), tf, &i);
443 }
444
445 /* Replace all goto queue members.  */
446
447 static void
448 replace_goto_queue (struct leh_tf_state *tf)
449 {
450   replace_goto_queue_stmt_list (*tf->top_p, tf);
451 }
452
453 /* For any GOTO_EXPR or RETURN_EXPR, decide whether it leaves a try_finally
454    node, and if so record that fact in the goto queue associated with that
455    try_finally node.  */
456
457 static void
458 maybe_record_in_goto_queue (struct leh_state *state, tree stmt)
459 {
460   struct leh_tf_state *tf = state->tf;
461   struct goto_queue_node *q;
462   size_t active, size;
463   int index;
464
465   if (!tf)
466     return;
467
468   switch (TREE_CODE (stmt))
469     {
470     case GOTO_EXPR:
471       {
472         tree lab = GOTO_DESTINATION (stmt);
473
474         /* Computed and non-local gotos do not get processed.  Given 
475            their nature we can neither tell whether we've escaped the
476            finally block nor redirect them if we knew.  */
477         if (TREE_CODE (lab) != LABEL_DECL)
478           return;
479
480         /* No need to record gotos that don't leave the try block.  */
481         if (! outside_finally_tree (lab, tf->try_finally_expr))
482           return;
483   
484         if (! tf->dest_array)
485           {
486             VARRAY_TREE_INIT (tf->dest_array, 10, "dest_array");
487             VARRAY_PUSH_TREE (tf->dest_array, lab);
488             index = 0;
489           }
490         else
491           {
492             int n = VARRAY_ACTIVE_SIZE (tf->dest_array);
493             for (index = 0; index < n; ++index)
494               if (VARRAY_TREE (tf->dest_array, index) == lab)
495                 break;
496             if (index == n)
497               VARRAY_PUSH_TREE (tf->dest_array, lab);
498           }
499       }
500       break;
501
502     case RETURN_EXPR:
503       tf->may_return = true;
504       index = -1;
505       break;
506
507     default:
508       abort ();
509     }
510
511   active = tf->goto_queue_active;
512   size = tf->goto_queue_size;
513   if (active >= size)
514     {
515       size = (size ? size * 2 : 32);
516       tf->goto_queue_size = size;
517       tf->goto_queue
518         = xrealloc (tf->goto_queue, size * sizeof (struct goto_queue_node));
519     }
520
521   q = &tf->goto_queue[active];
522   tf->goto_queue_active = active + 1;
523   
524   memset (q, 0, sizeof (*q));
525   q->stmt = stmt;
526   q->index = index;
527 }
528
529 #ifdef ENABLE_CHECKING
530 /* We do not process SWITCH_EXPRs for now.  As long as the original source
531    was in fact structured, and we've not yet done jump threading, then none
532    of the labels will leave outer TRY_FINALLY_EXPRs.  Verify this.  */
533
534 static void
535 verify_norecord_switch_expr (struct leh_state *state, tree switch_expr)
536 {
537   struct leh_tf_state *tf = state->tf;
538   size_t i, n;
539   tree vec;
540
541   if (!tf)
542     return;
543
544   vec = SWITCH_LABELS (switch_expr);
545   n = TREE_VEC_LENGTH (vec);
546
547   for (i = 0; i < n; ++i)
548     {
549       tree lab = CASE_LABEL (TREE_VEC_ELT (vec, i));
550       if (outside_finally_tree (lab, tf->try_finally_expr))
551         abort ();
552     }
553 }
554 #else
555 #define verify_norecord_switch_expr(state, switch_expr)
556 #endif
557
558 /* Redirect a RETURN_EXPR pointed to by STMT_P to FINLAB.  Place in CONT_P
559    whatever is needed to finish the return.  If MOD is non-null, insert it
560    before the new branch.  RETURN_VALUE_P is a cache containing a temporary
561    variable to be used in manipulating the value returned from the function.  */
562
563 static void
564 do_return_redirection (struct goto_queue_node *q, tree finlab, tree mod,
565                        tree *return_value_p)
566 {
567   tree ret_expr = TREE_OPERAND (q->stmt, 0);
568   tree x;
569
570   if (ret_expr)
571     {
572       /* The nasty part about redirecting the return value is that the
573          return value itself is to be computed before the FINALLY block
574          is executed.  e.g.
575
576                 int x;
577                 int foo (void)
578                 {
579                   x = 0;
580                   try {
581                     return x;
582                   } finally {
583                     x++;
584                   }
585                 }
586
587           should return 0, not 1.  Arrange for this to happen by copying
588           computed the return value into a local temporary.  This also
589           allows us to redirect multiple return statements through the
590           same destination block; whether this is a net win or not really
591           depends, I guess, but it does make generation of the switch in
592           lower_try_finally_switch easier.  */
593
594       if (TREE_CODE (ret_expr) == RESULT_DECL)
595         {
596           if (!*return_value_p)
597             *return_value_p = ret_expr;
598           else if (*return_value_p != ret_expr)
599             abort ();
600           q->cont_stmt = q->stmt;
601         }
602       else if (TREE_CODE (ret_expr) == MODIFY_EXPR)
603         {
604           tree result = TREE_OPERAND (ret_expr, 0);
605           tree new, old = TREE_OPERAND (ret_expr, 1);
606
607           if (!*return_value_p)
608             {
609               if (aggregate_value_p (TREE_TYPE (result),
610                                      TREE_TYPE (current_function_decl)))
611                 /* If this function returns in memory, copy the argument
612                    into the return slot now.  Otherwise, we might need to
613                    worry about magic return semantics, so we need to use a
614                    temporary to hold the value until we're actually ready
615                    to return.  */
616                 new = result;
617               else
618                 new = create_tmp_var (TREE_TYPE (old), "rettmp");
619               *return_value_p = new;
620             }
621           else
622             new = *return_value_p;
623
624           x = build (MODIFY_EXPR, TREE_TYPE (new), new, old);
625           append_to_statement_list (x, &q->repl_stmt);
626
627           if (new == result)
628             x = result;
629           else
630             x = build (MODIFY_EXPR, TREE_TYPE (result), result, new);
631           q->cont_stmt = build1 (RETURN_EXPR, void_type_node, x);
632         }
633       else
634         abort ();
635     }
636   else
637     {
638       /* If we don't return a value, all return statements are the same.  */
639       q->cont_stmt = q->stmt;
640     }
641
642   if (mod)
643     append_to_statement_list (mod, &q->repl_stmt);
644
645   x = build1 (GOTO_EXPR, void_type_node, finlab);
646   append_to_statement_list (x, &q->repl_stmt);
647 }
648
649 /* Similar, but easier, for GOTO_EXPR.  */
650
651 static void
652 do_goto_redirection (struct goto_queue_node *q, tree finlab, tree mod)
653 {
654   tree x;
655
656   q->cont_stmt = q->stmt;
657   if (mod)
658     append_to_statement_list (mod, &q->repl_stmt);
659
660   x = build1 (GOTO_EXPR, void_type_node, finlab);
661   append_to_statement_list (x, &q->repl_stmt);
662 }
663
664 /* We want to transform
665         try { body; } catch { stuff; }
666    to
667         body; goto over; lab: stuff; over:
668
669    T is a TRY_FINALLY or TRY_CATCH node.  LAB is the label that
670    should be placed before the second operand, or NULL.  OVER is
671    an existing label that should be put at the exit, or NULL.  */
672
673 static void
674 frob_into_branch_around (tree *tp, tree lab, tree over)
675 {
676   tree x, op1;
677
678   op1 = TREE_OPERAND (*tp, 1);
679   *tp = TREE_OPERAND (*tp, 0);
680
681   if (block_may_fallthru (*tp))
682     {
683       if (!over)
684         over = create_artificial_label ();
685       x = build1 (GOTO_EXPR, void_type_node, over);
686       append_to_statement_list (x, tp);
687     }
688
689   if (lab)
690     {
691       x = build1 (LABEL_EXPR, void_type_node, lab);
692       append_to_statement_list (x, tp);
693     }
694
695   append_to_statement_list (op1, tp);
696
697   if (over)
698     {
699       x = build1 (LABEL_EXPR, void_type_node, over);
700       append_to_statement_list (x, tp);
701     }
702 }
703
704 /* A subroutine of lower_try_finally.  Duplicate the tree rooted at T.
705    Make sure to record all new labels found.  */
706
707 static tree
708 lower_try_finally_dup_block (tree t, struct leh_state *outer_state)
709 {
710   tree region = NULL;
711
712   t = lhd_unsave_expr_now (t);
713
714   if (outer_state->tf)
715     region = outer_state->tf->try_finally_expr;
716   collect_finally_tree (t, region);
717
718   return t;
719 }
720
721 /* A subroutine of lower_try_finally.  Create a fallthru label for
722    the given try_finally state.  The only tricky bit here is that
723    we have to make sure to record the label in our outer context.  */
724
725 static tree
726 lower_try_finally_fallthru_label (struct leh_tf_state *tf)
727 {
728   tree label = tf->fallthru_label;
729   if (!label)
730     {
731       label = create_artificial_label ();
732       tf->fallthru_label = label;
733       if (tf->outer->tf)
734         record_in_finally_tree (label, tf->outer->tf->try_finally_expr); 
735     }
736   return label;
737 }
738
739 /* A subroutine of lower_try_finally.  If lang_protect_cleanup_actions
740    returns non-null, then the language requires that the exception path out
741    of a try_finally be treated specially.  To wit: the code within the
742    finally block may not itself throw an exception.  We have two choices here.
743    First we can duplicate the finally block and wrap it in a must_not_throw
744    region.  Second, we can generate code like
745
746         try {
747           finally_block;
748         } catch {
749           if (fintmp == eh_edge)
750             protect_cleanup_actions;
751         }
752
753    where "fintmp" is the temporary used in the switch statement generation
754    alternative considered below.  For the nonce, we always choose the first
755    option. 
756
757    THIS_STATE may be null if if this is a try-cleanup, not a try-finally.  */
758
759 static void
760 honor_protect_cleanup_actions (struct leh_state *outer_state,
761                                struct leh_state *this_state,
762                                struct leh_tf_state *tf)
763 {
764   tree protect_cleanup_actions, finally, x;
765   tree_stmt_iterator i;
766   bool finally_may_fallthru;
767
768   /* First check for nothing to do.  */
769   if (lang_protect_cleanup_actions)
770     protect_cleanup_actions = lang_protect_cleanup_actions ();
771   else
772     protect_cleanup_actions = NULL;
773
774   finally = TREE_OPERAND (*tf->top_p, 1);
775
776   /* If the EH case of the finally block can fall through, this may be a
777      structure of the form
778         try {
779           try {
780             throw ...;
781           } cleanup {
782             try {
783               throw ...;
784             } catch (...) {
785             }
786           }
787         } catch (...) {
788           yyy;
789         }
790     E.g. with an inline destructor with an embedded try block.  In this
791     case we must save the runtime EH data around the nested exception.
792
793     This complication means that any time the previous runtime data might
794     be used (via fallthru from the finally) we handle the eh case here,
795     whether or not protect_cleanup_actions is active.  */
796
797   finally_may_fallthru = block_may_fallthru (finally);
798   if (!finally_may_fallthru && !protect_cleanup_actions)
799     return;
800
801   /* Duplicate the FINALLY block.  Only need to do this for try-finally,
802      and not for cleanups.  */
803   if (this_state)
804     finally = lower_try_finally_dup_block (finally, outer_state);
805
806   /* Resume execution after the exception.  Adding this now lets
807      lower_eh_filter not add unnecessary gotos, as it is clear that
808      we never fallthru from this copy of the finally block.  */
809   if (finally_may_fallthru)
810     {
811       tree save_eptr, save_filt;
812
813       save_eptr = create_tmp_var (ptr_type_node, "save_eptr");
814       save_filt = create_tmp_var (integer_type_node, "save_filt");
815
816       i = tsi_start (finally);
817       x = build (EXC_PTR_EXPR, ptr_type_node);
818       x = build (MODIFY_EXPR, void_type_node, save_eptr, x);
819       tsi_link_before (&i, x, TSI_CONTINUE_LINKING);
820
821       x = build (FILTER_EXPR, integer_type_node);
822       x = build (MODIFY_EXPR, void_type_node, save_filt, x);
823       tsi_link_before (&i, x, TSI_CONTINUE_LINKING);
824
825       i = tsi_last (finally);
826       x = build (EXC_PTR_EXPR, ptr_type_node);
827       x = build (MODIFY_EXPR, void_type_node, x, save_eptr);
828       tsi_link_after (&i, x, TSI_CONTINUE_LINKING);
829
830       x = build (FILTER_EXPR, integer_type_node);
831       x = build (MODIFY_EXPR, void_type_node, x, save_filt);
832       tsi_link_after (&i, x, TSI_CONTINUE_LINKING);
833
834       x = build1 (RESX_EXPR, void_type_node,
835                   build_int_2 (get_eh_region_number (tf->region), 0));
836       tsi_link_after (&i, x, TSI_CONTINUE_LINKING);
837     }
838
839   /* Wrap the block with protect_cleanup_actions as the action.  */
840   if (protect_cleanup_actions)
841     {
842       x = build (EH_FILTER_EXPR, void_type_node, NULL, NULL);
843       append_to_statement_list (protect_cleanup_actions, &EH_FILTER_FAILURE (x));
844       EH_FILTER_MUST_NOT_THROW (x) = 1;
845       finally = build (TRY_CATCH_EXPR, void_type_node, finally, x);
846       lower_eh_filter (outer_state, &finally);
847     }
848   else
849     lower_eh_constructs_1 (outer_state, &finally);
850
851   /* Hook this up to the end of the existing try block.  If we
852      previously fell through the end, we'll have to branch around.
853      This means adding a new goto, and adding it to the queue.  */
854
855   i = tsi_last (TREE_OPERAND (*tf->top_p, 0));
856
857   if (tf->may_fallthru)
858     {
859       x = lower_try_finally_fallthru_label (tf);
860       x = build1 (GOTO_EXPR, void_type_node, x);
861       tsi_link_after (&i, x, TSI_CONTINUE_LINKING);
862
863       if (this_state)
864         maybe_record_in_goto_queue (this_state, x);
865
866       tf->may_fallthru = false;
867     }
868
869   x = build1 (LABEL_EXPR, void_type_node, tf->eh_label);
870   tsi_link_after (&i, x, TSI_CONTINUE_LINKING);
871   tsi_link_after (&i, finally, TSI_CONTINUE_LINKING);
872
873   /* Having now been handled, EH isn't to be considered with
874      the rest of the outgoing edges.  */
875   tf->may_throw = false;
876 }
877
878 /* A subroutine of lower_try_finally.  We have determined that there is
879    no fallthru edge out of the finally block.  This means that there is
880    no outgoing edge corresponding to any incoming edge.  Restructure the
881    try_finally node for this special case.  */
882
883 static void
884 lower_try_finally_nofallthru (struct leh_state *state, struct leh_tf_state *tf)
885 {
886   tree x, finally, lab, return_val;
887   struct goto_queue_node *q, *qe;
888
889   if (tf->may_throw)
890     lab = tf->eh_label;
891   else
892     lab = create_artificial_label ();
893
894   finally = TREE_OPERAND (*tf->top_p, 1);
895   *tf->top_p = TREE_OPERAND (*tf->top_p, 0);
896
897   x = build1 (LABEL_EXPR, void_type_node, lab);
898   append_to_statement_list (x, tf->top_p);
899
900   return_val = NULL;
901   q = tf->goto_queue;
902   qe = q + tf->goto_queue_active;
903   for (; q < qe; ++q)
904     if (q->index < 0)
905       do_return_redirection (q, lab, NULL, &return_val);
906     else
907       do_goto_redirection (q, lab, NULL);
908
909   replace_goto_queue (tf);
910
911   lower_eh_constructs_1 (state, &finally);
912   append_to_statement_list (finally, tf->top_p);
913 }
914
915 /* A subroutine of lower_try_finally.  We have determined that there is
916    exactly one destination of the finally block.  Restructure the
917    try_finally node for this special case.  */
918
919 static void
920 lower_try_finally_onedest (struct leh_state *state, struct leh_tf_state *tf)
921 {
922   struct goto_queue_node *q, *qe;
923   tree x, finally, finally_label;
924
925   finally = TREE_OPERAND (*tf->top_p, 1);
926   *tf->top_p = TREE_OPERAND (*tf->top_p, 0);
927
928   lower_eh_constructs_1 (state, &finally);
929
930   if (tf->may_throw)
931     {
932       /* Only reachable via the exception edge.  Add the given label to
933          the head of the FINALLY block.  Append a RESX at the end.  */
934
935       x = build1 (LABEL_EXPR, void_type_node, tf->eh_label);
936       append_to_statement_list (x, tf->top_p);
937
938       append_to_statement_list (finally, tf->top_p);
939       
940       x = build1 (RESX_EXPR, void_type_node,
941                   build_int_2 (get_eh_region_number (tf->region), 0));
942       append_to_statement_list (x, tf->top_p);
943
944       return;
945     }
946
947   if (tf->may_fallthru)
948     {
949       /* Only reachable via the fallthru edge.  Do nothing but let
950          the two blocks run together; we'll fall out the bottom.  */
951       append_to_statement_list (finally, tf->top_p);
952       return;
953     }
954
955   finally_label = create_artificial_label ();
956   x = build1 (LABEL_EXPR, void_type_node, finally_label);
957   append_to_statement_list (x, tf->top_p);
958
959   append_to_statement_list (finally, tf->top_p);
960
961   q = tf->goto_queue;
962   qe = q + tf->goto_queue_active;
963
964   if (tf->may_return)
965     {
966       /* Reachable by return expressions only.  Redirect them.  */
967       tree return_val = NULL;
968       for (; q < qe; ++q)
969         do_return_redirection (q, finally_label, NULL, &return_val);
970       replace_goto_queue (tf);
971     }
972   else
973     {
974       /* Reachable by goto expressions only.  Redirect them.  */
975       for (; q < qe; ++q)
976         do_goto_redirection (q, finally_label, NULL);
977       replace_goto_queue (tf);
978       
979       if (VARRAY_TREE (tf->dest_array, 0) == tf->fallthru_label)
980         {
981           /* Reachable by goto to fallthru label only.  Redirect it
982              to the new label (already created, sadly), and do not
983              emit the final branch out, or the fallthru label.  */
984           tf->fallthru_label = NULL;
985           return;
986         }
987     }
988
989   append_to_statement_list (tf->goto_queue[0].cont_stmt, tf->top_p);
990   maybe_record_in_goto_queue (state, tf->goto_queue[0].cont_stmt);
991 }
992
993 /* A subroutine of lower_try_finally.  There are multiple edges incoming
994    and outgoing from the finally block.  Implement this by duplicating the
995    finally block for every destination.  */
996
997 static void
998 lower_try_finally_copy (struct leh_state *state, struct leh_tf_state *tf)
999 {
1000   tree finally, new_stmt;
1001   tree x;
1002
1003   finally = TREE_OPERAND (*tf->top_p, 1);
1004   *tf->top_p = TREE_OPERAND (*tf->top_p, 0);
1005
1006   new_stmt = NULL_TREE;
1007
1008   if (tf->may_fallthru)
1009     {
1010       x = lower_try_finally_dup_block (finally, state);
1011       lower_eh_constructs_1 (state, &x);
1012       append_to_statement_list (x, &new_stmt);
1013
1014       x = lower_try_finally_fallthru_label (tf);
1015       x = build1 (GOTO_EXPR, void_type_node, x);
1016       append_to_statement_list (x, &new_stmt);
1017     }
1018
1019   if (tf->may_throw)
1020     {
1021       x = build1 (LABEL_EXPR, void_type_node, tf->eh_label);
1022       append_to_statement_list (x, &new_stmt);
1023
1024       x = lower_try_finally_dup_block (finally, state);
1025       lower_eh_constructs_1 (state, &x);
1026       append_to_statement_list (x, &new_stmt);
1027
1028       x = build1 (RESX_EXPR, void_type_node,
1029                   build_int_2 (get_eh_region_number (tf->region), 0));
1030       append_to_statement_list (x, &new_stmt);
1031     }
1032
1033   if (tf->goto_queue)
1034     {
1035       struct goto_queue_node *q, *qe;
1036       tree return_val = NULL;
1037       int return_index;
1038       tree *labels;
1039
1040       if (tf->dest_array)
1041         return_index = VARRAY_ACTIVE_SIZE (tf->dest_array);
1042       else
1043         return_index = 0;
1044       labels = xcalloc (sizeof (tree), return_index + 1);
1045
1046       q = tf->goto_queue;
1047       qe = q + tf->goto_queue_active;
1048       for (; q < qe; q++)
1049         {
1050           int index = q->index < 0 ? return_index : q->index;
1051           tree lab = labels[index];
1052           bool build_p = false;
1053
1054           if (!lab)
1055             {
1056               labels[index] = lab = create_artificial_label ();
1057               build_p = true;
1058             }
1059
1060           if (index == return_index)
1061             do_return_redirection (q, lab, NULL, &return_val);
1062           else
1063             do_goto_redirection (q, lab, NULL);
1064
1065           if (build_p)
1066             {
1067               x = build1 (LABEL_EXPR, void_type_node, lab);
1068               append_to_statement_list (x, &new_stmt);
1069
1070               x = lower_try_finally_dup_block (finally, state);
1071               lower_eh_constructs_1 (state, &x);
1072               append_to_statement_list (x, &new_stmt);
1073
1074               append_to_statement_list (q->cont_stmt, &new_stmt);
1075               maybe_record_in_goto_queue (state, q->cont_stmt);
1076             }
1077         }
1078       replace_goto_queue (tf);
1079       free (labels);
1080     }
1081
1082   /* Need to link new stmts after running replace_goto_queue due
1083      to not wanting to process the same goto stmts twice.  */
1084   append_to_statement_list (new_stmt, tf->top_p);
1085 }
1086
1087 /* A subroutine of lower_try_finally.  There are multiple edges incoming
1088    and outgoing from the finally block.  Implement this by instrumenting
1089    each incoming edge and creating a switch statement at the end of the
1090    finally block that branches to the appropriate destination.  */
1091
1092 static void
1093 lower_try_finally_switch (struct leh_state *state, struct leh_tf_state *tf)
1094 {
1095   struct goto_queue_node *q, *qe;
1096   tree return_val = NULL;
1097   tree finally, finally_tmp, finally_label;
1098   int return_index, eh_index, fallthru_index;
1099   int nlabels, ndests, j, last_case_index;
1100   tree case_label_vec, switch_stmt, last_case, switch_body;
1101   tree x;
1102
1103   /* Mash the TRY block to the head of the chain.  */
1104   finally = TREE_OPERAND (*tf->top_p, 1);
1105   *tf->top_p = TREE_OPERAND (*tf->top_p, 0);
1106
1107   /* Lower the finally block itself.  */
1108   lower_eh_constructs_1 (state, &finally);
1109
1110   /* Prepare for switch statement generation.  */
1111   if (tf->dest_array)
1112     nlabels = VARRAY_ACTIVE_SIZE (tf->dest_array);
1113   else
1114     nlabels = 0;
1115   return_index = nlabels;
1116   eh_index = return_index + tf->may_return;
1117   fallthru_index = eh_index + tf->may_throw;
1118   ndests = fallthru_index + tf->may_fallthru;
1119
1120   finally_tmp = create_tmp_var (integer_type_node, "finally_tmp");
1121   finally_label = create_artificial_label ();
1122
1123   case_label_vec = make_tree_vec (ndests);
1124   switch_stmt = build (SWITCH_EXPR, integer_type_node, finally_tmp,
1125                        NULL_TREE, case_label_vec);
1126   switch_body = NULL;
1127   last_case = NULL;
1128   last_case_index = 0;
1129
1130   /* Begin inserting code for getting to the finally block.  Things
1131      are done in this order to correspond to the sequence the code is
1132      layed out.  */
1133
1134   if (tf->may_fallthru)
1135     {
1136       x = build (MODIFY_EXPR, void_type_node, finally_tmp,
1137                  build_int_2 (fallthru_index, 0));
1138       append_to_statement_list (x, tf->top_p);
1139
1140       if (tf->may_throw)
1141         {
1142           x = build1 (GOTO_EXPR, void_type_node, finally_label);
1143           append_to_statement_list (x, tf->top_p);
1144         }
1145
1146
1147       last_case = build (CASE_LABEL_EXPR, void_type_node,
1148                          build_int_2 (fallthru_index, 0), NULL,
1149                          create_artificial_label ());
1150       TREE_VEC_ELT (case_label_vec, last_case_index) = last_case;
1151       last_case_index++;
1152
1153       x = build (LABEL_EXPR, void_type_node, CASE_LABEL (last_case));
1154       append_to_statement_list (x, &switch_body);
1155
1156       x = lower_try_finally_fallthru_label (tf);
1157       x = build1 (GOTO_EXPR, void_type_node, x);
1158       append_to_statement_list (x, &switch_body);
1159     }
1160
1161   if (tf->may_throw)
1162     {
1163       x = build1 (LABEL_EXPR, void_type_node, tf->eh_label);
1164       append_to_statement_list (x, tf->top_p);
1165
1166       x = build (MODIFY_EXPR, void_type_node, finally_tmp,
1167                  build_int_2 (eh_index, 0));
1168       append_to_statement_list (x, tf->top_p);
1169
1170       last_case = build (CASE_LABEL_EXPR, void_type_node,
1171                          build_int_2 (eh_index, 0), NULL,
1172                          create_artificial_label ());
1173       TREE_VEC_ELT (case_label_vec, last_case_index) = last_case;
1174       last_case_index++;
1175
1176       x = build (LABEL_EXPR, void_type_node, CASE_LABEL (last_case));
1177       append_to_statement_list (x, &switch_body);
1178       x = build1 (RESX_EXPR, void_type_node,
1179                   build_int_2 (get_eh_region_number (tf->region), 0));
1180       append_to_statement_list (x, &switch_body);
1181     }
1182
1183   x = build1 (LABEL_EXPR, void_type_node, finally_label);
1184   append_to_statement_list (x, tf->top_p);
1185
1186   append_to_statement_list (finally, tf->top_p);
1187
1188   /* Redirect each incoming goto edge.  */
1189   q = tf->goto_queue;
1190   qe = q + tf->goto_queue_active;
1191   j = last_case_index + tf->may_return;
1192   last_case_index += nlabels;
1193   for (; q < qe; ++q)
1194     {
1195       tree mod;
1196       int switch_id, case_index;
1197
1198       if (q->index < 0)
1199         {
1200           mod = build (MODIFY_EXPR, void_type_node, finally_tmp,
1201                        build_int_2 (return_index, 0));
1202           do_return_redirection (q, finally_label, mod, &return_val);
1203           switch_id = return_index;
1204         }
1205       else
1206         {
1207           mod = build (MODIFY_EXPR, void_type_node, finally_tmp,
1208                        build_int_2 (q->index, 0));
1209           do_goto_redirection (q, finally_label, mod);
1210           switch_id = q->index;
1211         }
1212
1213       case_index = j + q->index;
1214       if (!TREE_VEC_ELT (case_label_vec, case_index))
1215         {
1216           last_case = build (CASE_LABEL_EXPR, void_type_node,
1217                              build_int_2 (switch_id, 0), NULL,
1218                              create_artificial_label ());
1219           TREE_VEC_ELT (case_label_vec, case_index) = last_case;
1220
1221           x = build (LABEL_EXPR, void_type_node, CASE_LABEL (last_case));
1222           append_to_statement_list (x, &switch_body);
1223           append_to_statement_list (q->cont_stmt, &switch_body);
1224           maybe_record_in_goto_queue (state, q->cont_stmt);
1225         }
1226     }
1227   replace_goto_queue (tf);
1228   last_case_index += nlabels;
1229
1230   /* Make sure that the last case is the default label, as one is required.
1231      Then sort the labels, which is also required in GIMPLE.  */
1232   CASE_LOW (last_case) = NULL;
1233   sort_case_labels (case_label_vec);
1234
1235   /* Need to link switch_stmt after running replace_goto_queue due
1236      to not wanting to process the same goto stmts twice.  */
1237   append_to_statement_list (switch_stmt, tf->top_p);
1238   append_to_statement_list (switch_body, tf->top_p);
1239 }
1240
1241 /* Decide whether or not we are going to duplicate the finally block.
1242    There are several considerations.
1243
1244    First, if this is Java, then the finally block contains code
1245    written by the user.  It has line numbers associated with it,
1246    so duplicating the block means it's difficult to set a breakpoint.
1247    Since controlling code generation via -g is verboten, we simply
1248    never duplicate code without optimization.
1249
1250    Second, we'd like to prevent egregious code growth.  One way to
1251    do this is to estimate the size of the finally block, multiply
1252    that by the number of copies we'd need to make, and compare against
1253    the estimate of the size of the switch machinery we'd have to add.  */
1254
1255 static bool
1256 decide_copy_try_finally (int ndests, tree finally)
1257 {
1258   int f_estimate, sw_estimate;
1259
1260   if (!optimize)
1261     return false;
1262
1263   /* Finally estimate N times, plus N gotos.  */
1264   f_estimate = estimate_num_insns (finally);
1265   f_estimate = (f_estimate + 1) * ndests;
1266
1267   /* Switch statement (cost 10), N variable assignments, N gotos.  */
1268   sw_estimate = 10 + 2 * ndests;
1269
1270   /* Optimize for size clearly wants our best guess.  */
1271   if (optimize_size)
1272     return f_estimate < sw_estimate;
1273
1274   /* ??? These numbers are completely made up so far.  */
1275   if (optimize > 1)
1276     return f_estimate < 100 || f_estimate < sw_estimate * 2;
1277   else
1278     return f_estimate < 40 || f_estimate * 2 < sw_estimate * 3;
1279 }
1280
1281 /* A subroutine of lower_eh_constructs_1.  Lower a TRY_FINALLY_EXPR nodes
1282    to a sequence of labels and blocks, plus the exception region trees
1283    that record all the magic.  This is complicated by the need to 
1284    arrange for the FINALLY block to be executed on all exits.  */
1285
1286 static void
1287 lower_try_finally (struct leh_state *state, tree *tp)
1288 {
1289   struct leh_tf_state this_tf;
1290   struct leh_state this_state;
1291   int ndests;
1292
1293   /* Process the try block.  */
1294
1295   memset (&this_tf, 0, sizeof (this_tf));
1296   this_tf.try_finally_expr = *tp;
1297   this_tf.top_p = tp;
1298   this_tf.outer = state;
1299   if (using_eh_for_cleanups_p)
1300     this_tf.region
1301       = gen_eh_region_cleanup (state->cur_region, state->prev_try);
1302   else
1303     this_tf.region = NULL;
1304
1305   this_state.cur_region = this_tf.region;
1306   this_state.prev_try = state->prev_try;
1307   this_state.tf = &this_tf;
1308
1309   lower_eh_constructs_1 (&this_state, &TREE_OPERAND (*tp, 0));
1310
1311   /* Determine if the try block is escaped through the bottom.  */
1312   this_tf.may_fallthru = block_may_fallthru (TREE_OPERAND (*tp, 0));
1313
1314   /* Determine if any exceptions are possible within the try block.  */
1315   if (using_eh_for_cleanups_p)
1316     this_tf.may_throw = get_eh_region_may_contain_throw (this_tf.region);
1317   if (this_tf.may_throw)
1318     {
1319       this_tf.eh_label = create_artificial_label ();
1320       set_eh_region_tree_label (this_tf.region, this_tf.eh_label);
1321       honor_protect_cleanup_actions (state, &this_state, &this_tf);
1322     }
1323
1324   /* Sort the goto queue for efficient searching later.  */
1325   if (this_tf.goto_queue_active > 1)
1326     qsort (this_tf.goto_queue, this_tf.goto_queue_active,
1327            sizeof (struct goto_queue_node), goto_queue_cmp);
1328
1329   /* Determine how many edges (still) reach the finally block.  Or rather,
1330      how many destinations are reached by the finally block.  Use this to
1331      determine how we process the finally block itself.  */
1332
1333   if (this_tf.dest_array)
1334     ndests = VARRAY_ACTIVE_SIZE (this_tf.dest_array);
1335   else
1336     ndests = 0;
1337   ndests += this_tf.may_fallthru;
1338   ndests += this_tf.may_return;
1339   ndests += this_tf.may_throw;
1340
1341   /* If the FINALLY block is not reachable, dike it out.  */
1342   if (ndests == 0)
1343     *tp = TREE_OPERAND (*tp, 0);
1344
1345   /* If the finally block doesn't fall through, then any destination
1346      we might try to impose there isn't reached either.  There may be
1347      some minor amount of cleanup and redirection still needed.  */
1348   else if (!block_may_fallthru (TREE_OPERAND (*tp, 1)))
1349     lower_try_finally_nofallthru (state, &this_tf);
1350
1351   /* We can easily special-case redirection to a single destination.  */
1352   else if (ndests == 1)
1353     lower_try_finally_onedest (state, &this_tf);
1354
1355   else if (decide_copy_try_finally (ndests, TREE_OPERAND (*tp, 1)))
1356     lower_try_finally_copy (state, &this_tf);
1357   else
1358     lower_try_finally_switch (state, &this_tf);
1359
1360   /* If someone requested we add a label at the end of the transformed
1361      block, do so.  */
1362   if (this_tf.fallthru_label)
1363     {
1364       tree x = build1 (LABEL_EXPR, void_type_node, this_tf.fallthru_label);
1365       append_to_statement_list (x, tp);
1366     }
1367
1368   if (this_tf.goto_queue)
1369     free (this_tf.goto_queue);
1370 }
1371
1372 /* A subroutine of lower_eh_constructs_1.  Lower a TRY_CATCH_EXPR with a
1373    list of CATCH_EXPR nodes to a sequence of labels and blocks, plus the 
1374    exception region trees that record all the magic.  */
1375
1376 static void
1377 lower_catch (struct leh_state *state, tree *tp)
1378 {
1379   struct eh_region *try_region;
1380   struct leh_state this_state;
1381   tree_stmt_iterator i;
1382   tree out_label;
1383
1384   try_region = gen_eh_region_try (state->cur_region);
1385   this_state.cur_region = try_region;
1386   this_state.prev_try = try_region;
1387   this_state.tf = state->tf;
1388
1389   lower_eh_constructs_1 (&this_state, &TREE_OPERAND (*tp, 0));
1390
1391   if (!get_eh_region_may_contain_throw (try_region))
1392     {
1393       *tp = TREE_OPERAND (*tp, 0);
1394       return;
1395     }
1396
1397   out_label = NULL;
1398   for (i = tsi_start (TREE_OPERAND (*tp, 1)); !tsi_end_p (i); )
1399     {
1400       struct eh_region *catch_region;
1401       tree catch, x, eh_label;
1402
1403       catch = tsi_stmt (i);
1404       catch_region = gen_eh_region_catch (try_region, CATCH_TYPES (catch));
1405
1406       this_state.cur_region = catch_region;
1407       this_state.prev_try = state->prev_try;
1408       lower_eh_constructs_1 (&this_state, &CATCH_BODY (catch));
1409
1410       eh_label = create_artificial_label ();
1411       set_eh_region_tree_label (catch_region, eh_label);
1412
1413       x = build1 (LABEL_EXPR, void_type_node, eh_label);
1414       tsi_link_before (&i, x, TSI_SAME_STMT);
1415
1416       if (block_may_fallthru (CATCH_BODY (catch)))
1417         {
1418           if (!out_label)
1419             out_label = create_artificial_label ();
1420
1421           x = build1 (GOTO_EXPR, void_type_node, out_label);
1422           append_to_statement_list (x, &CATCH_BODY (catch));
1423         }
1424
1425       tsi_link_before (&i, CATCH_BODY (catch), TSI_SAME_STMT);
1426       tsi_delink (&i);
1427     }
1428
1429   frob_into_branch_around (tp, NULL, out_label);
1430 }
1431
1432 /* A subroutine of lower_eh_constructs_1.  Lower a TRY_CATCH_EXPR with a
1433    EH_FILTER_EXPR to a sequence of labels and blocks, plus the exception
1434    region trees that record all the magic.  */
1435
1436 static void
1437 lower_eh_filter (struct leh_state *state, tree *tp)
1438 {
1439   struct leh_state this_state;
1440   struct eh_region *this_region;
1441   tree inner = expr_first (TREE_OPERAND (*tp, 1));
1442   tree eh_label;
1443   
1444   if (EH_FILTER_MUST_NOT_THROW (inner))
1445     this_region = gen_eh_region_must_not_throw (state->cur_region);
1446   else
1447     this_region = gen_eh_region_allowed (state->cur_region,
1448                                          EH_FILTER_TYPES (inner));
1449   this_state = *state;
1450   this_state.cur_region = this_region;
1451   
1452   lower_eh_constructs_1 (&this_state, &TREE_OPERAND (*tp, 0));
1453
1454   if (!get_eh_region_may_contain_throw (this_region))
1455     {
1456       *tp = TREE_OPERAND (*tp, 0);
1457       return;
1458     }
1459
1460   lower_eh_constructs_1 (state, &EH_FILTER_FAILURE (inner));
1461   TREE_OPERAND (*tp, 1) = EH_FILTER_FAILURE (inner);
1462
1463   eh_label = create_artificial_label ();
1464   set_eh_region_tree_label (this_region, eh_label);
1465
1466   frob_into_branch_around (tp, eh_label, NULL);
1467 }
1468
1469 /* Implement a cleanup expression.  This is similar to try-finally,
1470    except that we only execute the cleanup block for exception edges.  */
1471
1472 static void
1473 lower_cleanup (struct leh_state *state, tree *tp)
1474 {
1475   struct leh_state this_state;
1476   struct eh_region *this_region;
1477   struct leh_tf_state fake_tf;
1478
1479   /* If not using eh, then exception-only cleanups are no-ops.  */
1480   if (!flag_exceptions)
1481     {
1482       *tp = TREE_OPERAND (*tp, 0);
1483       lower_eh_constructs_1 (state, tp);
1484       return;
1485     }
1486
1487   this_region = gen_eh_region_cleanup (state->cur_region, state->prev_try);
1488   this_state = *state;
1489   this_state.cur_region = this_region;
1490
1491   lower_eh_constructs_1 (&this_state, &TREE_OPERAND (*tp, 0));
1492
1493   if (!get_eh_region_may_contain_throw (this_region))
1494     {
1495       *tp = TREE_OPERAND (*tp, 0);
1496       return;
1497     }
1498
1499   /* Build enough of a try-finally state so that we can reuse
1500      honor_protect_cleanup_actions.  */
1501   memset (&fake_tf, 0, sizeof (fake_tf));
1502   fake_tf.top_p = tp;
1503   fake_tf.outer = state;
1504   fake_tf.region = this_region;
1505   fake_tf.may_fallthru = block_may_fallthru (TREE_OPERAND (*tp, 0));
1506   fake_tf.may_throw = true;
1507
1508   fake_tf.eh_label = create_artificial_label ();
1509   set_eh_region_tree_label (this_region, fake_tf.eh_label);
1510
1511   honor_protect_cleanup_actions (state, NULL, &fake_tf);
1512
1513   if (fake_tf.may_throw)
1514     {
1515       /* In this case honor_protect_cleanup_actions had nothing to do,
1516          and we should process this normally.  */
1517       lower_eh_constructs_1 (state, &TREE_OPERAND (*tp, 1));
1518       frob_into_branch_around (tp, fake_tf.eh_label, fake_tf.fallthru_label);
1519     }
1520   else
1521     {
1522       /* In this case honor_protect_cleanup_actions did nearly all of
1523          the work.  All we have left is to append the fallthru_label.  */
1524
1525       *tp = TREE_OPERAND (*tp, 0);
1526       if (fake_tf.fallthru_label)
1527         {
1528           tree x = build1 (LABEL_EXPR, void_type_node, fake_tf.fallthru_label);
1529           append_to_statement_list (x, tp);
1530         }
1531     }
1532 }
1533
1534 /* Main loop for lowering eh constructs.  */
1535
1536 static void
1537 lower_eh_constructs_1 (struct leh_state *state, tree *tp)
1538 {
1539   tree_stmt_iterator i;
1540   tree t = *tp;
1541
1542   switch (TREE_CODE (t))
1543     {
1544     case COND_EXPR:
1545       lower_eh_constructs_1 (state, &COND_EXPR_THEN (t));
1546       lower_eh_constructs_1 (state, &COND_EXPR_ELSE (t));
1547       break;
1548
1549     case CALL_EXPR:
1550       /* Look for things that can throw exceptions, and record them.  */
1551       if (state->cur_region && tree_could_throw_p (t))
1552         {
1553           record_stmt_eh_region (state->cur_region, t);
1554           note_eh_region_may_contain_throw (state->cur_region);
1555         }
1556       break;
1557
1558     case MODIFY_EXPR:
1559       /* Look for things that can throw exceptions, and record them.  */
1560       if (state->cur_region && tree_could_throw_p (t))
1561         {
1562           tree op;
1563
1564           record_stmt_eh_region (state->cur_region, t);
1565           note_eh_region_may_contain_throw (state->cur_region);
1566
1567           /* ??? For the benefit of calls.c, converting all this to rtl, 
1568              we need to record the call expression, not just the outer
1569              modify statement.  */
1570           op = get_call_expr_in (t);
1571           if (op)
1572             record_stmt_eh_region (state->cur_region, op);
1573         }
1574       break;
1575
1576     case GOTO_EXPR:
1577     case RETURN_EXPR:
1578       maybe_record_in_goto_queue (state, t);
1579       break;
1580     case SWITCH_EXPR:
1581       verify_norecord_switch_expr (state, t);
1582       break;
1583
1584     case TRY_FINALLY_EXPR:
1585       lower_try_finally (state, tp);
1586       break;
1587
1588     case TRY_CATCH_EXPR:
1589       i = tsi_start (TREE_OPERAND (t, 1));
1590       switch (TREE_CODE (tsi_stmt (i)))
1591         {
1592         case CATCH_EXPR:
1593           lower_catch (state, tp);
1594           break;
1595         case EH_FILTER_EXPR:
1596           lower_eh_filter (state, tp);
1597           break;
1598         default:
1599           lower_cleanup (state, tp);
1600           break;
1601         }
1602       break;
1603
1604     case STATEMENT_LIST:
1605       for (i = tsi_start (t); !tsi_end_p (i); )
1606         {
1607           lower_eh_constructs_1 (state, tsi_stmt_ptr (i));
1608           t = tsi_stmt (i);
1609           if (TREE_CODE (t) == STATEMENT_LIST)
1610             {
1611               tsi_link_before (&i, t, TSI_SAME_STMT);
1612               tsi_delink (&i);
1613             }
1614           else
1615             tsi_next (&i);
1616         }
1617       break;
1618
1619     default:
1620       /* A type, a decl, or some kind of statement that we're not
1621          interested in.  Don't walk them.  */
1622       break;
1623     }
1624 }
1625
1626 static void
1627 lower_eh_constructs (void)
1628 {
1629   struct leh_state null_state;
1630   tree *tp = &DECL_SAVED_TREE (current_function_decl);
1631
1632   finally_tree = htab_create (31, struct_ptr_hash, struct_ptr_eq, free);
1633   throw_stmt_table = htab_create_ggc (31, struct_ptr_hash, struct_ptr_eq,
1634                                       ggc_free);
1635
1636   collect_finally_tree (*tp, NULL);
1637
1638   memset (&null_state, 0, sizeof (null_state));
1639   lower_eh_constructs_1 (&null_state, tp);
1640
1641   htab_delete (finally_tree);
1642
1643   collect_eh_region_array ();
1644 }
1645
1646 struct tree_opt_pass pass_lower_eh = 
1647 {
1648   "eh",                                 /* name */
1649   NULL,                                 /* gate */
1650   lower_eh_constructs,                  /* execute */
1651   NULL,                                 /* sub */
1652   NULL,                                 /* next */
1653   0,                                    /* static_pass_number */
1654   TV_TREE_EH,                           /* tv_id */
1655   PROP_gimple_lcf,                      /* properties_required */
1656   PROP_gimple_leh,                      /* properties_provided */
1657   PROP_gimple_lcf,                      /* properties_destroyed */
1658   0,                                    /* todo_flags_start */
1659   TODO_dump_func                        /* todo_flags_finish */
1660 };
1661
1662 \f
1663 /* Construct EH edges for STMT.  */
1664
1665 static void
1666 make_eh_edge (struct eh_region *region, void *data)
1667 {
1668   tree stmt, lab;
1669   basic_block src, dst;
1670
1671   stmt = data;
1672   lab = get_eh_region_tree_label (region);
1673
1674   src = bb_for_stmt (stmt);
1675   dst = label_to_block (lab);
1676
1677   make_edge (src, dst, EDGE_ABNORMAL | EDGE_EH);
1678 }
1679   
1680 void
1681 make_eh_edges (tree stmt)
1682 {
1683   int region_nr;
1684   bool is_resx;
1685
1686   if (TREE_CODE (stmt) == RESX_EXPR)
1687     {
1688       region_nr = TREE_INT_CST_LOW (TREE_OPERAND (stmt, 0));
1689       is_resx = true;
1690     }
1691   else
1692     {
1693       region_nr = lookup_stmt_eh_region (stmt);
1694       if (region_nr < 0)
1695         return;
1696       is_resx = false;
1697     }
1698
1699   foreach_reachable_handler (region_nr, is_resx, make_eh_edge, stmt);
1700 }
1701
1702
1703 \f
1704 /* Return true if the expr can trap, as in dereferencing an invalid pointer
1705    location or floating point arithmetic.  C.f. the rtl version, may_trap_p.
1706    This routine expects only GIMPLE lhs or rhs input.  */
1707
1708 bool
1709 tree_could_trap_p (tree expr)
1710 {
1711   enum tree_code code = TREE_CODE (expr);
1712   bool honor_nans = false;
1713   bool honor_snans = false;
1714   bool fp_operation = false;
1715   bool honor_trapv = false;
1716   tree t, base, idx;
1717
1718   if (TREE_CODE_CLASS (code) == '<'
1719       || TREE_CODE_CLASS (code) == '1'
1720       || TREE_CODE_CLASS (code) == '2')
1721     {
1722       t = TREE_TYPE (expr);
1723       fp_operation = FLOAT_TYPE_P (t);
1724       if (fp_operation)
1725         {
1726           honor_nans = flag_trapping_math && !flag_finite_math_only;
1727           honor_snans = flag_signaling_nans != 0;
1728         }
1729       else if (INTEGRAL_TYPE_P (t) && TYPE_TRAP_SIGNED (t))
1730         honor_trapv = true;
1731     }
1732
1733  restart:
1734   switch (code)
1735     {
1736     case COMPONENT_REF:
1737     case REALPART_EXPR:
1738     case IMAGPART_EXPR:
1739     case BIT_FIELD_REF:
1740     case WITH_SIZE_EXPR:
1741       expr = TREE_OPERAND (expr, 0);
1742       code = TREE_CODE (expr);
1743       goto restart;
1744
1745     case ARRAY_RANGE_REF:
1746       /* Let us be conservative here for now.  We might be checking bounds of
1747          the access similarly to the case below.  */
1748       if (!TREE_THIS_NOTRAP (expr))
1749         return true;
1750
1751       base = TREE_OPERAND (expr, 0);
1752       return tree_could_trap_p (base);
1753
1754     case ARRAY_REF:
1755       base = TREE_OPERAND (expr, 0);
1756       idx = TREE_OPERAND (expr, 1);
1757       if (tree_could_trap_p (base))
1758         return true;
1759
1760       if (TREE_THIS_NOTRAP (expr))
1761         return false;
1762
1763       return !in_array_bounds_p (expr);
1764
1765     case INDIRECT_REF:
1766       return !TREE_THIS_NOTRAP (expr);
1767
1768     case ASM_EXPR:
1769       return TREE_THIS_VOLATILE (expr);
1770
1771     case TRUNC_DIV_EXPR:
1772     case CEIL_DIV_EXPR:
1773     case FLOOR_DIV_EXPR:
1774     case ROUND_DIV_EXPR:
1775     case EXACT_DIV_EXPR:
1776     case CEIL_MOD_EXPR:
1777     case FLOOR_MOD_EXPR:
1778     case ROUND_MOD_EXPR:
1779     case TRUNC_MOD_EXPR:
1780     case RDIV_EXPR:
1781       if (honor_snans || honor_trapv)
1782         return true;
1783       if (fp_operation && flag_trapping_math)
1784         return true;
1785       t = TREE_OPERAND (expr, 1);
1786       if (!TREE_CONSTANT (t) || integer_zerop (t))
1787         return true;
1788       return false;
1789
1790     case LT_EXPR:
1791     case LE_EXPR:
1792     case GT_EXPR:
1793     case GE_EXPR:
1794     case LTGT_EXPR:
1795       /* Some floating point comparisons may trap.  */
1796       return honor_nans;
1797
1798     case EQ_EXPR:
1799     case NE_EXPR:
1800     case UNORDERED_EXPR:
1801     case ORDERED_EXPR:
1802     case UNLT_EXPR:
1803     case UNLE_EXPR:
1804     case UNGT_EXPR:
1805     case UNGE_EXPR:
1806     case UNEQ_EXPR:
1807       return honor_snans;
1808
1809     case CONVERT_EXPR:
1810     case FIX_TRUNC_EXPR:
1811     case FIX_CEIL_EXPR:
1812     case FIX_FLOOR_EXPR:
1813     case FIX_ROUND_EXPR:
1814       /* Conversion of floating point might trap.  */
1815       return honor_nans;
1816
1817     case NEGATE_EXPR:
1818     case ABS_EXPR:
1819     case CONJ_EXPR:
1820       /* These operations don't trap with floating point.  */
1821       if (honor_trapv)
1822         return true;
1823       return false;
1824
1825     case PLUS_EXPR:
1826     case MINUS_EXPR:
1827     case MULT_EXPR:
1828       /* Any floating arithmetic may trap.  */
1829       if (fp_operation && flag_trapping_math)
1830         return true;
1831       if (honor_trapv)
1832         return true;
1833       return false;
1834
1835     default:
1836       /* Any floating arithmetic may trap.  */
1837       if (fp_operation && flag_trapping_math)
1838         return true;
1839       return false;
1840     }
1841 }
1842
1843 bool
1844 tree_could_throw_p (tree t)
1845 {
1846   if (!flag_exceptions)
1847     return false;
1848   if (TREE_CODE (t) == MODIFY_EXPR)
1849     {
1850       if (flag_non_call_exceptions
1851           && tree_could_trap_p (TREE_OPERAND (t, 0)))
1852         return true;
1853       t = TREE_OPERAND (t, 1);
1854     }
1855
1856   if (TREE_CODE (t) == WITH_SIZE_EXPR)
1857     t = TREE_OPERAND (t, 0);
1858   if (TREE_CODE (t) == CALL_EXPR)
1859     return (call_expr_flags (t) & ECF_NOTHROW) == 0;
1860   if (flag_non_call_exceptions)
1861     return tree_could_trap_p (t);
1862   return false;
1863 }
1864
1865 bool
1866 tree_can_throw_internal (tree stmt)
1867 {
1868   int region_nr = lookup_stmt_eh_region (stmt);
1869   if (region_nr < 0)
1870     return false;
1871   return can_throw_internal_1 (region_nr);
1872 }
1873
1874 bool
1875 tree_can_throw_external (tree stmt)
1876 {
1877   int region_nr = lookup_stmt_eh_region (stmt);
1878   if (region_nr < 0)
1879     return false;
1880   return can_throw_external_1 (region_nr);
1881 }
1882
1883 bool
1884 maybe_clean_eh_stmt (tree stmt)
1885 {
1886   if (!tree_could_throw_p (stmt))
1887     if (remove_stmt_from_eh_region (stmt))
1888       return true;
1889   return false;
1890 }
1891
1892 #include "gt-tree-eh.h"