OSDN Git Service

* doc/md.texi (Processor pipeline description): Mention that
[pf3gnuchains/gcc-fork.git] / gcc / tree-cfg.c
index 21277d8..bd2ec9a 100644 (file)
@@ -74,7 +74,6 @@ static void free_blocks_annotations (void);
 static void clear_blocks_annotations (void);
 static void make_blocks (tree);
 static void factor_computed_gotos (void);
-static tree tree_block_label (basic_block bb);
 
 /* Edges.  */
 static void make_edges (void);
@@ -419,7 +418,6 @@ static void
 make_edges (void)
 {
   basic_block bb;
-  edge e;
 
   /* Create an edge from entry to the first block with executable
      statements in it.  */
@@ -448,33 +446,6 @@ make_edges (void)
        make_edge (bb, bb->next_bb, EDGE_FALLTHRU);
     }
 
-  /* If there is a fallthru edge to exit out of the last block, transform it
-     to a return statement.  */
-  for (e = EXIT_BLOCK_PTR->prev_bb->succ; e; e = e->succ_next)
-    if (e->flags & EDGE_FALLTHRU)
-      break;
-
-  if (e && e->dest == EXIT_BLOCK_PTR)
-    {
-      block_stmt_iterator bsi;
-      basic_block ret_bb = EXIT_BLOCK_PTR->prev_bb;
-      tree x;
-
-      /* If E->SRC ends with a call that has an abnormal edge (for EH or
-        nonlocal goto), then we will need to split the edge to insert
-        an explicit return statement.  */
-      if (e != ret_bb->succ || e->succ_next)
-       {
-         ret_bb = split_edge (e);
-         e = ret_bb->succ;
-       }
-      e->flags &= ~EDGE_FALLTHRU;
-
-      x = build (RETURN_EXPR, void_type_node, NULL_TREE);
-      bsi = bsi_last (ret_bb);
-      bsi_insert_after (&bsi, x, BSI_NEW_STMT);
-    }
-
   /* We do not care about fake edges, so remove any that the CFG
      builder inserted for completeness.  */
   remove_fake_edges ();
@@ -539,7 +510,7 @@ make_ctrl_stmt_edges (basic_block bb)
 static void
 make_exit_edges (basic_block bb)
 {
-  tree last = last_stmt (bb);
+  tree last = last_stmt (bb), op;
 
   if (last == NULL_TREE)
     abort ();
@@ -579,8 +550,8 @@ make_exit_edges (basic_block bb)
       /* A MODIFY_EXPR may have a CALL_EXPR on its RHS and the CALL_EXPR
         may have an abnormal edge.  Search the RHS for this case and
         create any required edges.  */
-      if (TREE_CODE (TREE_OPERAND (last, 1)) == CALL_EXPR
-         && TREE_SIDE_EFFECTS (TREE_OPERAND (last, 1))
+      op = get_call_expr_in (last);
+      if (op && TREE_SIDE_EFFECTS (op)
          && current_function_has_nonlocal_label)
        make_goto_expr_edges (bb);
 
@@ -648,7 +619,21 @@ make_switch_expr_edges (basic_block bb)
 basic_block
 label_to_block (tree dest)
 {
-  return VARRAY_BB (label_to_block_map, LABEL_DECL_UID (dest));
+  int uid = LABEL_DECL_UID (dest);
+
+  /* We would die hard when faced by undefined label.  Emit label to
+     very first basic block.  This will hopefully make even the dataflow
+     and undefined variable warnings quite right.  */
+  if ((errorcount || sorrycount) && uid < 0)
+    {
+      block_stmt_iterator bsi = bsi_start (BASIC_BLOCK (0));
+      tree stmt;
+
+      stmt = build1 (LABEL_EXPR, void_type_node, dest);
+      bsi_insert_before (&bsi, stmt, BSI_NEW_STMT);
+      uid = LABEL_DECL_UID (dest);
+    }
+  return VARRAY_BB (label_to_block_map, uid);
 }
 
 
@@ -680,7 +665,12 @@ make_goto_expr_edges (basic_block bb)
       /* A GOTO to a local label creates normal edges.  */
       if (simple_goto_p (goto_t))
        {
-         make_edge (bb, label_to_block (dest), EDGE_FALLTHRU);
+         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;
        }
@@ -762,13 +752,50 @@ cleanup_tree_cfg (void)
 }
 
 
-/* Cleanup useless labels from the flow graph.  */
+/* Cleanup useless labels in basic blocks.  This is something we wish
+   to do early because it allows us to group case labels before creating
+   the edges for the CFG, and it speeds up block statement iterators in
+   all passes later on.
+   We only run this pass once, running it more than once is probably not
+   profitable.  */
+
+/* A map from basic block index to the leading label of that block.  */
+static tree *label_for_bb;
+
+/* Callback for for_each_eh_region.  Helper for cleanup_dead_labels.  */
+static void
+update_eh_label (struct eh_region *region)
+{
+  tree old_label = get_eh_region_tree_label (region);
+  if (old_label)
+    {
+      tree new_label = label_for_bb[label_to_block (old_label)->index];
+      set_eh_region_tree_label (region, new_label);
+    }
+}
+
+/* Given LABEL return the first label in the same basic block.  */
+static tree
+main_block_label (tree label)
+{
+  basic_block bb = label_to_block (label);
+
+  /* label_to_block possibly inserted undefined label into the chain.  */
+  if (!label_for_bb[bb->index])
+    label_for_bb[bb->index] = label;
+  return label_for_bb[bb->index];
+}
+
+/* Cleanup redundant labels.  This is a three-steo process:
+     1) Find the leading label for each block.
+     2) Redirect all references to labels to the leading labels.
+     3) Cleanup all useless labels.  */
 
 static void
 cleanup_dead_labels (void)
 {
   basic_block bb;
-  tree *label_for_bb = xcalloc (last_basic_block, sizeof (tree));
+  label_for_bb = xcalloc (last_basic_block, sizeof (tree));
 
   /* Find a suitable label for each block.  We use the first user-defined
      label is there is one, or otherwise just the first label we see.  */
@@ -805,7 +832,8 @@ cleanup_dead_labels (void)
        }
     }
 
