OSDN Git Service

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