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