OSDN Git Service

* tree-eh.c (tree_could_trap_p): Remove idx.
[pf3gnuchains/gcc-fork.git] / gcc / tree-eh.c
index 42834e4..698c654 100644 (file)
@@ -1,5 +1,5 @@
 /* Exception handling semantics and decomposition for trees.
-   Copyright (C) 2003 Free Software Foundation, Inc.
+   Copyright (C) 2003, 2004, 2005 Free Software Foundation, Inc.
 
 This file is part of GCC.
 
@@ -77,7 +77,7 @@ struct_ptr_hash (const void *a)
    we get to rtl.  Once we're done with lowering here, if we lose
    the information there's no way to recover it!
 
-   (2) There are many more statements that *cannot* throw as 
+   (2) There are many more statements that *cannot* throw as
    compared to those that can.  We should be saving some amount
    of space by only allocating memory for those that can throw.  */
 
@@ -103,8 +103,7 @@ record_stmt_eh_region (struct eh_region *region, tree t)
   n->region_nr = get_eh_region_number (region);
 
   slot = htab_find_slot (throw_stmt_table, n, INSERT);
-  if (*slot)
-    abort ();
+  gcc_assert (!*slot);
   *slot = n;
 }
 
@@ -114,16 +113,14 @@ add_stmt_to_eh_region (tree t, int num)
   struct throw_stmt_node *n;
   void **slot;
 
-  if (num < 0)
-    abort ();
+  gcc_assert (num >= 0);
 
   n = ggc_alloc (sizeof (*n));
   n->stmt = t;
   n->region_nr = num;
 
   slot = htab_find_slot (throw_stmt_table, n, INSERT);
-  if (*slot)
-    abort ();
+  gcc_assert (!*slot);
   *slot = n;
 }
 
@@ -186,8 +183,7 @@ record_in_finally_tree (tree child, tree parent)
   n->parent = parent;
 
   slot = htab_find_slot (finally_tree, n, INSERT);
-  if (*slot)
-    abort ();
+  gcc_assert (!*slot);
   *slot = n;
 }
 
