OSDN Git Service

* expmed.c (emit_store_flag): Also special-case double-word
[pf3gnuchains/gcc-fork.git] / gcc / tree-cfg.c
index ca8afed..8600a99 100644 (file)
@@ -666,7 +666,11 @@ make_goto_expr_edges (basic_block bb)
       if (simple_goto_p (goto_t))
        {
          edge e = make_edge (bb, label_to_block (dest), EDGE_FALLTHRU);
+#ifdef USE_MAPPED_LOCATION
+         e->goto_locus = EXPR_LOCATION (goto_t);
+#else
          e->goto_locus = EXPR_LOCUS (goto_t);
+#endif
          bsi_remove (&last);
          return;
        }
@@ -933,6 +937,7 @@ group_case_labels (void)
          tree labels = SWITCH_LABELS (stmt);
          int old_size = TREE_VEC_LENGTH (labels);
          int i, j, new_size = old_size;
+         tree default_label = TREE_VEC_ELT (labels, old_size - 1);
 
          /* Look for possible opportunities to merge cases.
             Ignore the last element of the label vector because it
@@ -946,8 +951,18 @@ group_case_labels (void)
              if (! base_case)
                abort ();
 
-             type = TREE_TYPE (CASE_LOW (base_case));
              base_label = CASE_LABEL (base_case);
+
+             /* Discard cases that have the same destination as the
+                default case.  */
+             if (base_label == default_label)
+               {
+                 TREE_VEC_ELT (labels, i) = NULL_TREE;
+                 i++;
+                 continue;
+               }
+
+             type = TREE_TYPE (CASE_LOW (base_case));
              base_high = CASE_HIGH (base_case) ?
                CASE_HIGH (base_case) : CASE_LOW (base_case);
 
@@ -1115,9 +1130,10 @@ static void remove_useless_stmts_1 (tree *, struct rus_data *);
 static bool
 remove_useless_stmts_warn_notreached (tree stmt)
 {
-  if (EXPR_LOCUS (stmt))
+  if (EXPR_HAS_LOCATION (stmt))
     {
-      warning ("%Hwill never be executed", EXPR_LOCUS (stmt));
+      location_t loc = EXPR_LOCATION (stmt);
+      warning ("%Hwill never be executed", &loc);
       return true;
     }
 
@@ -1776,7 +1792,7 @@ static void
 remove_bb (basic_block bb)
 {
   block_stmt_iterator i;
-  location_t *loc = NULL;
+  source_locus loc = 0;
 
   if (dump_file)
     {
@@ -1799,8 +1815,12 @@ remove_bb (basic_block bb)
         jump threading, thus resulting in bogus warnings.  Not great,
         since this way we lose warnings for gotos in the original
         program that are indeed unreachable.  */
-      if (TREE_CODE (stmt) != GOTO_EXPR && EXPR_LOCUS (stmt) && !loc)
+      if (TREE_CODE (stmt) != GOTO_EXPR && EXPR_HAS_LOCATION (stmt) && !loc)
+#ifdef USE_MAPPED_LOCATION
+       loc = EXPR_LOCATION (stmt);
+#else
        loc = EXPR_LOCUS (stmt);
+#endif
     }
 
   /* If requested, give a warning that the first statement in the
@@ -1808,7 +1828,11 @@ remove_bb (basic_block bb)
      loop above, so the last statement we process is the first statement
      in the block.  */
   if (warn_notreached && loc)
+#ifdef USE_MAPPED_LOCATION
+    warning ("%Hwill never be executed", &loc);
+#else
     warning ("%Hwill never be executed", loc);
+#endif
 
   remove_phi_nodes_and_edges_for_unreachable_block (bb);
 }
@@ -2641,7 +2665,11 @@ disband_implicit_edges (void)
       label = tree_block_label (e->dest);
 
       stmt = build1 (GOTO_EXPR, void_type_node, label);
+#ifdef USE_MAPPED_LOCATION
+      SET_EXPR_LOCATION (stmt, e->goto_locus);
+#else
       SET_EXPR_LOCUS (stmt, e->goto_locus);
+#endif
       bsi_insert_after (&last, stmt, BSI_NEW_STMT);
       e->flags &= ~EDGE_FALLTHRU;
     }
