OSDN Git Service

Fix another mips typo.
[pf3gnuchains/gcc-fork.git] / gcc / tree-eh.c
index 21c3a1c..a231f29 100644 (file)
@@ -37,8 +37,15 @@ Boston, MA 02111-1307, USA.  */
 #include "langhooks.h"
 #include "ggc.h"
 
-/* HACK */
-extern int using_eh_for_cleanups_p;
+\f
+/* Nonzero if we are using EH to handle cleanups.  */
+static int using_eh_for_cleanups_p = 0;
+
+void
+using_eh_for_cleanups (void)
+{
+  using_eh_for_cleanups_p = 1;
+}
 \f
 /* Misc functions used in this file.  */
 
@@ -119,7 +126,27 @@ add_stmt_to_eh_region (tree t, int num)
     abort ();
   *slot = n;
 }
-  
+
+bool
+remove_stmt_from_eh_region (tree t)
+{
+  struct throw_stmt_node dummy;
+  void **slot;
+
+  if (!throw_stmt_table)
+    return false;
+
+  dummy.stmt = t;
+  slot = htab_find_slot (throw_stmt_table, &dummy, NO_INSERT);
+  if (slot)
+    {
+      htab_clear_slot (throw_stmt_table, slot);
+      return true;
+    }
+  else
+    return false;
+}
+
 int
 lookup_stmt_eh_region (tree t)
 {
@@ -805,7 +832,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), 0));
       tsi_link_after (&i, x, TSI_CONTINUE_LINKING);
     }
 
@@ -911,7 +939,8 @@ lower_try_finally_onedest (struct leh_state *state, struct leh_tf_state *tf)
       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), 0));
       append_to_statement_list (x, tf->top_p);
 
       return;
@@ -999,7 +1028,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), 0));
       append_to_statement_list (x, &new_stmt);
     }
 
@@ -1107,7 +1137,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, 0));
       append_to_statement_list (x, tf->top_p);
 
       if (tf->may_throw)
@@ -1118,7 +1148,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, 0), NULL,
                         create_artificial_label ());
       TREE_VEC_ELT (case_label_vec, last_case_index) = last_case;
       last_case_index++;
@@ -1137,11 +1167,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, 0));
       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, 0), NULL,
                         create_artificial_label ());
       TREE_VEC_ELT (case_label_vec, last_case_index) = last_case;
       last_case_index++;
@@ -1149,7 +1179,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), 0));
       append_to_statement_list (x, &switch_body);
     }
 
@@ -1171,14 +1202,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, 0));
          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, 0));
          do_goto_redirection (q, finally_label, mod);
          switch_id = q->index;
        }
@@ -1187,7 +1218,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, 0), NULL,
                             create_artificial_label ());
          TREE_VEC_ELT (case_label_vec, case_index) = last_case;
 
@@ -1532,14 +1563,17 @@ lower_eh_constructs_1 (struct leh_state *state, tree *tp)
       /* Look for things that can throw exceptions, and record them.  */
       if (state->cur_region && tree_could_throw_p (t))
        {
+         tree op;
+
          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, 
             we need to record the call expression, not just the outer
             modify statement.  */
-         if (TREE_CODE (TREE_OPERAND (t, 1)) == CALL_EXPR)
-           record_stmt_eh_region (state->cur_region, TREE_OPERAND (t, 1));
+         op = get_call_expr_in (t);
+         if (op)
+           record_stmt_eh_region (state->cur_region, op);
        }
       break;
 
@@ -1600,7 +1634,8 @@ lower_eh_constructs (void)
   tree *tp = &DECL_SAVED_TREE (current_function_decl);
 
   finally_tree = htab_create (31, struct_ptr_hash, struct_ptr_eq, free);
-  throw_stmt_table = htab_create_ggc (31, struct_ptr_hash, struct_ptr_eq, free);
+  throw_stmt_table = htab_create_ggc (31, struct_ptr_hash, struct_ptr_eq,
+                                     ggc_free);
 
   collect_finally_tree (*tp, NULL);
 
@@ -1670,27 +1705,73 @@ make_eh_edges (tree stmt)
 
 
 \f
