OSDN Git Service

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