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