00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021 #include "config.h"
00022 #include "system.h"
00023 #include "coretypes.h"
00024 #include "tm.h"
00025 #include "tree.h"
00026 #include "rtl.h"
00027 #include "tm_p.h"
00028 #include "flags.h"
00029 #include "function.h"
00030 #include "except.h"
00031 #include "tree-flow.h"
00032 #include "tree-dump.h"
00033 #include "tree-inline.h"
00034 #include "tree-iterator.h"
00035 #include "tree-pass.h"
00036 #include "timevar.h"
00037 #include "langhooks.h"
00038 #include "ggc.h"
00039 #include "toplev.h"
00040
00041
00042
00043 static int using_eh_for_cleanups_p = 0;
00044
00045 void
00046 using_eh_for_cleanups (void)
00047 {
00048 using_eh_for_cleanups_p = 1;
00049 }
00050
00051
00052
00053
00054
00055
00056
00057 static int
00058 struct_ptr_eq (const void *a, const void *b)
00059 {
00060 const void * const * x = (const void * const *) a;
00061 const void * const * y = (const void * const *) b;
00062 return *x == *y;
00063 }
00064
00065 static hashval_t
00066 struct_ptr_hash (const void *a)
00067 {
00068 const void * const * x = (const void * const *) a;
00069 return (size_t)*x >> 4;
00070 }
00071
00072
00073
00074
00075
00076
00077
00078
00079
00080
00081
00082
00083
00084
00085 static void
00086 record_stmt_eh_region (struct eh_region *region, tree t)
00087 {
00088 if (!region)
00089 return;
00090
00091 add_stmt_to_eh_region (t, get_eh_region_number (region));
00092 }
00093
00094 void
00095 add_stmt_to_eh_region_fn (struct function *ifun, tree t, int num)
00096 {
00097 struct throw_stmt_node *n;
00098 void **slot;
00099
00100 gcc_assert (num >= 0);
00101 gcc_assert (TREE_CODE (t) != RESX_EXPR);
00102
00103 n = GGC_NEW (struct throw_stmt_node);
00104 n->stmt = t;
00105 n->region_nr = num;
00106
00107 if (!get_eh_throw_stmt_table (ifun))
00108 set_eh_throw_stmt_table (ifun, htab_create_ggc (31, struct_ptr_hash,
00109 struct_ptr_eq,
00110 ggc_free));
00111
00112 slot = htab_find_slot (get_eh_throw_stmt_table (ifun), n, INSERT);
00113 gcc_assert (!*slot);
00114 *slot = n;
00115
00116
00117
00118 if (TREE_CODE (t) == MODIFY_EXPR
00119 && (t = get_call_expr_in (t)))
00120 add_stmt_to_eh_region_fn (ifun, t, num);
00121 }
00122
00123 void
00124 add_stmt_to_eh_region (tree t, int num)
00125 {
00126 add_stmt_to_eh_region_fn (cfun, t, num);
00127 }
00128
00129 bool
00130 remove_stmt_from_eh_region_fn (struct function *ifun, tree t)
00131 {
00132 struct throw_stmt_node dummy;
00133 void **slot;
00134
00135 if (!get_eh_throw_stmt_table (ifun))
00136 return false;
00137
00138 dummy.stmt = t;
00139 slot = htab_find_slot (get_eh_throw_stmt_table (ifun), &dummy,
00140 NO_INSERT);
00141 if (slot)
00142 {
00143 htab_clear_slot (get_eh_throw_stmt_table (ifun), slot);
00144
00145
00146
00147 if (TREE_CODE (t) == MODIFY_EXPR
00148 && (t = get_call_expr_in (t)))
00149 remove_stmt_from_eh_region_fn (ifun, t);
00150 return true;
00151 }
00152 else
00153 return false;
00154 }
00155
00156 bool
00157 remove_stmt_from_eh_region (tree t)
00158 {
00159 return remove_stmt_from_eh_region_fn (cfun, t);
00160 }
00161
00162 int
00163 lookup_stmt_eh_region_fn (struct function *ifun, tree t)
00164 {
00165 struct throw_stmt_node *p, n;
00166
00167 if (!get_eh_throw_stmt_table (ifun))
00168 return -2;
00169
00170 n.stmt = t;
00171 p = (struct throw_stmt_node *) htab_find (get_eh_throw_stmt_table (ifun),
00172 &n);
00173
00174 return (p ? p->region_nr : -1);
00175 }
00176
00177 int
00178 lookup_stmt_eh_region (tree t)
00179 {
00180
00181
00182 if (!cfun)
00183 return -1;
00184 return lookup_stmt_eh_region_fn (cfun, t);
00185 }
00186
00187
00188
00189
00190
00191
00192 struct finally_tree_node
00193 {
00194 tree child, parent;
00195 };
00196
00197
00198 static htab_t finally_tree;
00199
00200 static void
00201 record_in_finally_tree (tree child, tree parent)
00202 {
00203 struct finally_tree_node *n;
00204 void **slot;
00205
00206 n = XNEW (struct finally_tree_node);
00207 n->child = child;
00208 n->parent = parent;
00209
00210 slot = htab_find_slot (finally_tree, n, INSERT);
00211 gcc_assert (!*slot);
00212 *slot = n;
00213 }
00214
00215 static void
00216 collect_finally_tree (tree t, tree region)
00217 {
00218 tailrecurse:
00219 switch (TREE_CODE (t))
00220 {
00221 case LABEL_EXPR:
00222 record_in_finally_tree (LABEL_EXPR_LABEL (t), region);
00223 break;
00224
00225 case TRY_FINALLY_EXPR:
00226 record_in_finally_tree (t, region);
00227 collect_finally_tree (TREE_OPERAND (t, 0), t);
00228 t = TREE_OPERAND (t, 1);
00229 goto tailrecurse;
00230
00231 case TRY_CATCH_EXPR:
00232 collect_finally_tree (TREE_OPERAND (t, 0), region);
00233 t = TREE_OPERAND (t, 1);
00234 goto tailrecurse;
00235
00236 case CATCH_EXPR:
00237 t = CATCH_BODY (t);
00238 goto tailrecurse;
00239
00240 case EH_FILTER_EXPR:
00241 t = EH_FILTER_FAILURE (t);
00242 goto tailrecurse;
00243
00244 case STATEMENT_LIST:
00245 {
00246 tree_stmt_iterator i;
00247 for (i = tsi_start (t); !tsi_end_p (i); tsi_next (&i))
00248 collect_finally_tree (tsi_stmt (i), region);
00249 }
00250 break;
00251
00252 default:
00253
00254
00255 break;
00256 }
00257 }
00258
00259
00260
00261
00262 static bool
00263 outside_finally_tree (tree start, tree target)
00264 {
00265 struct finally_tree_node n, *p;
00266
00267 do
00268 {
00269 n.child = start;
00270 p = (struct finally_tree_node *) htab_find (finally_tree, &n);
00271 if (!p)
00272 return true;
00273 start = p->parent;
00274 }
00275 while (start != target);
00276
00277 return false;
00278 }
00279
00280
00281
00282
00283
00284
00285
00286
00287 struct leh_state
00288 {
00289
00290
00291
00292 struct eh_region *cur_region;
00293 struct eh_region *prev_try;
00294
00295
00296
00297
00298 struct leh_tf_state *tf;
00299 };
00300
00301 struct leh_tf_state
00302 {
00303
00304
00305
00306
00307 tree try_finally_expr;
00308 tree *top_p;
00309
00310
00311 struct leh_state *outer;
00312
00313
00314 struct eh_region *region;
00315
00316
00317
00318 struct goto_queue_node {
00319 tree stmt;
00320 tree repl_stmt;
00321 tree cont_stmt;
00322 int index;
00323 } *goto_queue;
00324 size_t goto_queue_size;
00325 size_t goto_queue_active;
00326
00327
00328 VEC(tree,heap) *dest_array;
00329
00330
00331
00332
00333 tree fallthru_label;
00334
00335
00336
00337 tree eh_label;
00338
00339
00340
00341 bool may_fallthru;
00342
00343
00344 bool may_return;
00345
00346
00347
00348 bool may_throw;
00349 };
00350
00351 static void lower_eh_filter (struct leh_state *, tree *);
00352 static void lower_eh_constructs_1 (struct leh_state *, tree *);
00353
00354
00355
00356
00357 static int
00358 goto_queue_cmp (const void *x, const void *y)
00359 {
00360 tree a = ((const struct goto_queue_node *)x)->stmt;
00361 tree b = ((const struct goto_queue_node *)y)->stmt;
00362 return (a == b ? 0 : a < b ? -1 : 1);
00363 }
00364
00365
00366
00367
00368 static tree
00369 find_goto_replacement (struct leh_tf_state *tf, tree stmt)
00370 {
00371 struct goto_queue_node tmp, *ret;
00372 tmp.stmt = stmt;
00373 ret = (struct goto_queue_node *)
00374 bsearch (&tmp, tf->goto_queue, tf->goto_queue_active,
00375 sizeof (struct goto_queue_node), goto_queue_cmp);
00376 return (ret ? ret->repl_stmt : NULL);
00377 }
00378
00379
00380
00381
00382
00383
00384 static void
00385 replace_goto_queue_cond_clause (tree *tp, struct leh_tf_state *tf,
00386 tree_stmt_iterator *tsi)
00387 {
00388 tree new, one, label;
00389
00390 new = find_goto_replacement (tf, *tp);
00391 if (!new)
00392 return;
00393
00394 one = expr_only (new);
00395 if (one && TREE_CODE (one) == GOTO_EXPR)
00396 {
00397 *tp = one;
00398 return;
00399 }
00400
00401 label = build1 (LABEL_EXPR, void_type_node, NULL_TREE);
00402 *tp = build_and_jump (&LABEL_EXPR_LABEL (label));
00403
00404 tsi_link_after (tsi, label, TSI_CONTINUE_LINKING);
00405 tsi_link_after (tsi, new, TSI_CONTINUE_LINKING);
00406 }
00407
00408
00409
00410
00411 static void replace_goto_queue_stmt_list (tree, struct leh_tf_state *);
00412
00413 static void
00414 replace_goto_queue_1 (tree t, struct leh_tf_state *tf, tree_stmt_iterator *tsi)
00415 {
00416 switch (TREE_CODE (t))
00417 {
00418 case GOTO_EXPR:
00419 case RETURN_EXPR:
00420 t = find_goto_replacement (tf, t);
00421 if (t)
00422 {
00423 tsi_link_before (tsi, t, TSI_SAME_STMT);
00424 tsi_delink (tsi);
00425 return;
00426 }
00427 break;
00428
00429 case COND_EXPR:
00430 replace_goto_queue_cond_clause (&COND_EXPR_THEN (t), tf, tsi);
00431 replace_goto_queue_cond_clause (&COND_EXPR_ELSE (t), tf, tsi);
00432 break;
00433
00434 case TRY_FINALLY_EXPR:
00435 case TRY_CATCH_EXPR:
00436 replace_goto_queue_stmt_list (TREE_OPERAND (t, 0), tf);
00437 replace_goto_queue_stmt_list (TREE_OPERAND (t, 1), tf);
00438 break;
00439 case CATCH_EXPR:
00440 replace_goto_queue_stmt_list (CATCH_BODY (t), tf);
00441 break;
00442 case EH_FILTER_EXPR:
00443 replace_goto_queue_stmt_list (EH_FILTER_FAILURE (t), tf);
00444 break;
00445
00446 case STATEMENT_LIST:
00447 gcc_unreachable ();
00448
00449 default:
00450
00451 break;
00452 }
00453
00454 tsi_next (tsi);
00455 }
00456
00457
00458
00459 static void
00460 replace_goto_queue_stmt_list (tree t, struct leh_tf_state *tf)
00461 {
00462 tree_stmt_iterator i = tsi_start (t);
00463 while (!tsi_end_p (i))
00464 replace_goto_queue_1 (tsi_stmt (i), tf, &i);
00465 }
00466
00467
00468
00469 static void
00470 replace_goto_queue (struct leh_tf_state *tf)
00471 {
00472 if (tf->goto_queue_active == 0)
00473 return;
00474 replace_goto_queue_stmt_list (*tf->top_p, tf);
00475 }
00476
00477
00478
00479
00480
00481 static void
00482 maybe_record_in_goto_queue (struct leh_state *state, tree stmt)
00483 {
00484 struct leh_tf_state *tf = state->tf;
00485 struct goto_queue_node *q;
00486 size_t active, size;
00487 int index;
00488
00489 if (!tf)
00490 return;
00491
00492 switch (TREE_CODE (stmt))
00493 {
00494 case GOTO_EXPR:
00495 {
00496 tree lab = GOTO_DESTINATION (stmt);
00497
00498
00499
00500
00501 if (TREE_CODE (lab) != LABEL_DECL)
00502 return;
00503
00504
00505 if (! outside_finally_tree (lab, tf->try_finally_expr))
00506 return;
00507
00508 if (! tf->dest_array)
00509 {
00510 tf->dest_array = VEC_alloc (tree, heap, 10);
00511 VEC_quick_push (tree, tf->dest_array, lab);
00512 index = 0;
00513 }
00514 else
00515 {
00516 int n = VEC_length (tree, tf->dest_array);
00517 for (index = 0; index < n; ++index)
00518 if (VEC_index (tree, tf->dest_array, index) == lab)
00519 break;
00520 if (index == n)
00521 VEC_safe_push (tree, heap, tf->dest_array, lab);
00522 }
00523 }
00524 break;
00525
00526 case RETURN_EXPR:
00527 tf->may_return = true;
00528 index = -1;
00529 break;
00530
00531 default:
00532 gcc_unreachable ();
00533 }
00534
00535 active = tf->goto_queue_active;
00536 size = tf->goto_queue_size;
00537 if (active >= size)
00538 {
00539 size = (size ? size * 2 : 32);
00540 tf->goto_queue_size = size;
00541 tf->goto_queue
00542 = XRESIZEVEC (struct goto_queue_node, tf->goto_queue, size);
00543 }
00544
00545 q = &tf->goto_queue[active];
00546 tf->goto_queue_active = active + 1;
00547
00548 memset (q, 0, sizeof (*q));
00549 q->stmt = stmt;
00550 q->index = index;
00551 }
00552
00553 #ifdef ENABLE_CHECKING
00554
00555
00556
00557
00558 static void
00559 verify_norecord_switch_expr (struct leh_state *state, tree switch_expr)
00560 {
00561 struct leh_tf_state *tf = state->tf;
00562 size_t i, n;
00563 tree vec;
00564
00565 if (!tf)
00566 return;
00567
00568 vec = SWITCH_LABELS (switch_expr);
00569 n = TREE_VEC_LENGTH (vec);
00570
00571 for (i = 0; i < n; ++i)
00572 {
00573 tree lab = CASE_LABEL (TREE_VEC_ELT (vec, i));
00574 gcc_assert (!outside_finally_tree (lab, tf->try_finally_expr));
00575 }
00576 }
00577 #else
00578 #define verify_norecord_switch_expr(state, switch_expr)
00579 #endif
00580
00581
00582
00583
00584
00585
00586 static void
00587 do_return_redirection (struct goto_queue_node *q, tree finlab, tree mod,
00588 tree *return_value_p)
00589 {
00590 tree ret_expr = TREE_OPERAND (q->stmt, 0);
00591 tree x;
00592
00593 if (ret_expr)
00594 {
00595
00596
00597
00598
00599
00600
00601
00602
00603
00604
00605
00606
00607
00608
00609
00610
00611
00612
00613
00614
00615
00616
00617 switch (TREE_CODE (ret_expr))
00618 {
00619 case RESULT_DECL:
00620 if (!*return_value_p)
00621 *return_value_p = ret_expr;
00622 else
00623 gcc_assert (*return_value_p == ret_expr);
00624 q->cont_stmt = q->stmt;
00625 break;
00626
00627 case MODIFY_EXPR:
00628 {
00629 tree result = TREE_OPERAND (ret_expr, 0);
00630 tree new, old = TREE_OPERAND (ret_expr, 1);
00631
00632 if (!*return_value_p)
00633 {
00634 if (aggregate_value_p (TREE_TYPE (result),
00635 TREE_TYPE (current_function_decl)))
00636
00637
00638
00639
00640
00641 new = result;
00642 else
00643 new = create_tmp_var (TREE_TYPE (old), "rettmp");
00644 *return_value_p = new;
00645 }
00646 else
00647 new = *return_value_p;
00648
00649 x = build2 (MODIFY_EXPR, TREE_TYPE (new), new, old);
00650 append_to_statement_list (x, &q->repl_stmt);
00651
00652 if (new == result)
00653 x = result;
00654 else
00655 x = build2 (MODIFY_EXPR, TREE_TYPE (result), result, new);
00656 q->cont_stmt = build1 (RETURN_EXPR, void_type_node, x);
00657 }
00658
00659 default:
00660 gcc_unreachable ();
00661 }
00662 }
00663 else
00664 {
00665
00666 q->cont_stmt = q->stmt;
00667 }
00668
00669 if (mod)
00670 append_to_statement_list (mod, &q->repl_stmt);
00671
00672 x = build1 (GOTO_EXPR, void_type_node, finlab);
00673 append_to_statement_list (x, &q->repl_stmt);
00674 }
00675
00676
00677
00678 static void
00679 do_goto_redirection (struct goto_queue_node *q, tree finlab, tree mod)
00680 {
00681 tree x;
00682
00683 q->cont_stmt = q->stmt;
00684 if (mod)
00685 append_to_statement_list (mod, &q->repl_stmt);
00686
00687 x = build1 (GOTO_EXPR, void_type_node, finlab);
00688 append_to_statement_list (x, &q->repl_stmt);
00689 }
00690
00691
00692
00693
00694
00695
00696
00697
00698
00699
00700 static void
00701 frob_into_branch_around (tree *tp, tree lab, tree over)
00702 {
00703 tree x, op1;
00704
00705 op1 = TREE_OPERAND (*tp, 1);
00706 *tp = TREE_OPERAND (*tp, 0);
00707
00708 if (block_may_fallthru (*tp))
00709 {
00710 if (!over)
00711 over = create_artificial_label ();
00712 x = build1 (GOTO_EXPR, void_type_node, over);
00713 append_to_statement_list (x, tp);
00714 }
00715
00716 if (lab)
00717 {
00718 x = build1 (LABEL_EXPR, void_type_node, lab);
00719 append_to_statement_list (x, tp);
00720 }
00721
00722 append_to_statement_list (op1, tp);
00723
00724 if (over)
00725 {
00726 x = build1 (LABEL_EXPR, void_type_node, over);
00727 append_to_statement_list (x, tp);
00728 }
00729 }
00730
00731
00732
00733
00734 static tree
00735 lower_try_finally_dup_block (tree t, struct leh_state *outer_state)
00736 {
00737 tree region = NULL;
00738
00739 t = unsave_expr_now (t);
00740
00741 if (outer_state->tf)
00742 region = outer_state->tf->try_finally_expr;
00743 collect_finally_tree (t, region);
00744
00745 return t;
00746 }
00747
00748
00749
00750
00751
00752 static tree
00753 lower_try_finally_fallthru_label (struct leh_tf_state *tf)
00754 {
00755 tree label = tf->fallthru_label;
00756 if (!label)
00757 {
00758 label = create_artificial_label ();
00759 tf->fallthru_label = label;
00760 if (tf->outer->tf)
00761 record_in_finally_tree (label, tf->outer->tf->try_finally_expr);
00762 }
00763 return label;
00764 }
00765
00766
00767
00768
00769
00770
00771
00772
00773
00774
00775
00776
00777
00778
00779
00780
00781
00782
00783
00784
00785
00786 static void
00787 honor_protect_cleanup_actions (struct leh_state *outer_state,
00788 struct leh_state *this_state,
00789 struct leh_tf_state *tf)
00790 {
00791 tree protect_cleanup_actions, finally, x;
00792 tree_stmt_iterator i;
00793 bool finally_may_fallthru;
00794
00795
00796 if (lang_protect_cleanup_actions)
00797 protect_cleanup_actions = lang_protect_cleanup_actions ();
00798 else
00799 protect_cleanup_actions = NULL;
00800
00801 finally = TREE_OPERAND (*tf->top_p, 1);
00802
00803
00804
00805
00806
00807
00808
00809
00810
00811
00812
00813
00814
00815
00816
00817
00818
00819
00820
00821
00822
00823
00824 finally_may_fallthru = block_may_fallthru (finally);
00825 if (!finally_may_fallthru && !protect_cleanup_actions)
00826 return;
00827
00828
00829
00830 if (this_state)
00831 finally = lower_try_finally_dup_block (finally, outer_state);
00832
00833
00834
00835
00836 if (finally_may_fallthru)
00837 {
00838 tree save_eptr, save_filt;
00839
00840 save_eptr = create_tmp_var (ptr_type_node, "save_eptr");
00841 save_filt = create_tmp_var (integer_type_node, "save_filt");
00842
00843 i = tsi_start (finally);
00844 x = build0 (EXC_PTR_EXPR, ptr_type_node);
00845 x = build2 (MODIFY_EXPR, void_type_node, save_eptr, x);
00846 tsi_link_before (&i, x, TSI_CONTINUE_LINKING);
00847
00848 x = build0 (FILTER_EXPR, integer_type_node);
00849 x = build2 (MODIFY_EXPR, void_type_node, save_filt, x);
00850 tsi_link_before (&i, x, TSI_CONTINUE_LINKING);
00851
00852 i = tsi_last (finally);
00853 x = build0 (EXC_PTR_EXPR, ptr_type_node);
00854 x = build2 (MODIFY_EXPR, void_type_node, x, save_eptr);
00855 tsi_link_after (&i, x, TSI_CONTINUE_LINKING);
00856
00857 x = build0 (FILTER_EXPR, integer_type_node);
00858 x = build2 (MODIFY_EXPR, void_type_node, x, save_filt);
00859 tsi_link_after (&i, x, TSI_CONTINUE_LINKING);
00860
00861 x = build_resx (get_eh_region_number (tf->region));
00862 tsi_link_after (&i, x, TSI_CONTINUE_LINKING);
00863 }
00864
00865
00866 if (protect_cleanup_actions)
00867 {
00868 x = build2 (EH_FILTER_EXPR, void_type_node, NULL, NULL);
00869 append_to_statement_list (protect_cleanup_actions, &EH_FILTER_FAILURE (x));
00870 EH_FILTER_MUST_NOT_THROW (x) = 1;
00871 finally = build2 (TRY_CATCH_EXPR, void_type_node, finally, x);
00872 lower_eh_filter (outer_state, &finally);
00873 }
00874 else
00875 lower_eh_constructs_1 (outer_state, &finally);
00876
00877
00878
00879
00880
00881 i = tsi_last (TREE_OPERAND (*tf->top_p, 0));
00882
00883 if (tf->may_fallthru)
00884 {
00885 x = lower_try_finally_fallthru_label (tf);
00886 x = build1 (GOTO_EXPR, void_type_node, x);
00887 tsi_link_after (&i, x, TSI_CONTINUE_LINKING);
00888
00889 if (this_state)
00890 maybe_record_in_goto_queue (this_state, x);
00891
00892 tf->may_fallthru = false;
00893 }
00894
00895 x = build1 (LABEL_EXPR, void_type_node, tf->eh_label);
00896 tsi_link_after (&i, x, TSI_CONTINUE_LINKING);
00897 tsi_link_after (&i, finally, TSI_CONTINUE_LINKING);
00898
00899
00900
00901 tf->may_throw = false;
00902 }
00903
00904
00905
00906
00907
00908
00909 static void
00910 lower_try_finally_nofallthru (struct leh_state *state, struct leh_tf_state *tf)
00911 {
00912 tree x, finally, lab, return_val;
00913 struct goto_queue_node *q, *qe;
00914
00915 if (tf->may_throw)
00916 lab = tf->eh_label;
00917 else
00918 lab = create_artificial_label ();
00919
00920 finally = TREE_OPERAND (*tf->top_p, 1);
00921 *tf->top_p = TREE_OPERAND (*tf->top_p, 0);
00922
00923 x = build1 (LABEL_EXPR, void_type_node, lab);
00924 append_to_statement_list (x, tf->top_p);
00925
00926 return_val = NULL;
00927 q = tf->goto_queue;
00928 qe = q + tf->goto_queue_active;
00929 for (; q < qe; ++q)
00930 if (q->index < 0)
00931 do_return_redirection (q, lab, NULL, &return_val);
00932 else
00933 do_goto_redirection (q, lab, NULL);
00934
00935 replace_goto_queue (tf);
00936
00937 lower_eh_constructs_1 (state, &finally);
00938 append_to_statement_list (finally, tf->top_p);
00939 }
00940
00941
00942
00943
00944
00945 static void
00946 lower_try_finally_onedest (struct leh_state *state, struct leh_tf_state *tf)
00947 {
00948 struct goto_queue_node *q, *qe;
00949 tree x, finally, finally_label;
00950
00951 finally = TREE_OPERAND (*tf->top_p, 1);
00952 *tf->top_p = TREE_OPERAND (*tf->top_p, 0);
00953
00954 lower_eh_constructs_1 (state, &finally);
00955
00956 if (tf->may_throw)
00957 {
00958
00959
00960
00961 x = build1 (LABEL_EXPR, void_type_node, tf->eh_label);
00962 append_to_statement_list (x, tf->top_p);
00963
00964 append_to_statement_list (finally, tf->top_p);
00965
00966 x = build_resx (get_eh_region_number (tf->region));
00967
00968 append_to_statement_list (x, tf->top_p);
00969
00970 return;
00971 }
00972
00973 if (tf->may_fallthru)
00974 {
00975
00976
00977 append_to_statement_list (finally, tf->top_p);
00978 return;
00979 }
00980
00981 finally_label = create_artificial_label ();
00982 x = build1 (LABEL_EXPR, void_type_node, finally_label);
00983 append_to_statement_list (x, tf->top_p);
00984
00985 append_to_statement_list (finally, tf->top_p);
00986
00987 q = tf->goto_queue;
00988 qe = q + tf->goto_queue_active;
00989
00990 if (tf->may_return)
00991 {
00992
00993 tree return_val = NULL;
00994 for (; q < qe; ++q)
00995 do_return_redirection (q, finally_label, NULL, &return_val);
00996 replace_goto_queue (tf);
00997 }
00998 else
00999 {
01000
01001 for (; q < qe; ++q)
01002 do_goto_redirection (q, finally_label, NULL);
01003 replace_goto_queue (tf);
01004
01005 if (VEC_index (tree, tf->dest_array, 0) == tf->fallthru_label)
01006 {
01007
01008
01009
01010 tf->fallthru_label = NULL;
01011 return;
01012 }
01013 }
01014
01015 append_to_statement_list (tf->goto_queue[0].cont_stmt, tf->top_p);
01016 maybe_record_in_goto_queue (state, tf->goto_queue[0].cont_stmt);
01017 }
01018
01019
01020
01021
01022
01023 static void
01024 lower_try_finally_copy (struct leh_state *state, struct leh_tf_state *tf)
01025 {
01026 tree finally, new_stmt;
01027 tree x;
01028
01029 finally = TREE_OPERAND (*tf->top_p, 1);
01030 *tf->top_p = TREE_OPERAND (*tf->top_p, 0);
01031
01032 new_stmt = NULL_TREE;
01033
01034 if (tf->may_fallthru)
01035 {
01036 x = lower_try_finally_dup_block (finally, state);
01037 lower_eh_constructs_1 (state, &x);
01038 append_to_statement_list (x, &new_stmt);
01039
01040 x = lower_try_finally_fallthru_label (tf);
01041 x = build1 (GOTO_EXPR, void_type_node, x);
01042 append_to_statement_list (x, &new_stmt);
01043 }
01044
01045 if (tf->may_throw)
01046 {
01047 x = build1 (LABEL_EXPR, void_type_node, tf->eh_label);
01048 append_to_statement_list (x, &new_stmt);
01049
01050 x = lower_try_finally_dup_block (finally, state);
01051 lower_eh_constructs_1 (state, &x);
01052 append_to_statement_list (x, &new_stmt);
01053
01054 x = build_resx (get_eh_region_number (tf->region));
01055 append_to_statement_list (x, &new_stmt);
01056 }
01057
01058 if (tf->goto_queue)
01059 {
01060 struct goto_queue_node *q, *qe;
01061 tree return_val = NULL;
01062 int return_index, index;
01063 struct labels_s
01064 {
01065 struct goto_queue_node *q;
01066 tree label;
01067 } *labels;
01068
01069 return_index = VEC_length (tree, tf->dest_array);
01070 labels = XCNEWVEC (struct labels_s, return_index + 1);
01071
01072 q = tf->goto_queue;
01073 qe = q + tf->goto_queue_active;
01074 for (; q < qe; q++)
01075 {
01076 index = q->index < 0 ? return_index : q->index;
01077
01078 if (!labels[index].q)
01079 labels[index].q = q;
01080 }
01081
01082 for (index = 0; index < return_index + 1; index++)
01083 {
01084 tree lab;
01085
01086 q = labels[index].q;
01087 if (! q)
01088 continue;
01089
01090 lab = labels[index].label = create_artificial_label ();
01091
01092 if (index == return_index)
01093 do_return_redirection (q, lab, NULL, &return_val);
01094 else
01095 do_goto_redirection (q, lab, NULL);
01096
01097 x = build1 (LABEL_EXPR, void_type_node, lab);
01098 append_to_statement_list (x, &new_stmt);
01099
01100 x = lower_try_finally_dup_block (finally, state);
01101 lower_eh_constructs_1 (state, &x);
01102 append_to_statement_list (x, &new_stmt);
01103
01104 append_to_statement_list (q->cont_stmt, &new_stmt);
01105 maybe_record_in_goto_queue (state, q->cont_stmt);
01106 }
01107
01108 for (q = tf->goto_queue; q < qe; q++)
01109 {
01110 tree lab;
01111
01112 index = q->index < 0 ? return_index : q->index;
01113
01114 if (labels[index].q == q)
01115 continue;
01116
01117 lab = labels[index].label;
01118
01119 if (index == return_index)
01120 do_return_redirection (q, lab, NULL, &return_val);
01121 else
01122 do_goto_redirection (q, lab, NULL);
01123 }
01124
01125 replace_goto_queue (tf);
01126 free (labels);
01127 }
01128
01129
01130
01131 append_to_statement_list (new_stmt, tf->top_p);
01132 }
01133
01134
01135
01136
01137
01138
01139 static void
01140 lower_try_finally_switch (struct leh_state *state, struct leh_tf_state *tf)
01141 {
01142 struct goto_queue_node *q, *qe;
01143 tree return_val = NULL;
01144 tree finally, finally_tmp, finally_label;
01145 int return_index, eh_index, fallthru_index;
01146 int nlabels, ndests, j, last_case_index;
01147 tree case_label_vec, switch_stmt, last_case, switch_body;
01148 tree x;
01149
01150
01151 finally = TREE_OPERAND (*tf->top_p, 1);
01152 *tf->top_p = TREE_OPERAND (*tf->top_p, 0);
01153
01154
01155 lower_eh_constructs_1 (state, &finally);
01156
01157
01158 nlabels = VEC_length (tree, tf->dest_array);
01159 return_index = nlabels;
01160 eh_index = return_index + tf->may_return;
01161 fallthru_index = eh_index + tf->may_throw;
01162 ndests = fallthru_index + tf->may_fallthru;
01163
01164 finally_tmp = create_tmp_var (integer_type_node, "finally_tmp");
01165 finally_label = create_artificial_label ();
01166
01167 case_label_vec = make_tree_vec (ndests);
01168 switch_stmt = build3 (SWITCH_EXPR, integer_type_node, finally_tmp,
01169 NULL_TREE, case_label_vec);
01170 switch_body = NULL;
01171 last_case = NULL;
01172 last_case_index = 0;
01173
01174
01175
01176
01177
01178 if (tf->may_fallthru)
01179 {
01180 x = build2 (MODIFY_EXPR, void_type_node, finally_tmp,
01181 build_int_cst (NULL_TREE, fallthru_index));
01182 append_to_statement_list (x, tf->top_p);
01183
01184 if (tf->may_throw)
01185 {
01186 x = build1 (GOTO_EXPR, void_type_node, finally_label);
01187 append_to_statement_list (x, tf->top_p);
01188 }
01189
01190
01191 last_case = build3 (CASE_LABEL_EXPR, void_type_node,
01192 build_int_cst (NULL_TREE, fallthru_index), NULL,
01193 create_artificial_label ());
01194 TREE_VEC_ELT (case_label_vec, last_case_index) = last_case;
01195 last_case_index++;
01196
01197 x = build1 (LABEL_EXPR, void_type_node, CASE_LABEL (last_case));
01198 append_to_statement_list (x, &switch_body);
01199
01200 x = lower_try_finally_fallthru_label (tf);
01201 x = build1 (GOTO_EXPR, void_type_node, x);
01202 append_to_statement_list (x, &switch_body);
01203 }
01204
01205 if (tf->may_throw)
01206 {
01207 x = build1 (LABEL_EXPR, void_type_node, tf->eh_label);
01208 append_to_statement_list (x, tf->top_p);
01209
01210 x = build2 (MODIFY_EXPR, void_type_node, finally_tmp,
01211 build_int_cst (NULL_TREE, eh_index));
01212 append_to_statement_list (x, tf->top_p);
01213
01214 last_case = build3 (CASE_LABEL_EXPR, void_type_node,
01215 build_int_cst (NULL_TREE, eh_index), NULL,
01216 create_artificial_label ());
01217 TREE_VEC_ELT (case_label_vec, last_case_index) = last_case;
01218 last_case_index++;
01219
01220 x = build1 (LABEL_EXPR, void_type_node, CASE_LABEL (last_case));
01221 append_to_statement_list (x, &switch_body);
01222 x = build_resx (get_eh_region_number (tf->region));
01223 append_to_statement_list (x, &switch_body);
01224 }
01225
01226 x = build1 (LABEL_EXPR, void_type_node, finally_label);
01227 append_to_statement_list (x, tf->top_p);
01228
01229 append_to_statement_list (finally, tf->top_p);
01230
01231
01232 q = tf->goto_queue;
01233 qe = q + tf->goto_queue_active;
01234 j = last_case_index + tf->may_return;
01235 for (; q < qe; ++q)
01236 {
01237 tree mod;
01238 int switch_id, case_index;
01239
01240 if (q->index < 0)
01241 {
01242 mod = build2 (MODIFY_EXPR, void_type_node, finally_tmp,
01243 build_int_cst (NULL_TREE, return_index));
01244 do_return_redirection (q, finally_label, mod, &return_val);
01245 switch_id = return_index;
01246 }
01247 else
01248 {
01249 mod = build2 (MODIFY_EXPR, void_type_node, finally_tmp,
01250 build_int_cst (NULL_TREE, q->index));
01251 do_goto_redirection (q, finally_label, mod);
01252 switch_id = q->index;
01253 }
01254
01255 case_index = j + q->index;
01256 if (!TREE_VEC_ELT (case_label_vec, case_index))
01257 TREE_VEC_ELT (case_label_vec, case_index)
01258 = build3 (CASE_LABEL_EXPR, void_type_node,
01259 build_int_cst (NULL_TREE, switch_id), NULL,
01260
01261
01262
01263
01264
01265
01266 q->cont_stmt);
01267 }
01268 for (j = last_case_index; j < last_case_index + nlabels; j++)
01269 {
01270 tree label;
01271 tree cont_stmt;
01272
01273 last_case = TREE_VEC_ELT (case_label_vec, j);
01274
01275 gcc_assert (last_case);
01276
01277 cont_stmt = CASE_LABEL (last_case);
01278
01279 label = create_artificial_label ();
01280 CASE_LABEL (last_case) = label;
01281
01282 x = build1 (LABEL_EXPR, void_type_node, label);
01283 append_to_statement_list (x, &switch_body);
01284 append_to_statement_list (cont_stmt, &switch_body);
01285 maybe_record_in_goto_queue (state, cont_stmt);
01286 }
01287 replace_goto_queue (tf);
01288
01289
01290
01291 CASE_LOW (last_case) = NULL;
01292 sort_case_labels (case_label_vec);
01293
01294
01295
01296 append_to_statement_list (switch_stmt, tf->top_p);
01297 append_to_statement_list (switch_body, tf->top_p);
01298 }
01299
01300
01301
01302
01303
01304
01305
01306
01307
01308
01309
01310
01311
01312
01313
01314 static bool
01315 decide_copy_try_finally (int ndests, tree finally)
01316 {
01317 int f_estimate, sw_estimate;
01318
01319 if (!optimize)
01320 return false;
01321
01322
01323 f_estimate = estimate_num_insns (finally);
01324 f_estimate = (f_estimate + 1) * ndests;
01325
01326
01327 sw_estimate = 10 + 2 * ndests;
01328
01329
01330 if (optimize_size)
01331 return f_estimate < sw_estimate;
01332
01333
01334 if (optimize > 1)
01335 return f_estimate < 100 || f_estimate < sw_estimate * 2;
01336 else
01337 return f_estimate < 40 || f_estimate * 2 < sw_estimate * 3;
01338 }
01339
01340
01341
01342
01343
01344
01345 static void
01346 lower_try_finally (struct leh_state *state, tree *tp)
01347 {
01348 struct leh_tf_state this_tf;
01349 struct leh_state this_state;
01350 int ndests;
01351
01352
01353
01354 memset (&this_tf, 0, sizeof (this_tf));
01355 this_tf.try_finally_expr = *tp;
01356 this_tf.top_p = tp;
01357 this_tf.outer = state;
01358 if (using_eh_for_cleanups_p)
01359 this_tf.region
01360 = gen_eh_region_cleanup (state->cur_region, state->prev_try);
01361 else
01362 this_tf.region = NULL;
01363
01364 this_state.cur_region = this_tf.region;
01365 this_state.prev_try = state->prev_try;
01366 this_state.tf = &this_tf;
01367
01368 lower_eh_constructs_1 (&this_state, &TREE_OPERAND (*tp, 0));
01369
01370
01371 this_tf.may_fallthru = block_may_fallthru (TREE_OPERAND (*tp, 0));
01372
01373
01374 if (using_eh_for_cleanups_p)
01375 this_tf.may_throw = get_eh_region_may_contain_throw (this_tf.region);
01376 if (this_tf.may_throw)
01377 {
01378 this_tf.eh_label = create_artificial_label ();
01379 set_eh_region_tree_label (this_tf.region, this_tf.eh_label);
01380 honor_protect_cleanup_actions (state, &this_state, &this_tf);
01381 }
01382
01383
01384 if (this_tf.goto_queue_active > 1)
01385 qsort (this_tf.goto_queue, this_tf.goto_queue_active,
01386 sizeof (struct goto_queue_node), goto_queue_cmp);
01387
01388
01389
01390
01391
01392 ndests = VEC_length (tree, this_tf.dest_array);
01393 ndests += this_tf.may_fallthru;
01394 ndests += this_tf.may_return;
01395 ndests += this_tf.may_throw;
01396
01397
01398 if (ndests == 0)
01399 *tp = TREE_OPERAND (*tp, 0);
01400
01401
01402
01403
01404 else if (!block_may_fallthru (TREE_OPERAND (*tp, 1)))
01405 lower_try_finally_nofallthru (state, &this_tf);
01406
01407
01408 else if (ndests == 1)
01409 lower_try_finally_onedest (state, &this_tf);
01410
01411 else if (decide_copy_try_finally (ndests, TREE_OPERAND (*tp, 1)))
01412 lower_try_finally_copy (state, &this_tf);
01413 else
01414 lower_try_finally_switch (state, &this_tf);
01415
01416
01417
01418 if (this_tf.fallthru_label)
01419 {
01420 tree x = build1 (LABEL_EXPR, void_type_node, this_tf.fallthru_label);
01421 append_to_statement_list (x, tp);
01422 }
01423
01424 VEC_free (tree, heap, this_tf.dest_array);
01425 if (this_tf.goto_queue)
01426 free (this_tf.goto_queue);
01427 }
01428
01429
01430
01431
01432
01433 static void
01434 lower_catch (struct leh_state *state, tree *tp)
01435 {
01436 struct eh_region *try_region;
01437 struct leh_state this_state;
01438 tree_stmt_iterator i;
01439 tree out_label;
01440
01441 try_region = gen_eh_region_try (state->cur_region);
01442 this_state.cur_region = try_region;
01443 this_state.prev_try = try_region;
01444 this_state.tf = state->tf;
01445
01446 lower_eh_constructs_1 (&this_state, &TREE_OPERAND (*tp, 0));
01447
01448 if (!get_eh_region_may_contain_throw (try_region))
01449 {
01450 *tp = TREE_OPERAND (*tp, 0);
01451 return;
01452 }
01453
01454 out_label = NULL;
01455 for (i = tsi_start (TREE_OPERAND (*tp, 1)); !tsi_end_p (i); )
01456 {
01457 struct eh_region *catch_region;
01458 tree catch, x, eh_label;
01459
01460 catch = tsi_stmt (i);
01461 catch_region = gen_eh_region_catch (try_region, CATCH_TYPES (catch));
01462
01463 this_state.cur_region = catch_region;
01464 this_state.prev_try = state->prev_try;
01465 lower_eh_constructs_1 (&this_state, &CATCH_BODY (catch));
01466
01467 eh_label = create_artificial_label ();
01468 set_eh_region_tree_label (catch_region, eh_label);
01469
01470 x = build1 (LABEL_EXPR, void_type_node, eh_label);
01471 tsi_link_before (&i, x, TSI_SAME_STMT);
01472
01473 if (block_may_fallthru (CATCH_BODY (catch)))
01474 {
01475 if (!out_label)
01476 out_label = create_artificial_label ();
01477
01478 x = build1 (GOTO_EXPR, void_type_node, out_label);
01479 append_to_statement_list (x, &CATCH_BODY (catch));
01480 }
01481
01482 tsi_link_before (&i, CATCH_BODY (catch), TSI_SAME_STMT);
01483 tsi_delink (&i);
01484 }
01485
01486 frob_into_branch_around (tp, NULL, out_label);
01487 }
01488
01489
01490
01491
01492
01493 static void
01494 lower_eh_filter (struct leh_state *state, tree *tp)
01495 {
01496 struct leh_state this_state;
01497 struct eh_region *this_region;
01498 tree inner = expr_first (TREE_OPERAND (*tp, 1));
01499 tree eh_label;
01500
01501 if (EH_FILTER_MUST_NOT_THROW (inner))
01502 this_region = gen_eh_region_must_not_throw (state->cur_region);
01503 else
01504 this_region = gen_eh_region_allowed (state->cur_region,
01505 EH_FILTER_TYPES (inner));
01506 this_state = *state;
01507 this_state.cur_region = this_region;
01508
01509
01510 if (EH_FILTER_MUST_NOT_THROW (inner))
01511 this_state.prev_try = NULL;
01512
01513 lower_eh_constructs_1 (&this_state, &TREE_OPERAND (*tp, 0));
01514
01515 if (!get_eh_region_may_contain_throw (this_region))
01516 {
01517 *tp = TREE_OPERAND (*tp, 0);
01518 return;
01519 }
01520
01521 lower_eh_constructs_1 (state, &EH_FILTER_FAILURE (inner));
01522 TREE_OPERAND (*tp, 1) = EH_FILTER_FAILURE (inner);
01523
01524 eh_label = create_artificial_label ();
01525 set_eh_region_tree_label (this_region, eh_label);
01526
01527 frob_into_branch_around (tp, eh_label, NULL);
01528 }
01529
01530
01531
01532
01533 static void
01534 lower_cleanup (struct leh_state *state, tree *tp)
01535 {
01536 struct leh_state this_state;
01537 struct eh_region *this_region;
01538 struct leh_tf_state fake_tf;
01539
01540
01541 if (!flag_exceptions)
01542 {
01543 *tp = TREE_OPERAND (*tp, 0);
01544 lower_eh_constructs_1 (state, tp);
01545 return;
01546 }
01547
01548 this_region = gen_eh_region_cleanup (state->cur_region, state->prev_try);
01549 this_state = *state;
01550 this_state.cur_region = this_region;
01551
01552 lower_eh_constructs_1 (&this_state, &TREE_OPERAND (*tp, 0));
01553
01554 if (!get_eh_region_may_contain_throw (this_region))
01555 {
01556 *tp = TREE_OPERAND (*tp, 0);
01557 return;
01558 }
01559
01560
01561
01562 memset (&fake_tf, 0, sizeof (fake_tf));
01563 fake_tf.top_p = tp;
01564 fake_tf.outer = state;
01565 fake_tf.region = this_region;
01566 fake_tf.may_fallthru = block_may_fallthru (TREE_OPERAND (*tp, 0));
01567 fake_tf.may_throw = true;
01568
01569 fake_tf.eh_label = create_artificial_label ();
01570 set_eh_region_tree_label (this_region, fake_tf.eh_label);
01571
01572 honor_protect_cleanup_actions (state, NULL, &fake_tf);
01573
01574 if (fake_tf.may_throw)
01575 {
01576
01577
01578 lower_eh_constructs_1 (state, &TREE_OPERAND (*tp, 1));
01579 frob_into_branch_around (tp, fake_tf.eh_label, fake_tf.fallthru_label);
01580 }
01581 else
01582 {
01583
01584
01585
01586 *tp = TREE_OPERAND (*tp, 0);
01587 if (fake_tf.fallthru_label)
01588 {
01589 tree x = build1 (LABEL_EXPR, void_type_node, fake_tf.fallthru_label);
01590 append_to_statement_list (x, tp);
01591 }
01592 }
01593 }
01594
01595
01596
01597 static void
01598 lower_eh_constructs_1 (struct leh_state *state, tree *tp)
01599 {
01600 tree_stmt_iterator i;
01601 tree t = *tp;
01602
01603 switch (TREE_CODE (t))
01604 {
01605 case COND_EXPR:
01606 lower_eh_constructs_1 (state, &COND_EXPR_THEN (t));
01607 lower_eh_constructs_1 (state, &COND_EXPR_ELSE (t));
01608 break;
01609
01610 case CALL_EXPR:
01611
01612 if (state->cur_region && tree_could_throw_p (t))
01613 {
01614 record_stmt_eh_region (state->cur_region, t);
01615 note_eh_region_may_contain_throw (state->cur_region);
01616 }
01617 break;
01618
01619 case MODIFY_EXPR:
01620
01621 if (state->cur_region && tree_could_throw_p (t))
01622 {
01623 record_stmt_eh_region (state->cur_region, t);
01624 note_eh_region_may_contain_throw (state->cur_region);
01625 }
01626 break;
01627
01628 case GOTO_EXPR:
01629 case RETURN_EXPR:
01630 maybe_record_in_goto_queue (state, t);
01631 break;
01632 case SWITCH_EXPR:
01633 verify_norecord_switch_expr (state, t);
01634 break;
01635
01636 case TRY_FINALLY_EXPR:
01637 lower_try_finally (state, tp);
01638 break;
01639
01640 case TRY_CATCH_EXPR:
01641 i = tsi_start (TREE_OPERAND (t, 1));
01642 switch (TREE_CODE (tsi_stmt (i)))
01643 {
01644 case CATCH_EXPR:
01645 lower_catch (state, tp);
01646 break;
01647 case EH_FILTER_EXPR:
01648 lower_eh_filter (state, tp);
01649 break;
01650 default:
01651 lower_cleanup (state, tp);
01652 break;
01653 }
01654 break;
01655
01656 case STATEMENT_LIST:
01657 for (i = tsi_start (t); !tsi_end_p (i); )
01658 {
01659 lower_eh_constructs_1 (state, tsi_stmt_ptr (i));
01660 t = tsi_stmt (i);
01661 if (TREE_CODE (t) == STATEMENT_LIST)
01662 {
01663 tsi_link_before (&i, t, TSI_SAME_STMT);
01664 tsi_delink (&i);
01665 }
01666 else
01667 tsi_next (&i);
01668 }
01669 break;
01670
01671 default:
01672
01673
01674 break;
01675 }
01676 }
01677
01678 static unsigned int
01679 lower_eh_constructs (void)
01680 {
01681 struct leh_state null_state;
01682 tree *tp = &DECL_SAVED_TREE (current_function_decl);
01683
01684 finally_tree = htab_create (31, struct_ptr_hash, struct_ptr_eq, free);
01685
01686 collect_finally_tree (*tp, NULL);
01687
01688 memset (&null_state, 0, sizeof (null_state));
01689 lower_eh_constructs_1 (&null_state, tp);
01690
01691 htab_delete (finally_tree);
01692
01693 collect_eh_region_array ();
01694 return 0;
01695 }
01696
01697 struct tree_opt_pass pass_lower_eh =
01698 {
01699 "eh",
01700 NULL,
01701 lower_eh_constructs,
01702 NULL,
01703 NULL,
01704 0,
01705 TV_TREE_EH,
01706 PROP_gimple_lcf,
01707 PROP_gimple_leh,
01708 0,
01709 0,
01710 TODO_dump_func,
01711 0
01712 };
01713
01714
01715
01716
01717 static void
01718 make_eh_edge (struct eh_region *region, void *data)
01719 {
01720 tree stmt, lab;
01721 basic_block src, dst;
01722
01723 stmt = (tree) data;
01724 lab = get_eh_region_tree_label (region);
01725
01726 src = bb_for_stmt (stmt);
01727 dst = label_to_block (lab);
01728
01729 make_edge (src, dst, EDGE_ABNORMAL | EDGE_EH);
01730 }
01731
01732 void
01733 make_eh_edges (tree stmt)
01734 {
01735 int region_nr;
01736 bool is_resx;
01737
01738 if (TREE_CODE (stmt) == RESX_EXPR)
01739 {
01740 region_nr = TREE_INT_CST_LOW (TREE_OPERAND (stmt, 0));
01741 is_resx = true;
01742 }
01743 else
01744 {
01745 region_nr = lookup_stmt_eh_region (stmt);
01746 if (region_nr < 0)
01747 return;
01748 is_resx = false;
01749 }
01750
01751 foreach_reachable_handler (region_nr, is_resx, make_eh_edge, stmt);
01752 }
01753
01754 static bool mark_eh_edge_found_error;
01755
01756
01757
01758 static void
01759 mark_eh_edge (struct eh_region *region, void *data)
01760 {
01761 tree stmt, lab;
01762 basic_block src, dst;
01763 edge e;
01764
01765 stmt = (tree) data;
01766 lab = get_eh_region_tree_label (region);
01767
01768 src = bb_for_stmt (stmt);
01769 dst = label_to_block (lab);
01770
01771 e = find_edge (src, dst);
01772 if (!e)
01773 {
01774 error ("EH edge %i->%i is missing", src->index, dst->index);
01775 mark_eh_edge_found_error = true;
01776 }
01777 else if (!(e->flags & EDGE_EH))
01778 {
01779 error ("EH edge %i->%i miss EH flag", src->index, dst->index);
01780 mark_eh_edge_found_error = true;
01781 }
01782 else if (e->aux)
01783 {
01784
01785 error ("EH edge %i->%i has duplicated regions", src->index, dst->index);
01786 mark_eh_edge_found_error = true;
01787 }
01788 else
01789 e->aux = (void *)1;
01790 }
01791
01792
01793
01794 bool
01795 verify_eh_edges (tree stmt)
01796 {
01797 int region_nr;
01798 bool is_resx;
01799 basic_block bb = bb_for_stmt (stmt);
01800 edge_iterator ei;
01801 edge e;
01802
01803 FOR_EACH_EDGE (e, ei, bb->succs)
01804 gcc_assert (!e->aux);
01805 mark_eh_edge_found_error = false;
01806 if (TREE_CODE (stmt) == RESX_EXPR)
01807 {
01808 region_nr = TREE_INT_CST_LOW (TREE_OPERAND (stmt, 0));
01809 is_resx = true;
01810 }
01811 else
01812 {
01813 region_nr = lookup_stmt_eh_region (stmt);
01814 if (region_nr < 0)
01815 {
01816 FOR_EACH_EDGE (e, ei, bb->succs)
01817 if (e->flags & EDGE_EH)
01818 {
01819 error ("BB %i can not throw but has EH edges", bb->index);
01820 return true;
01821 }
01822 return false;
01823 }
01824 if (!tree_could_throw_p (stmt))
01825 {
01826 error ("BB %i last statement has incorrectly set region", bb->index);
01827 return true;
01828 }
01829 is_resx = false;
01830 }
01831
01832 foreach_reachable_handler (region_nr, is_resx, mark_eh_edge, stmt);
01833 FOR_EACH_EDGE (e, ei, bb->succs)
01834 {
01835 if ((e->flags & EDGE_EH) && !e->aux)
01836 {
01837 error ("unnecessary EH edge %i->%i", bb->index, e->dest->index);
01838 mark_eh_edge_found_error = true;
01839 return true;
01840 }
01841 e->aux = NULL;
01842 }
01843 return mark_eh_edge_found_error;
01844 }
01845
01846
01847
01848
01849
01850
01851 bool
01852 tree_could_trap_p (tree expr)
01853 {
01854 enum tree_code code = TREE_CODE (expr);
01855 bool honor_nans = false;
01856 bool honor_snans = false;
01857 bool fp_operation = false;
01858 bool honor_trapv = false;
01859 tree t, base;
01860
01861 if (TREE_CODE_CLASS (code) == tcc_comparison
01862 || TREE_CODE_CLASS (code) == tcc_unary
01863 || TREE_CODE_CLASS (code) == tcc_binary)
01864 {
01865 t = TREE_TYPE (expr);
01866 fp_operation = FLOAT_TYPE_P (t);
01867 if (fp_operation)
01868 {
01869 honor_nans = flag_trapping_math && !flag_finite_math_only;
01870 honor_snans = flag_signaling_nans != 0;
01871 }
01872 else if (INTEGRAL_TYPE_P (t) && TYPE_OVERFLOW_TRAPS (t))
01873 honor_trapv = true;
01874 }
01875
01876 restart:
01877 switch (code)
01878 {
01879 case TARGET_MEM_REF:
01880
01881
01882 expr = TMR_ORIGINAL (expr);
01883 code = TREE_CODE (expr);
01884 goto restart;
01885
01886 case COMPONENT_REF:
01887 case REALPART_EXPR:
01888 case IMAGPART_EXPR:
01889 case BIT_FIELD_REF:
01890 case VIEW_CONVERT_EXPR:
01891 case WITH_SIZE_EXPR:
01892 expr = TREE_OPERAND (expr, 0);
01893 code = TREE_CODE (expr);
01894 goto restart;
01895
01896 case ARRAY_RANGE_REF:
01897 base = TREE_OPERAND (expr, 0);
01898 if (tree_could_trap_p (base))
01899 return true;
01900
01901 if (TREE_THIS_NOTRAP (expr))
01902 return false;
01903
01904 return !range_in_array_bounds_p (expr);
01905
01906 case ARRAY_REF:
01907 base = TREE_OPERAND (expr, 0);
01908 if (tree_could_trap_p (base))
01909 return true;
01910
01911 if (TREE_THIS_NOTRAP (expr))
01912 return false;
01913
01914 return !in_array_bounds_p (expr);
01915
01916 case INDIRECT_REF:
01917 case ALIGN_INDIRECT_REF:
01918 case MISALIGNED_INDIRECT_REF:
01919 return !TREE_THIS_NOTRAP (expr);
01920
01921 case ASM_EXPR:
01922 return TREE_THIS_VOLATILE (expr);
01923
01924 case TRUNC_DIV_EXPR:
01925 case CEIL_DIV_EXPR:
01926 case FLOOR_DIV_EXPR:
01927 case ROUND_DIV_EXPR:
01928 case EXACT_DIV_EXPR:
01929 case CEIL_MOD_EXPR:
01930 case FLOOR_MOD_EXPR:
01931 case ROUND_MOD_EXPR:
01932 case TRUNC_MOD_EXPR:
01933 case RDIV_EXPR:
01934 if (honor_snans || honor_trapv)
01935 return true;
01936 if (fp_operation)
01937 return flag_trapping_math;
01938 t = TREE_OPERAND (expr, 1);
01939 if (!TREE_CONSTANT (t) || integer_zerop (t))
01940 return true;
01941 return false;
01942
01943 case LT_EXPR:
01944 case LE_EXPR:
01945 case GT_EXPR:
01946 case GE_EXPR:
01947 case LTGT_EXPR:
01948
01949 return honor_nans;
01950
01951 case EQ_EXPR:
01952 case NE_EXPR:
01953 case UNORDERED_EXPR:
01954 case ORDERED_EXPR:
01955 case UNLT_EXPR:
01956 case UNLE_EXPR:
01957 case UNGT_EXPR:
01958 case UNGE_EXPR:
01959 case UNEQ_EXPR:
01960 return honor_snans;
01961
01962 case CONVERT_EXPR:
01963 case FIX_TRUNC_EXPR:
01964 case FIX_CEIL_EXPR:
01965 case FIX_FLOOR_EXPR:
01966 case FIX_ROUND_EXPR:
01967
01968 return honor_nans;
01969
01970 case NEGATE_EXPR:
01971 case ABS_EXPR:
01972 case CONJ_EXPR:
01973
01974 if (honor_trapv)
01975 return true;
01976 return false;
01977
01978 case PLUS_EXPR:
01979 case MINUS_EXPR:
01980 case MULT_EXPR:
01981
01982 if (fp_operation && flag_trapping_math)
01983 return true;
01984 if (honor_trapv)
01985 return true;
01986 return false;
01987
01988 case CALL_EXPR:
01989 t = get_callee_fndecl (expr);
01990
01991 if (!t || !DECL_P (t) || DECL_WEAK (t))
01992 return true;
01993 return false;
01994
01995 default:
01996
01997 if (fp_operation && flag_trapping_math)
01998 return true;
01999 return false;
02000 }
02001 }
02002
02003 bool
02004 tree_could_throw_p (tree t)
02005 {
02006 if (!flag_exceptions)
02007 return false;
02008 if (TREE_CODE (t) == MODIFY_EXPR)
02009 {
02010 if (flag_non_call_exceptions
02011 && tree_could_trap_p (TREE_OPERAND (t, 0)))
02012 return true;
02013 t = TREE_OPERAND (t, 1);
02014 }
02015
02016 if (TREE_CODE (t) == WITH_SIZE_EXPR)
02017 t = TREE_OPERAND (t, 0);
02018 if (TREE_CODE (t) == CALL_EXPR)
02019 return (call_expr_flags (t) & ECF_NOTHROW) == 0;
02020 if (flag_non_call_exceptions)
02021 return tree_could_trap_p (t);
02022 return false;
02023 }
02024
02025 bool
02026 tree_can_throw_internal (tree stmt)
02027 {
02028 int region_nr;
02029 bool is_resx = false;
02030
02031 if (TREE_CODE (stmt) == RESX_EXPR)
02032 region_nr = TREE_INT_CST_LOW (TREE_OPERAND (stmt, 0)), is_resx = true;
02033 else
02034 region_nr = lookup_stmt_eh_region (stmt);
02035 if (region_nr < 0)
02036 return false;
02037 return can_throw_internal_1 (region_nr, is_resx);
02038 }
02039
02040 bool
02041 tree_can_throw_external (tree stmt)
02042 {
02043 int region_nr;
02044 bool is_resx = false;
02045
02046 if (TREE_CODE (stmt) == RESX_EXPR)
02047 region_nr = TREE_INT_CST_LOW (TREE_OPERAND (stmt, 0)), is_resx = true;
02048 else
02049 region_nr = lookup_stmt_eh_region (stmt);
02050 if (region_nr < 0)
02051 return tree_could_throw_p (stmt);
02052 else
02053 return can_throw_external_1 (region_nr, is_resx);
02054 }
02055
02056
02057
02058
02059
02060
02061 bool
02062 maybe_clean_or_replace_eh_stmt (tree old_stmt, tree new_stmt)
02063 {
02064 int region_nr = lookup_stmt_eh_region (old_stmt);
02065
02066 if (region_nr >= 0)
02067 {
02068 bool new_stmt_could_throw = tree_could_throw_p (new_stmt);
02069
02070 if (new_stmt == old_stmt && new_stmt_could_throw)
02071 return false;
02072
02073 remove_stmt_from_eh_region (old_stmt);
02074 if (new_stmt_could_throw)
02075 {
02076 add_stmt_to_eh_region (new_stmt, region_nr);
02077 return false;
02078 }
02079 else
02080 return true;
02081 }
02082
02083 return false;
02084 }
02085
02086 #ifdef ENABLE_CHECKING
02087 static int
02088 verify_eh_throw_stmt_node (void **slot, void *data ATTRIBUTE_UNUSED)
02089 {
02090 struct throw_stmt_node *node = (struct throw_stmt_node *)*slot;
02091
02092 gcc_assert (node->stmt->common.ann == NULL);
02093 return 1;
02094 }
02095
02096 void
02097 verify_eh_throw_table_statements (void)
02098 {
02099 if (!get_eh_throw_stmt_table (cfun))
02100 return;
02101 htab_traverse (get_eh_throw_stmt_table (cfun),
02102 verify_eh_throw_stmt_node,
02103 NULL);
02104 }
02105
02106 #endif