@@ -265,7 +261,7 @@ outside_finally_tree (tree start, tree target)
 
 struct leh_state
 {
-  /* What's "current" while constructing the eh region tree.  These 
+  /* What's "current" while constructing the eh region tree.  These
      correspond to variables of the same name in cfun->eh, which we
      don't have easy access to.  */
   struct eh_region *cur_region;
@@ -280,7 +276,7 @@ struct leh_state
 struct leh_tf_state
 {
   /* Pointer to the TRY_FINALLY node under discussion.  The try_finally_expr
-     is the original TRY_FINALLY_EXPR.  We need to retain this so that 
+     is the original TRY_FINALLY_EXPR.  We need to retain this so that
      outside_finally_tree can reliably reference the tree used in the
      collect_finally_tree data structures.  */
   tree try_finally_expr;
@@ -311,7 +307,7 @@ struct leh_tf_state
      though subsequent transformations may have cleared that flag.  */
   tree fallthru_label;
 
-  /* A label that has been registered with except.c to be the 
+  /* A label that has been registered with except.c to be the
      landing pad for this try block.  */
   tree eh_label;
 
@@ -330,7 +326,7 @@ struct leh_tf_state
 static void lower_eh_filter (struct leh_state *, tree *);
 static void lower_eh_constructs_1 (struct leh_state *, tree *);
 
-/* Comparison function for qsort/bsearch.  We're interested in 
+/* Comparison function for qsort/bsearch.  We're interested in
    searching goto queue elements for source statements.  */
 
 static int
@@ -383,7 +379,7 @@ replace_goto_queue_cond_clause (tree *tp, struct leh_tf_state *tf,
   tsi_link_after (tsi, new, TSI_CONTINUE_LINKING);
 }
 
-/* The real work of replace_goto_queue.  Returns with TSI updated to 
+/* The real work of replace_goto_queue.  Returns with TSI updated to
    point to the next statement.  */
 
 static void replace_goto_queue_stmt_list (tree, struct leh_tf_state *);
@@ -422,7 +418,7 @@ replace_goto_queue_1 (tree t, struct leh_tf_state *tf, tree_stmt_iterator *tsi)
       break;
 
     case STATEMENT_LIST:
-      abort ();
+      gcc_unreachable ();
 
     default:
       /* These won't have gotos in them.  */
@@ -447,6 +443,8 @@ replace_goto_queue_stmt_list (tree t, struct leh_tf_state *tf)
 static void
 replace_goto_queue (struct leh_tf_state *tf)
 {
+  if (tf->goto_queue_active == 0)
+    return;
   replace_goto_queue_stmt_list (*tf->top_p, tf);
 }
 
@@ -471,7 +469,7 @@ maybe_record_in_goto_queue (struct leh_state *state, tree stmt)
       {
        tree lab = GOTO_DESTINATION (stmt);
 
-       /* Computed and non-local gotos do not get processed.  Given 
+       /* Computed and non-local gotos do not get processed.  Given
           their nature we can neither tell whether we've escaped the
           finally block nor redirect them if we knew.  */
        if (TREE_CODE (lab) != LABEL_DECL)
@@ -480,7 +478,7 @@ maybe_record_in_goto_queue (struct leh_state *state, tree stmt)
        /* No need to record gotos that don't leave the try block.  */
        if (! outside_finally_tree (lab, tf->try_finally_expr))
          return;
-  
+
        if (! tf->dest_array)
          {
            VARRAY_TREE_INIT (tf->dest_array, 10, "dest_array");
@@ -505,7 +503,7 @@ maybe_record_in_goto_queue (struct leh_state *state, tree stmt)
       break;
 
     default:
-      abort ();
+      gcc_unreachable ();
     }
 
   active = tf->goto_queue_active;
@@ -520,7 +518,7 @@ maybe_record_in_goto_queue (struct leh_state *state, tree stmt)
 
   q = &tf->goto_queue[active];
   tf->goto_queue_active = active + 1;
-  
+
   memset (q, 0, sizeof (*q));
   q->stmt = stmt;
   q->index = index;
@@ -547,8 +545,7 @@ verify_norecord_switch_expr (struct leh_state *state, tree switch_expr)
   for (i = 0; i < n; ++i)
     {
       tree lab = CASE_LABEL (TREE_VEC_ELT (vec, i));
-      if (outside_finally_tree (lab, tf->try_finally_expr))
-       abort ();
+      gcc_assert (!outside_finally_tree (lab, tf->try_finally_expr));
     }
 }
 #else
@@ -591,47 +588,51 @@ do_return_redirection (struct goto_queue_node *q, tree finlab, tree mod,
          depends, I guess, but it does make generation of the switch in
          lower_try_finally_switch easier.  */
 
-      if (TREE_CODE (ret_expr) == RESULT_DECL)
+      switch (TREE_CODE (ret_expr))
        {
+       case RESULT_DECL:
          if (!*return_value_p)
            *return_value_p = ret_expr;
-         else if (*return_value_p != ret_expr)
-           abort ();
-          q->cont_stmt = q->stmt;
-       }
-      else if (TREE_CODE (ret_expr) == MODIFY_EXPR)
-       {
-         tree result = TREE_OPERAND (ret_expr, 0);
-         tree new, old = TREE_OPERAND (ret_expr, 1);
-
-         if (!*return_value_p)
-           {
-             if (aggregate_value_p (TREE_TYPE (result),
-                                    TREE_TYPE (current_function_decl)))
-               /* If this function returns in memory, copy the argument
-                  into the return slot now.  Otherwise, we might need to
-                  worry about magic return semantics, so we need to use a
-                  temporary to hold the value until we're actually ready
-                  to return.  */
-               new = result;
-             else
-               new = create_tmp_var (TREE_TYPE (old), "rettmp");
-             *return_value_p = new;
-           }
          else
-           new = *return_value_p;
+           gcc_assert (*return_value_p == ret_expr);
+         q->cont_stmt = q->stmt;
+         break;
 
-         x = build (MODIFY_EXPR, TREE_TYPE (new), new, old);
-         append_to_statement_list (x, &q->repl_stmt);
+       case MODIFY_EXPR:
+         {
+           tree result = TREE_OPERAND (ret_expr, 0);
+           tree new, old = TREE_OPERAND (ret_expr, 1);
+
+           if (!*return_value_p)
+             {
+               if (aggregate_value_p (TREE_TYPE (result),
+                                     TREE_TYPE (current_function_decl)))
+                 /* If this function returns in memory, copy the argument
+                   into the return slot now.  Otherwise, we might need to
+                   worry about magic return semantics, so we need to use a
+                   temporary to hold the value until we're actually ready
+                   to return.  */
+                 new = result;
+               else
+                 new = create_tmp_var (TREE_TYPE (old), "rettmp");
+               *return_value_p = new;
+             }
+           else
+             new = *return_value_p;
+
+           x = build (MODIFY_EXPR, TREE_TYPE (new), new, old);
+           append_to_statement_list (x, &q->repl_stmt);
+
+           if (new == result)
+             x = result;
+           else
+             x = build (MODIFY_EXPR, TREE_TYPE (result), result, new);
+           q->cont_stmt = build1 (RETURN_EXPR, void_type_node, x);
+         }
 
-         if (new == result)
-           x = result;
-         else
-           x = build (MODIFY_EXPR, TREE_TYPE (result), result, new);
-         q->cont_stmt = build1 (RETURN_EXPR, void_type_node, x);
+       default:
+         gcc_unreachable ();
        }
-      else
-       abort ();
     }
   else
     {
@@ -709,7 +710,7 @@ lower_try_finally_dup_block (tree t, struct leh_state *outer_state)
 {
   tree region = NULL;
 
-  t = lhd_unsave_expr_now (t);
+  t = unsave_expr_now (t);
 
   if (outer_state->tf)
     region = outer_state->tf->try_finally_expr;
@@ -731,7 +732,7 @@ lower_try_finally_fallthru_label (struct leh_tf_state *tf)
       label = create_artificial_label ();
       tf->fallthru_label = label;
       if (tf->outer->tf)
-        record_in_finally_tree (label, tf->outer->tf->try_finally_expr); 
+        record_in_finally_tree (label, tf->outer->tf->try_finally_expr);
     }
   return label;
 }
@@ -752,9 +753,9 @@ lower_try_finally_fallthru_label (struct leh_tf_state *tf)
 
    where "fintmp" is the temporary used in the switch statement generation
    alternative considered below.  For the nonce, we always choose the first
-   option. 
+   option.
 
-   THIS_STATE may be null if if this is a try-cleanup, not a try-finally.  */
+   THIS_STATE may be null if this is a try-cleanup, not a try-finally.  */
 
 static void
 honor_protect_cleanup_actions (struct leh_state *outer_state,
@@ -832,7 +833,8 @@ honor_protect_cleanup_actions (struct leh_state *outer_state,
       tsi_link_after (&i, x, TSI_CONTINUE_LINKING);
 
       x = build1 (RESX_EXPR, void_type_node,
-                 build_int_2 (get_eh_region_number (tf->region), 0));
+                 build_int_cst (NULL_TREE,
+                                get_eh_region_number (tf->region)));
       tsi_link_after (&i, x, TSI_CONTINUE_LINKING);
     }
 
@@ -936,9 +938,10 @@ lower_try_finally_onedest (struct leh_state *state, struct leh_tf_state *tf)
       append_to_statement_list (x, tf->top_p);
 
       append_to_statement_list (finally, tf->top_p);
-      
+
       x = build1 (RESX_EXPR, void_type_node,
-                 build_int_2 (get_eh_region_number (tf->region), 0));
+                 build_int_cst (NULL_TREE,
+                                get_eh_region_number (tf->region)));
       append_to_statement_list (x, tf->top_p);
 
       return;
@@ -975,7 +978,7 @@ lower_try_finally_onedest (struct leh_state *state, struct leh_tf_state *tf)
       for (; q < qe; ++q)
        do_goto_redirection (q, finally_label, NULL);
       replace_goto_queue (tf);
-      
+
       if (VARRAY_TREE (tf->dest_array, 0) == tf->fallthru_label)
        {
          /* Reachable by goto to fallthru label only.  Redirect it
@@ -1026,7 +1029,8 @@ lower_try_finally_copy (struct leh_state *state, struct leh_tf_state *tf)
       append_to_statement_list (x, &new_stmt);
 
       x = build1 (RESX_EXPR, void_type_node,
-                 build_int_2 (get_eh_region_number (tf->region), 0));
+                 build_int_cst (NULL_TREE,
+                                get_eh_region_number (tf->region)));
       append_to_statement_list (x, &new_stmt);
     }
 
@@ -1134,7 +1138,7 @@ lower_try_finally_switch (struct leh_state *state, struct leh_tf_state *tf)
   if (tf->may_fallthru)
     {
       x = build (MODIFY_EXPR, void_type_node, finally_tmp,
-                build_int_2 (fallthru_index, 0));
+                build_int_cst (NULL_TREE, fallthru_index));
       append_to_statement_list (x, tf->top_p);
 
       if (tf->may_throw)
@@ -1145,7 +1149,7 @@ lower_try_finally_switch (struct leh_state *state, struct leh_tf_state *tf)
 
 
       last_case = build (CASE_LABEL_EXPR, void_type_node,
-                        build_int_2 (fallthru_index, 0), NULL,
+                        build_int_cst (NULL_TREE, fallthru_index), NULL,
                         create_artificial_label ());
       TREE_VEC_ELT (case_label_vec, last_case_index) = last_case;
       last_case_index++;
@@ -1164,11 +1168,11 @@ lower_try_finally_switch (struct leh_state *state, struct leh_tf_state *tf)
       append_to_statement_list (x, tf->top_p);
 
       x = build (MODIFY_EXPR, void_type_node, finally_tmp,
-                build_int_2 (eh_index, 0));
+                build_int_cst (NULL_TREE, eh_index));
       append_to_statement_list (x, tf->top_p);
 
       last_case = build (CASE_LABEL_EXPR, void_type_node,
-                        build_int_2 (eh_index, 0), NULL,
+                        build_int_cst (NULL_TREE, eh_index), NULL,
                         create_artificial_label ());
       TREE_VEC_ELT (case_label_vec, last_case_index) = last_case;
       last_case_index++;
@@ -1176,7 +1180,8 @@ lower_try_finally_switch (struct leh_state *state, struct leh_tf_state *tf)
       x = build (LABEL_EXPR, void_type_node, CASE_LABEL (last_case));
       append_to_statement_list (x, &switch_body);
       x = build1 (RESX_EXPR, void_type_node,
-                 build_int_2 (get_eh_region_number (tf->region), 0));
+                 build_int_cst (NULL_TREE,
+                                get_eh_region_number (tf->region)));
       append_to_statement_list (x, &switch_body);
     }
 
@@ -1198,14 +1203,14 @@ lower_try_finally_switch (struct leh_state *state, struct leh_tf_state *tf)
       if (q->index < 0)
        {
          mod = build (MODIFY_EXPR, void_type_node, finally_tmp,
-                      build_int_2 (return_index, 0));
+                      build_int_cst (NULL_TREE, return_index));
          do_return_redirection (q, finally_label, mod, &return_val);
          switch_id = return_index;
        }
       else
        {
          mod = build (MODIFY_EXPR, void_type_node, finally_tmp,
-                      build_int_2 (q->index, 0));
+                      build_int_cst (NULL_TREE, q->index));
          do_goto_redirection (q, finally_label, mod);
          switch_id = q->index;
        }
@@ -1214,7 +1219,7 @@ lower_try_finally_switch (struct leh_state *state, struct leh_tf_state *tf)
       if (!TREE_VEC_ELT (case_label_vec, case_index))
        {
          last_case = build (CASE_LABEL_EXPR, void_type_node,
-                            build_int_2 (switch_id, 0), NULL,
+                            build_int_cst (NULL_TREE, switch_id), NULL,
                             create_artificial_label ());
          TREE_VEC_ELT (case_label_vec, case_index) = last_case;
 
@@ -1280,7 +1285,7 @@ decide_copy_try_finally (int ndests, tree finally)
 
 /* A subroutine of lower_eh_constructs_1.  Lower a TRY_FINALLY_EXPR nodes
    to a sequence of labels and blocks, plus the exception region trees
-   that record all the magic.  This is complicated by the need to 
+   that record all the magic.  This is complicated by the need to
    arrange for the FINALLY block to be executed on all exits.  */
 
 static void
@@ -1370,7 +1375,7 @@ lower_try_finally (struct leh_state *state, tree *tp)
 }
 
 /* A subroutine of lower_eh_constructs_1.  Lower a TRY_CATCH_EXPR with a
-   list of CATCH_EXPR nodes to a sequence of labels and blocks, plus the 
+   list of CATCH_EXPR nodes to a sequence of labels and blocks, plus the
    exception region trees that record all the magic.  */
 
 static void
@@ -1440,7 +1445,7 @@ lower_eh_filter (struct leh_state *state, tree *tp)
   struct eh_region *this_region;
   tree inner = expr_first (TREE_OPERAND (*tp, 1));
   tree eh_label;
-  
+
   if (EH_FILTER_MUST_NOT_THROW (inner))
     this_region = gen_eh_region_must_not_throw (state->cur_region);
   else
@@ -1448,7 +1453,7 @@ lower_eh_filter (struct leh_state *state, tree *tp)
                                         EH_FILTER_TYPES (inner));
   this_state = *state;
   this_state.cur_region = this_region;