@@ -3134,7 +3162,9 @@ verify_expr (tree *tp, int *walk_subtrees, void *data ATTRIBUTE_UNUSED)
   if (TYPE_P (t))
     *walk_subtrees = 0;
   
-  /* Check operand N for being valid GIMPLE and give error MSG if not.  */
+  /* Check operand N for being valid GIMPLE and give error MSG if not. 
+     We check for constants explicitly since they are not considered
+     gimple invariants if they overflowed.  */
 #define CHECK_OP(N, MSG) \
   do { if (TREE_CODE_CLASS (TREE_CODE (TREE_OPERAND (t, N))) != 'c'    \
          && !is_gimple_val (TREE_OPERAND (t, N)))                      \
@@ -3283,24 +3313,8 @@ verify_expr (tree *tp, int *walk_subtrees, void *data ATTRIBUTE_UNUSED)
     case BIT_IOR_EXPR:
     case BIT_XOR_EXPR:
     case BIT_AND_EXPR:
-      x = TREE_OPERAND (t, 0);
-      /* We check for constants explicitly since they are not considered
-        gimple invariants if they overflowed.  */
-      if (TREE_CODE_CLASS (TREE_CODE (x)) != 'c'
-         && !is_gimple_val (x))
-       {
-         error ("Invalid operand to binary operator");
-         return x;
-       }
-      x = TREE_OPERAND (t, 1);
-      /* We check for constants explicitly since they are not considered
-        gimple invariants if they overflowed.  */
-      if (TREE_CODE_CLASS (TREE_CODE (x)) != 'c'
-         && !is_gimple_val (x))
-       {
-         error ("Invalid operand to binary operator");
-         return x;
-       }
+      CHECK_OP (0, "Invalid operand to binary operator");
+      CHECK_OP (1, "Invalid operand to binary operator");
       break;
 
     default:
@@ -3316,15 +3330,14 @@ verify_expr (tree *tp, int *walk_subtrees, void *data ATTRIBUTE_UNUSED)
    TODO: Implement type checking.  */
 
 static bool
-verify_stmt (tree stmt)
+verify_stmt (tree stmt, bool last_in_block)
 {
   tree addr;
 
   if (!is_gimple_stmt (stmt))
     {
       error ("Is not a valid GIMPLE statement.");
-      debug_generic_stmt (stmt);
-      return true;
+      goto fail;
     }
 
   addr = walk_tree (&stmt, verify_expr, NULL, NULL);
@@ -3334,7 +3347,30 @@ verify_stmt (tree stmt)
       return true;
     }
 
+  /* If the statement is marked as part of an EH region, then it is
+     expected that the statement could throw.  Verify that when we
+     have optimizations that simplify statements such that we prove
+     that they cannot throw, that we update other data structures
+     to match.  */
+  if (lookup_stmt_eh_region (stmt) >= 0)
+    {
+      if (!tree_could_throw_p (stmt))
+       {
+         error ("Statement marked for throw, but doesn't.");
+         goto fail;
+       }
+      if (!last_in_block && tree_can_throw_internal (stmt))
+       {
+         error ("Statement marked for throw in middle of block.");
+         goto fail;
+       }
+    }
+
   return false;
+
+ fail:
+  debug_generic_stmt (stmt);
+  return true;
 }
 
 
@@ -3449,10 +3485,11 @@ verify_stmts (void)
            }
        }
 