-  /* Now redirect all jumps/branches to the selected label for each block.  */
+  /* Now redirect all jumps/branches to the selected label.
+     First do so for each block ending in a control statement.  */
   FOR_EACH_BB (bb)
     {
       tree stmt = last_stmt (bb);
@@ -817,15 +845,14 @@ cleanup_dead_labels (void)
        case COND_EXPR:
          {
            tree true_branch, false_branch;
-           basic_block true_bb, false_bb;
 
            true_branch = COND_EXPR_THEN (stmt);
            false_branch = COND_EXPR_ELSE (stmt);
-           true_bb = label_to_block (GOTO_DESTINATION (true_branch));
-           false_bb = label_to_block (GOTO_DESTINATION (false_branch));
 
-           GOTO_DESTINATION (true_branch) = label_for_bb[true_bb->index];
-           GOTO_DESTINATION (false_branch) = label_for_bb[false_bb->index];
+           GOTO_DESTINATION (true_branch)
+             = main_block_label (GOTO_DESTINATION (true_branch));
+           GOTO_DESTINATION (false_branch)
+             = main_block_label (GOTO_DESTINATION (false_branch));
 
            break;
          }
@@ -838,12 +865,8 @@ cleanup_dead_labels (void)
   
            /* Replace all destination labels.  */
            for (i = 0; i < n; ++i)
-             {
-               tree label = CASE_LABEL (TREE_VEC_ELT (vec, i));
-
-               CASE_LABEL (TREE_VEC_ELT (vec, i)) =
-                 label_for_bb[label_to_block (label)->index];
-             }
+             CASE_LABEL (TREE_VEC_ELT (vec, i))
+               = main_block_label (CASE_LABEL (TREE_VEC_ELT (vec, i)));
   
            break;
          }
@@ -851,19 +874,20 @@ cleanup_dead_labels (void)
        /* We have to handle GOTO_EXPRs until they're removed, and we don't
           remove them until after we've created the CFG edges.  */
        case GOTO_EXPR:
-         {
-           tree label = GOTO_DESTINATION (stmt);
-           if (! computed_goto_p (stmt))
-             GOTO_DESTINATION (stmt) =
-               label_for_bb[label_to_block (label)->index];
-           break;
-         }
+          if (! computed_goto_p (stmt))
+           {
+             GOTO_DESTINATION (stmt)
+               = main_block_label (GOTO_DESTINATION (stmt));
+             break;
+           }
 
        default:
          break;
       }
     }
 