-  
+
   lower_eh_constructs_1 (&this_state, &TREE_OPERAND (*tp, 0));
 
   if (!get_eh_region_may_contain_throw (this_region))
@@ -1564,7 +1569,7 @@ lower_eh_constructs_1 (struct leh_state *state, tree *tp)
          record_stmt_eh_region (state->cur_region, t);
          note_eh_region_may_contain_throw (state->cur_region);
 
-         /* ??? For the benefit of calls.c, converting all this to rtl, 
+         /* ??? For the benefit of calls.c, converting all this to rtl,
             we need to record the call expression, not just the outer
             modify statement.  */
          op = get_call_expr_in (t);
@@ -1643,7 +1648,7 @@ lower_eh_constructs (void)
   collect_eh_region_array ();
 }
 
-struct tree_opt_pass pass_lower_eh = 
+struct tree_opt_pass pass_lower_eh =
 {
   "eh",                                        /* name */
   NULL,                                        /* gate */
@@ -1656,7 +1661,8 @@ struct tree_opt_pass pass_lower_eh =
   PROP_gimple_leh,                     /* properties_provided */
   PROP_gimple_lcf,                     /* properties_destroyed */
   0,                                   /* todo_flags_start */
-  TODO_dump_func                       /* todo_flags_finish */
+  TODO_dump_func,                      /* todo_flags_finish */
+  0                                    /* letter */
 };
 
 \f
