1/* Exception handling semantics and decomposition for trees.
2   Copyright (C) 2003, 2004, 2005 Free Software Foundation, Inc.
3
4This file is part of GCC.
5
6GCC is free software; you can redistribute it and/or modify
7it under the terms of the GNU General Public License as published by
8the Free Software Foundation; either version 2, or (at your option)
9any later version.
10
11GCC is distributed in the hope that it will be useful,
12but WITHOUT ANY WARRANTY; without even the implied warranty of
13MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14GNU General Public License for more details.
15
16You should have received a copy of the GNU General Public License
17along with GCC; see the file COPYING.  If not, write to
18the Free Software Foundation, 51 Franklin Street, Fifth Floor,
19Boston, 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
42/* Nonzero if we are using EH to handle cleanups.  */
43static int using_eh_for_cleanups_p = 0;
44
45void
46using_eh_for_cleanups (void)
47{
48  using_eh_for_cleanups_p = 1;
49}
50
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
57static int
58struct_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
65static hashval_t
66struct_ptr_hash (const void *a)
67{
68  const void * const * x = a;
69  return (size_t)*x >> 4;
70}
71
72
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
85static void
86record_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
94void
95add_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
123void
124add_stmt_to_eh_region (tree t, int num)
125{
126  add_stmt_to_eh_region_fn (cfun, t, num);
127}
128
129bool
130remove_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
156bool
157remove_stmt_from_eh_region (tree t)
158{
159  return remove_stmt_from_eh_region_fn (cfun, t);
160}
161
162int
163lookup_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
176int
177lookup_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
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
191struct finally_tree_node
192{
193  tree child, parent;
194};
195
196/* Note that this table is *not* marked GTY.  It is short-lived.  */
197static htab_t finally_tree;
198
199static void
200record_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
214static void
215collect_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
261static bool
262outside_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
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
286struct 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
300struct 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
350static void lower_eh_filter (struct leh_state *, tree *);
351static 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
356static int
357goto_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
367static tree
368find_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
382static void
383replace_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
409static void replace_goto_queue_stmt_list (tree, struct leh_tf_state *);
410
411static void
412replace_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
457static void
458replace_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
467static void
468replace_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
479static void
480maybe_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
556static void
557verify_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
584static void
585do_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
676static void
677do_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
698static void
699frob_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
732static tree
733lower_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
750static tree
751lower_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
784static void
785honor_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
907static void
908lower_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
943static void
944lower_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
1021static void
1022lower_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
1137static void
1138lower_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
1312static bool
1313decide_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
1343static void
1344lower_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
1431static void
1432lower_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
1491static void
1492lower_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
1527static void
1528lower_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
1591static void
1592lower_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
1672static void
1673lower_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
1690struct 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
1708/* Construct EH edges for STMT.  */
1709
1710static void
1711make_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
1725void
1726make_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
1747static 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.  */
1751static void
1752mark_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.  */
1787bool
1788verify_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
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
1844bool
1845tree_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
1994bool
1995tree_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
2016bool
2017tree_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
2031bool
2032tree_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
2052bool
2053maybe_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}
2076