+  for_each_eh_region (update_eh_label);
+
   /* Finally, purge dead labels.  All user-defined labels and labels that
      can be the target of non-local gotos are preserved.  */
   FOR_EACH_BB (bb)
@@ -913,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
@@ -926,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);
 
@@ -1095,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;
     }
 
@@ -1484,7 +1520,7 @@ clear_special_calls (void)
 static void
 remove_useless_stmts_1 (tree *tp, struct rus_data *data)
 {
-  tree t = *tp;
+  tree t = *tp, op;
 
   switch (TREE_CODE (t))
     {
@@ -1530,10 +1566,11 @@ remove_useless_stmts_1 (tree *tp, struct rus_data *data)
     case MODIFY_EXPR:
       data->last_goto = NULL;
       fold_stmt (tp);
-      if (TREE_CODE (TREE_OPERAND (t, 1)) == CALL_EXPR)
+      op = get_call_expr_in (t);
+      if (op)
        {
-         update_call_expr_flags (TREE_OPERAND (t, 1));
-         notice_special_calls (TREE_OPERAND (t, 1));
+         update_call_expr_flags (op);
+         notice_special_calls (op);
        }
       if (tree_could_throw_p (t))
        data->may_throw = true;
@@ -1739,7 +1776,7 @@ remove_phi_nodes_and_edges_for_unreachable_block (basic_block bb)
   phi = phi_nodes (bb);
   while (phi)
     {
-      tree next = TREE_CHAIN (phi);
+      tree next = PHI_CHAIN (phi);
       remove_phi_node (phi, NULL_TREE, bb);
       phi = next;
     }
@@ -1756,7 +1793,7 @@ static void
 remove_bb (basic_block bb)
 {
   block_stmt_iterator i;
-  location_t *loc = NULL;
+  source_locus loc = 0;
 
   if (dump_file)
     {
@@ -1779,8 +1816,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
@@ -1788,7 +1829,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);
 }
@@ -2084,7 +2129,7 @@ phi_alternatives_equal (basic_block dest, edge e1, edge e2)
   tree phi, val1, val2;
   int n1, n2;
 
-  for (phi = phi_nodes (dest); phi; phi = TREE_CHAIN (phi))
+  for (phi = phi_nodes (dest); phi; phi = PHI_CHAIN (phi))
     {
       n1 = phi_arg_from_edge (phi, e1);
       n2 = phi_arg_from_edge (phi, e2);
@@ -2263,10 +2308,10 @@ dump_cfg_stats (FILE *file)
 {
   static long max_num_merged_labels = 0;
   unsigned long size, total = 0;
-  long n_edges;
+  int n_edges;
   basic_block bb;
   const char * const fmt_str   = "%-30s%-13s%12s\n";
-  const char * const fmt_str_1 = "%-30s%13lu%11lu%c\n";
+  const char * const fmt_str_1 = "%-30s%13d%11lu%c\n";
   const char * const fmt_str_3 = "%-43s%11lu%c\n";
   const char *funcname
     = lang_hooks.decl_printable_name (current_function_decl, 2);
@@ -2281,8 +2326,8 @@ dump_cfg_stats (FILE *file)
 
   size = n_basic_blocks * sizeof (struct basic_block_def);
   total += size;
-  fprintf (file, fmt_str_1, "Basic blocks", n_basic_blocks, SCALE (size),
-          LABEL (size));
+  fprintf (file, fmt_str_1, "Basic blocks", n_basic_blocks,
+          SCALE (size), LABEL (size));
 
   n_edges = 0;
   FOR_EACH_BB (bb)
@@ -2434,37 +2479,24 @@ is_ctrl_stmt (tree t)
 bool
 is_ctrl_altering_stmt (tree t)
 {
-  tree call = t;
+  tree call;
 
 #if defined ENABLE_CHECKING
   if (t == NULL)
     abort ();
 #endif
 
-  switch (TREE_CODE (t))
+  call = get_call_expr_in (t);
+  if (call)
     {
-    case MODIFY_EXPR:
-      /* A MODIFY_EXPR with a rhs of a call has the characteristics
-        of the call.  */
-      call = TREE_OPERAND (t, 1);
-      if (TREE_CODE (call) != CALL_EXPR)
-       break;
-      /* FALLTHRU */
-
-    case CALL_EXPR:
       /* A non-pure/const CALL_EXPR alters flow control if the current
         function has nonlocal labels.  */
-      if (TREE_SIDE_EFFECTS (t)
-         && current_function_has_nonlocal_label)
+      if (TREE_SIDE_EFFECTS (call) && current_function_has_nonlocal_label)
        return true;
 
       /* A CALL_EXPR also alters control flow if it does not return.  */
       if (call_expr_flags (call) & (ECF_NORETURN | ECF_LONGJMP))
        return true;
-      break;
-
-    default:
-      return false;
     }
 
   /* If a statement can throw, it alters control flow.  */
@@ -2554,7 +2586,7 @@ disband_implicit_edges (void)
   basic_block bb;
   block_stmt_iterator last;
   edge e;
-  tree stmt, label, forward;
+  tree stmt, label;
 
   FOR_EACH_BB (bb)
     {
@@ -2612,8 +2644,7 @@ disband_implicit_edges (void)
        if (e->flags & EDGE_FALLTHRU)
          break;
 
-      if (!e
-         || e->dest == bb->next_bb)
+      if (!e || e->dest == bb->next_bb)
        continue;
 
       if (e->dest == EXIT_BLOCK_PTR)
@@ -2621,35 +2652,30 @@ disband_implicit_edges (void)
 
       label = tree_block_label (e->dest);
 
-      /* If this is a goto to a goto, jump to the final destination.
-         Handles unfactoring of the computed jumps.
-         ??? Why bother putting this back together when rtl is just
-        about to take it apart again?  */
-      forward = last_and_only_stmt (e->dest);
-      if (forward
-         && TREE_CODE (forward) == GOTO_EXPR)
-       label = GOTO_DESTINATION (forward);
-
-      bsi_insert_after (&last,
-                       build1 (GOTO_EXPR, void_type_node, label),
-                       BSI_NEW_STMT);
+      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;
     }
 }
 
-
-/* Remove all the blocks and edges that make up the flowgraph.  */
+/* Remove block annotations and other datastructures.  */
 
 void
-delete_tree_cfg (void)
+delete_tree_cfg_annotations (void)
 {
+  basic_block bb;
   if (n_basic_blocks > 0)
     free_blocks_annotations ();
 
-  free_basic_block_vars ();
-  basic_block_info = NULL;
   label_to_block_map = NULL;
   free_rbi_pool ();
+  FOR_EACH_BB (bb)
+    bb->rbi = NULL;
 }
 
 
@@ -3012,27 +3038,6 @@ bsi_insert_on_edge (edge e, tree stmt)
 }
 
 
-/* Specialized edge insertion for SSA-PRE.  FIXME: This should
-   probably disappear.  The only reason it's here is because PRE needs
-   the call to tree_find_edge_insert_loc().  */
-
-void pre_insert_on_edge (edge e, tree stmt);
-
-void
-pre_insert_on_edge (edge e, tree stmt)
-{
-  block_stmt_iterator bsi;
-
-  if (PENDING_STMT (e))
-    abort ();
-
-  if (tree_find_edge_insert_loc (e, &bsi))
-    bsi_insert_after (&bsi, stmt, BSI_NEW_STMT);
-  else
-    bsi_insert_before (&bsi, stmt, BSI_NEW_STMT);
-}
-
-
 /*---------------------------------------------------------------------------
             Tree specific functions for CFG manipulation
 ---------------------------------------------------------------------------*/
@@ -3072,7 +3077,7 @@ tree_split_edge (edge edge_in)
   /* Find all the PHI arguments on the original edge, and change them to
      the new edge.  Do it before redirection, so that the argument does not
      get removed.  */
-  for (phi = phi_nodes (dest); phi; phi = TREE_CHAIN (phi))
+  for (phi = phi_nodes (dest); phi; phi = PHI_CHAIN (phi))
     {
       num_elem = PHI_NUM_ARGS (phi);
       for (i = 0; i < num_elem; i++)
@@ -3117,13 +3122,20 @@ has_label_p (basic_block bb, tree label)
    properly noticed as such.  */
 
 static tree
-verify_expr (tree *tp, int *walk_subtrees ATTRIBUTE_UNUSED,
-            void *data ATTRIBUTE_UNUSED)
+verify_expr (tree *tp, int *walk_subtrees, void *data ATTRIBUTE_UNUSED)
 {
   tree t = *tp, x;
 
   if (TYPE_P (t))
     *walk_subtrees = 0;
+  
+  /* 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)))                      \
+       { error (MSG); return TREE_OPERAND (t, N); }} while (0)
 
   switch (TREE_CODE (t))
     {
@@ -3141,17 +3153,21 @@ verify_expr (tree *tp, int *walk_subtrees ATTRIBUTE_UNUSED,
          && is_gimple_reg (TREE_OPERAND (x, 0)))
        {
          error ("GIMPLE register modified with BIT_FIELD_REF");
-         return *tp;
+         return t;
        }
       break;
 
     case ADDR_EXPR:
-      x = TREE_OPERAND (t, 0);
-      while (TREE_CODE (x) == ARRAY_REF
-            || TREE_CODE (x) == COMPONENT_REF
-            || TREE_CODE (x) == REALPART_EXPR
-            || TREE_CODE (x) == IMAGPART_EXPR)
-       x = TREE_OPERAND (x, 0);
+      /* Skip any references (they will be checked when we recurse down the
+        tree) and ensure that any variable used as a prefix is marked
+        addressable.  */
+      for (x = TREE_OPERAND (t, 0);
+          (handled_component_p (x)
+           || TREE_CODE (x) == REALPART_EXPR
+           || TREE_CODE (x) == IMAGPART_EXPR);
+          x = TREE_OPERAND (x, 0))
+       ;
+
       if (TREE_CODE (x) != VAR_DECL && TREE_CODE (x) != PARM_DECL)
        return NULL;
       if (!TREE_ADDRESSABLE (x))
@@ -3182,19 +3198,50 @@ verify_expr (tree *tp, int *walk_subtrees ATTRIBUTE_UNUSED,
     case BIT_NOT_EXPR:
     case NON_LVALUE_EXPR:
     case TRUTH_NOT_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 unary operator");
-         return x;
-       }
+      CHECK_OP (0, "Invalid operand to unary operator");
       break;
 
     case REALPART_EXPR:
     case IMAGPART_EXPR:
+    case COMPONENT_REF:
+    case ARRAY_REF:
+    case ARRAY_RANGE_REF:
+    case BIT_FIELD_REF:
+    case VIEW_CONVERT_EXPR:
+      /* We have a nest of references.  Verify that each of the operands
+        that determine where to reference is either a constant or a variable,
+        verify that the base is valid, and then show we've already checked
+        the subtrees.  */
+      while (TREE_CODE (t) == REALPART_EXPR || TREE_CODE (t) == IMAGPART_EXPR
+            || handled_component_p (t))
+       {
+         if (TREE_CODE (t) == COMPONENT_REF && TREE_OPERAND (t, 2))
+           CHECK_OP (2, "Invalid COMPONENT_REF offset operator");
+         else if (TREE_CODE (t) == ARRAY_REF
+                  || TREE_CODE (t) == ARRAY_RANGE_REF)
+           {
+             CHECK_OP (1, "Invalid array index.");
+             if (TREE_OPERAND (t, 2))
+               CHECK_OP (2, "Invalid array lower bound.");
+             if (TREE_OPERAND (t, 3))
+               CHECK_OP (3, "Invalid array stride.");
+           }
+         else if (TREE_CODE (t) == BIT_FIELD_REF)
+           {
+             CHECK_OP (1, "Invalid operand to BIT_FIELD_REF");
+             CHECK_OP (2, "Invalid operand to BIT_FIELD_REF");
+           }
+
+         t = TREE_OPERAND (t, 0);
+       }
+
+      if (TREE_CODE_CLASS (TREE_CODE (t)) != 'c'
+         && !is_gimple_lvalue (t))
+       {
+         error ("Invalid reference prefix.");
+         return t;
+       }
+      *walk_subtrees = 0;
       break;
 
     case LT_EXPR:
@@ -3233,30 +3280,16 @@ verify_expr (tree *tp, int *walk_subtrees 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:
       break;
     }
   return NULL;
+
+#undef CHECK_OP
 }
 
 
@@ -3264,15 +3297,14 @@ verify_expr (tree *tp, int *walk_subtrees 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);
@@ -3282,7 +3314,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;
 }
 
 
@@ -3299,7 +3354,7 @@ tree_node_can_be_shared (tree t)
       || TREE_CODE (t) == SSA_NAME)
     return true;
 
-  while ((TREE_CODE (t) == ARRAY_REF
+  while (((TREE_CODE (t) == ARRAY_REF || TREE_CODE (t) == ARRAY_RANGE_REF)
          /* We check for constants explicitly since they are not considered
             gimple invariants if they overflowed.  */
          && (TREE_CODE_CLASS (TREE_CODE (TREE_OPERAND (t, 1))) == 'c'
@@ -3358,7 +3413,7 @@ verify_stmts (void)
       tree phi;
       int i;
 
-      for (phi = phi_nodes (bb); phi; phi = TREE_CHAIN (phi))
+      for (phi = phi_nodes (bb); phi; phi = PHI_CHAIN (phi))
        {
          int phi_num_args = PHI_NUM_ARGS (phi);
 
@@ -3397,10 +3452,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)
            {
@@ -3603,6 +3659,7 @@ tree_verify_flow_info (void)
 
        case SWITCH_EXPR:
          {
+           tree prev;
            edge e;
            size_t i, n;
            tree vec;
@@ -3621,6 +3678,34 @@ tree_verify_flow_info (void)
                label_bb->aux = (void *)1;
              }
 
+           /* Verify that the case labels are sorted.  */
+           prev = TREE_VEC_ELT (vec, 0);
+           for (i = 1; i < n - 1; ++i)
+             {
+               tree c = TREE_VEC_ELT (vec, i);
+               if (! CASE_LOW (c))
+                 {
+                   error ("Found default case not at end of case vector");
+                   err = 1;
+                   continue;
+                 }
+               if (! tree_int_cst_lt (CASE_LOW (prev), CASE_LOW (c)))
+                 {
+                   error ("Case labels not sorted:\n ");
+                   print_generic_expr (stderr, prev, 0);
+                   fprintf (stderr," is greater than ");
+                   print_generic_expr (stderr, c, 0);
+                   fprintf (stderr," but comes before it.\n");
+                   err = 1;
+                 }
+               prev = c;
+             }
+           if (CASE_LOW (TREE_VEC_ELT (vec, n - 1)))
+             {
+               error ("No default case found at end of case vector");
+               err = 1;
+             }
+
            for (e = bb->succ; e; e = e->succ_next)
              {
                if (!e->dest->aux)
@@ -3676,7 +3761,7 @@ tree_make_forwarder_block (edge fallthru)
 {
   edge e;
   basic_block dummy, bb;
-  tree phi, new_phi, var;
+  tree phi, new_phi, var, prev, next;
 
   dummy = fallthru->src;
   bb = fallthru->dest;
@@ -3686,17 +3771,24 @@ tree_make_forwarder_block (edge fallthru)
 
   /* If we redirected a branch we must create new phi nodes at the
      start of BB.  */
-  for (phi = phi_nodes (dummy); phi; phi = TREE_CHAIN (phi))
+  for (phi = phi_nodes (dummy); phi; phi = PHI_CHAIN (phi))
     {
       var = PHI_RESULT (phi);
       new_phi = create_phi_node (var, bb);
       SSA_NAME_DEF_STMT (var) = new_phi;
-      PHI_RESULT (phi) = make_ssa_name (SSA_NAME_VAR (var), phi);
+      SET_PHI_RESULT (phi, make_ssa_name (SSA_NAME_VAR (var), phi));
       add_phi_arg (&new_phi, PHI_RESULT (phi), fallthru);
     }
 
-  /* Ensure that the PHI node chains are in the same order.  */
-  set_phi_nodes (bb, nreverse (phi_nodes (bb)));
+  /* Ensure that the PHI node chain is in the same order.  */
+  prev = NULL;
+  for (phi = phi_nodes (bb); phi; phi = next)
+    {
+      next = PHI_CHAIN (phi);
+      PHI_CHAIN (phi) = prev;
+      prev = phi;
+    }
+  set_phi_nodes (bb, prev);
 
   /* Add the arguments we have stored on edges.  */
   for (e = bb->pred; e; e = e->pred_next)
@@ -3706,7 +3798,7 @@ tree_make_forwarder_block (edge fallthru)
 
       for (phi = phi_nodes (bb), var = PENDING_STMT (e);
           phi;
-          phi = TREE_CHAIN (phi), var = TREE_CHAIN (var))
+          phi = PHI_CHAIN (phi), var = TREE_CHAIN (var))
        add_phi_arg (&phi, TREE_VALUE (var), e);
 
       PENDING_STMT (e) = NULL;
@@ -3836,7 +3928,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;
 
@@ -3887,7 +3979,7 @@ thread_jumps (void)
              /* Update PHI nodes.   We know that the new argument should
                 have the same value as the argument associated with LAST.
                 Otherwise we would have changed our target block above.  */
-             for (phi = phi_nodes (dest); phi; phi = TREE_CHAIN (phi))
+             for (phi = phi_nodes (dest); phi; phi = PHI_CHAIN (phi))
                {
                  arg = phi_arg_from_edge (phi, last);
                  if (arg < 0)
@@ -3909,7 +4001,7 @@ thread_jumps (void)
 /* Return a non-special label in the head of basic block BLOCK.
    Create one if it doesn't exist.  */
 
-static tree
+tree
 tree_block_label (basic_block bb)
 {
   block_stmt_iterator i, s = bsi_start (bb);
@@ -4155,11 +4247,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;
@@ -4377,15 +4476,7 @@ static bool
 tree_block_ends_with_call_p (basic_block bb)
 {
   block_stmt_iterator bsi = bsi_last (bb);
-  tree t = tsi_stmt (bsi.tsi);
-
-  if (TREE_CODE (t) == RETURN_EXPR && TREE_OPERAND (t, 0))
-    t = TREE_OPERAND (t, 0);
-
-  if (TREE_CODE (t) == MODIFY_EXPR)
-    t = TREE_OPERAND (t, 1);
-
-  return TREE_CODE (t) == CALL_EXPR;
+  return get_call_expr_in (bsi_stmt (bsi)) != NULL;
 }
 
 
@@ -4406,11 +4497,7 @@ tree_block_ends_with_condjump_p (basic_block bb)
 static bool
 need_fake_edge_p (tree t)
 {
-  if (TREE_CODE (t) == RETURN_EXPR && TREE_OPERAND (t, 0))
-    t = TREE_OPERAND (t, 0);
-
-  if (TREE_CODE (t) == MODIFY_EXPR)
-    t = TREE_OPERAND (t, 1);
+  tree call;
 
   /* NORETURN and LONGJMP calls already have an edge to exit.
      CONST, PURE and ALWAYS_RETURN calls do not need one.
@@ -4419,9 +4506,10 @@ need_fake_edge_p (tree t)
      figured out from the RTL in mark_constant_function, and
      the counter incrementation code from -fprofile-arcs
      leads to different results from -fbranch-probabilities.  */
-  if (TREE_CODE (t) == CALL_EXPR
-      && !(call_expr_flags (t) & 
-           (ECF_NORETURN | ECF_LONGJMP | ECF_ALWAYS_RETURN)))
+  call = get_call_expr_in (t);
+  if (call
+      && !(call_expr_flags (call) & 
+          (ECF_NORETURN | ECF_LONGJMP | ECF_ALWAYS_RETURN)))
     return true;
 
   if (TREE_CODE (t) == ASM_EXPR
@@ -4549,6 +4637,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",
@@ -4595,7 +4717,7 @@ split_critical_edges (void)
 
 struct tree_opt_pass pass_split_crit_edges = 
 {
-  NULL,                          /* name */
+  "crited",                          /* name */
   NULL,                          /* gate */
   split_critical_edges,          /* execute */
   NULL,                          /* sub */
@@ -4606,7 +4728,7 @@ struct tree_opt_pass pass_split_crit_edges =
   PROP_no_crit_edges,            /* properties_provided */
   0,                             /* properties_destroyed */
   0,                             /* todo_flags_start */
-  0,                             /* todo_flags_finish */
+  TODO_dump_func,                             /* todo_flags_finish */
 };
 \f
 /* Emit return warnings.  */
@@ -4614,7 +4736,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;
 
@@ -4629,17 +4755,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
@@ -4654,10 +4794,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;
            }
        }
@@ -4698,7 +4845,7 @@ struct tree_opt_pass pass_warn_function_return =
   NULL,                                        /* next */
   0,                                   /* static_pass_number */
   0,                                   /* tv_id */
-  PROP_ssa,                            /* properties_required */
+  PROP_cfg,                            /* properties_required */
   0,                                   /* properties_provided */
   0,                                   /* properties_destroyed */
   0,                                   /* todo_flags_start */