@@ -1676,7 +1682,7 @@ make_eh_edge (struct eh_region *region, void *data)
 
   make_edge (src, dst, EDGE_ABNORMAL | EDGE_EH);
 }
-  
+
 void
 make_eh_edges (tree stmt)
 {
@@ -1713,11 +1719,11 @@ tree_could_trap_p (tree expr)
   bool honor_snans = false;
   bool fp_operation = false;
   bool honor_trapv = false;
-  tree t, base, idx;
+  tree t, base;
 
-  if (TREE_CODE_CLASS (code) == '<'
-      || TREE_CODE_CLASS (code) == '1'
-      || TREE_CODE_CLASS (code) == '2')
+  if (TREE_CODE_CLASS (code) == tcc_comparison
+      || TREE_CODE_CLASS (code) == tcc_unary
+      || TREE_CODE_CLASS (code) == tcc_binary)
     {
       t = TREE_TYPE (expr);
       fp_operation = FLOAT_TYPE_P (t);
@@ -1753,7 +1759,6 @@ tree_could_trap_p (tree expr)
 
     case ARRAY_REF:
       base = TREE_OPERAND (expr, 0);
-      idx = TREE_OPERAND (expr, 1);
       if (tree_could_trap_p (base))
        return true;
 
@@ -1763,6 +1768,8 @@ tree_could_trap_p (tree expr)
       return !in_array_bounds_p (expr);
 
     case INDIRECT_REF:
+    case ALIGN_INDIRECT_REF:
+    case MISALIGNED_INDIRECT_REF:
       return !TREE_THIS_NOTRAP (expr);
 
     case ASM_EXPR:
@@ -1832,6 +1839,13 @@ tree_could_trap_p (tree expr)
        return true;
       return false;
 
+    case CALL_EXPR:
+      t = get_callee_fndecl (expr);
+      /* Assume that calls to weak functions may trap.  */
+      if (!t || !DECL_P (t) || DECL_WEAK (t))
+       return true;
+      return false;
+
     default:
       /* Any floating arithmetic may trap.  */
       if (fp_operation && flag_trapping_math)