-      for (bsi = bsi_start (bb); !bsi_end_p (bsi); bsi_next (&bsi))
+      for (bsi = bsi_start (bb); !bsi_end_p (bsi); )
        {
          tree stmt = bsi_stmt (bsi);
-         err |= verify_stmt (stmt);
+         bsi_next (&bsi);
+         err |= verify_stmt (stmt, bsi_end_p (bsi));
          addr = walk_tree (&stmt, verify_node_sharing, htab, NULL);
          if (addr)
            {
@@ -3924,7 +3961,7 @@ thread_jumps (void)
               dest = dest->succ->dest)
            {
              /* An infinite loop detected.  We redirect the edge anyway, so
-                that the loop is shrinked into single basic block.  */
+                that the loop is shrunk into single basic block.  */
              if (!bb_ann (dest)->forwardable)
                break;
 
@@ -4243,11 +4280,18 @@ tree_duplicate_bb (basic_block bb)
   for (bsi = bsi_start (bb); !bsi_end_p (bsi); bsi_next (&bsi))
     {
       tree stmt = bsi_stmt (bsi);
+      tree copy;
 
       if (TREE_CODE (stmt) == LABEL_EXPR)
        continue;
 
-      bsi_insert_after (&bsi_tgt, unshare_expr (stmt), BSI_NEW_STMT);
+      copy = unshare_expr (stmt);
+
+      /* Copy also the virtual operands.  */
+      get_stmt_ann (copy);
+      copy_virtual_operands (copy, stmt);
+      
+      bsi_insert_after (&bsi_tgt, copy, BSI_NEW_STMT);
     }
 
   return new_bb;
@@ -4637,6 +4681,40 @@ tree_flow_call_edges_add (sbitmap blocks)
   return blocks_split;
 }
 
+bool
+tree_purge_dead_eh_edges (basic_block bb)
+{
+  bool changed = false;
+  edge e, next;
+  tree stmt = last_stmt (bb);
+
+  if (stmt && tree_can_throw_internal (stmt))
+    return false;
+
+  for (e = bb->succ; e ; e = next)
+    {
+      next = e->succ_next;
+      if (e->flags & EDGE_EH)
+       {
+         ssa_remove_edge (e);
+         changed = true;
+       }
+    }
+
+  return changed;
+}
+
+bool
+tree_purge_all_dead_eh_edges (bitmap blocks)
+{
+  bool changed = false;
+  size_t i;
+
+  EXECUTE_IF_SET_IN_BITMAP (blocks, 0, i,
+    { changed |= tree_purge_dead_eh_edges (BASIC_BLOCK (i)); });
+
+  return changed;
+}
 
 struct cfg_hooks tree_cfg_hooks = {
   "tree",
@@ -4702,7 +4780,11 @@ struct tree_opt_pass pass_split_crit_edges =
 static void
 execute_warn_function_return (void)
 {
+#ifdef USE_MAPPED_LOCATION
+  source_location location;
+#else
   location_t *locus;
+#endif
   tree last;
   edge e;
 
@@ -4717,17 +4799,31 @@ execute_warn_function_return (void)
   if (TREE_THIS_VOLATILE (cfun->decl)
       && EXIT_BLOCK_PTR->pred != NULL)
     {
+#ifdef USE_MAPPED_LOCATION
+      location = UNKNOWN_LOCATION;
+#else
       locus = NULL;
+#endif
       for (e = EXIT_BLOCK_PTR->pred; e ; e = e->pred_next)
        {
          last = last_stmt (e->src);
          if (TREE_CODE (last) == RETURN_EXPR
+#ifdef USE_MAPPED_LOCATION
+             && (location = EXPR_LOCATION (last)) != UNKNOWN_LOCATION)
+#else
              && (locus = EXPR_LOCUS (last)) != NULL)
+#endif
            break;
        }
+#ifdef USE_MAPPED_LOCATION
+      if (location == UNKNOWN_LOCATION)
+       location = cfun->function_end_locus;
+      warning ("%H`noreturn' function does return", &location);
+#else
       if (!locus)
        locus = &cfun->function_end_locus;
       warning ("%H`noreturn' function does return", locus);
+#endif
     }
 
   /* If we see "return;" in some basic block, then we do reach the end
@@ -4742,10 +4838,17 @@ execute_warn_function_return (void)
          if (TREE_CODE (last) == RETURN_EXPR
              && TREE_OPERAND (last, 0) == NULL)
            {
+#ifdef USE_MAPPED_LOCATION
+             location = EXPR_LOCATION (last);
+             if (location == UNKNOWN_LOCATION)
+                 location = cfun->function_end_locus;
+             warning ("%Hcontrol reaches end of non-void function", &location);
+#else
              locus = EXPR_LOCUS (last);
              if (!locus)
                locus = &cfun->function_end_locus;
              warning ("%Hcontrol reaches end of non-void function", locus);
+#endif
              break;
            }
        }