-/* Return true if the expr can trap, as in dereferencing an
-   invalid pointer location.  */
+/* Return true if the expr can trap, as in dereferencing an invalid pointer
+   location or floating point arithmetic.  C.f. the rtl version, may_trap_p.
+   This routine expects only GIMPLE lhs or rhs input.  */
 
 bool
 tree_could_trap_p (tree expr)
 {
   enum tree_code code = TREE_CODE (expr);
-  tree t;
+  bool honor_nans = false;
+  bool honor_snans = false;
+  bool fp_operation = false;
+  bool honor_trapv = false;
+  tree t, base, idx;
+
+  if (TREE_CODE_CLASS (code) == '<'
+      || TREE_CODE_CLASS (code) == '1'
+      || TREE_CODE_CLASS (code) == '2')
+    {
+      t = TREE_TYPE (expr);
+      fp_operation = FLOAT_TYPE_P (t);
+      if (fp_operation)
+       {
+         honor_nans = flag_trapping_math && !flag_finite_math_only;
+         honor_snans = flag_signaling_nans != 0;
+       }
+      else if (INTEGRAL_TYPE_P (t) && TYPE_TRAP_SIGNED (t))
+       honor_trapv = true;
+    }
 
+ restart:
   switch (code)
     {
-    case ARRAY_REF:
-    case ARRAY_RANGE_REF:
     case COMPONENT_REF:
     case REALPART_EXPR:
     case IMAGPART_EXPR:
     case BIT_FIELD_REF:
-      t = get_base_address (expr);
-      return !t || TREE_CODE (t) == INDIRECT_REF;
+    case WITH_SIZE_EXPR:
+      expr = TREE_OPERAND (expr, 0);
+      code = TREE_CODE (expr);
+      goto restart;
+
+    case ARRAY_RANGE_REF:
+      /* Let us be conservative here for now.  We might be checking bounds of
+        the access similarly to the case below.  */
+      if (!TREE_THIS_NOTRAP (expr))
+       return true;
+
+      base = TREE_OPERAND (expr, 0);
+      return tree_could_trap_p (base);
+
+    case ARRAY_REF:
+      base = TREE_OPERAND (expr, 0);
+      idx = TREE_OPERAND (expr, 1);
+      if (tree_could_trap_p (base))
+       return true;
+
+      if (TREE_THIS_NOTRAP (expr))
+       return false;
+
+      return !in_array_bounds_p (expr);
 
     case INDIRECT_REF:
+      return !TREE_THIS_NOTRAP (expr);
+
+    case ASM_EXPR:
+      return TREE_THIS_VOLATILE (expr);
+
     case TRUNC_DIV_EXPR:
     case CEIL_DIV_EXPR:
     case FLOOR_DIV_EXPR:
@@ -1700,16 +1781,69 @@ tree_could_trap_p (tree expr)
     case FLOOR_MOD_EXPR:
     case ROUND_MOD_EXPR:
     case TRUNC_MOD_EXPR:
-      return true;
+    case RDIV_EXPR:
+      if (honor_snans || honor_trapv)
+       return true;
+      if (fp_operation && flag_trapping_math)
+       return true;
+      t = TREE_OPERAND (expr, 1);
+      if (!TREE_CONSTANT (t) || integer_zerop (t))
+        return true;
+      return false;
+
+    case LT_EXPR:
+    case LE_EXPR:
+    case GT_EXPR:
+    case GE_EXPR:
+    case LTGT_EXPR:
+      /* Some floating point comparisons may trap.  */
+      return honor_nans;
+
+    case EQ_EXPR:
+    case NE_EXPR:
+    case UNORDERED_EXPR:
+    case ORDERED_EXPR:
+    case UNLT_EXPR:
+    case UNLE_EXPR:
+    case UNGT_EXPR:
+    case UNGE_EXPR:
+    case UNEQ_EXPR:
+      return honor_snans;
+
+    case CONVERT_EXPR:
+    case FIX_TRUNC_EXPR:
+    case FIX_CEIL_EXPR:
+    case FIX_FLOOR_EXPR:
+    case FIX_ROUND_EXPR:
+      /* Conversion of floating point might trap.  */
+      return honor_nans;
+
+    case NEGATE_EXPR:
+    case ABS_EXPR:
+    case CONJ_EXPR:
+      /* These operations don't trap with floating point.  */
+      if (honor_trapv)
+       return true;
+      return false;
+
+    case PLUS_EXPR:
+    case MINUS_EXPR:
+    case MULT_EXPR:
+      /* Any floating arithmetic may trap.  */
+      if (fp_operation && flag_trapping_math)
+       return true;
+      if (honor_trapv)
+       return true;
+      return false;
 
     default:
-      break;
+      /* Any floating arithmetic may trap.  */
+      if (fp_operation && flag_trapping_math)
+       return true;
+      return false;
     }
-
-  return false;
 }
 
-
 bool
 tree_could_throw_p (tree t)
 {
@@ -1723,6 +1857,8 @@ tree_could_throw_p (tree t)
       t = TREE_OPERAND (t, 1);
     }
 
+  if (TREE_CODE (t) == WITH_SIZE_EXPR)
+    t = TREE_OPERAND (t, 0);
   if (TREE_CODE (t) == CALL_EXPR)
     return (call_expr_flags (t) & ECF_NOTHROW) == 0;
   if (flag_non_call_exceptions)
@@ -1748,4 +1884,13 @@ tree_can_throw_external (tree stmt)
   return can_throw_external_1 (region_nr);
 }
 
+bool
+maybe_clean_eh_stmt (tree stmt)
+{
+  if (!tree_could_throw_p (stmt))
+    if (remove_stmt_from_eh_region (stmt))
+      return true;
+  return false;
+}
+
 #include "gt-tree-eh.h"