OSDN Git Service

* expmed.c (emit_store_flag): Also special-case double-word
[pf3gnuchains/gcc-fork.git] / gcc / tree-cfg.c
index d6823cb..8600a99 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 ();
@@ -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;
        }
@@ -784,6 +774,18 @@ update_eh_label (struct eh_region *region)
     }
 }
 
+/* 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.
@@ -843,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;
          }
@@ -864,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;
          }
@@ -877,13 +874,12 @@ 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;
@@ -941,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
@@ -954,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);
 
@@ -1123,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;
     }
 
@@ -1767,7 +1775,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;
     }
@@ -1784,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)
     {
@@ -1807,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
@@ -1816,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);
 }
@@ -2112,7 +2128,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);
@@ -2582,7 +2598,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)
     {
@@ -2640,8 +2656,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)
@@ -2649,35 +2664,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;
 }
 
 
@@ -3100,7 +3110,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++)
@@ -3145,13 +3155,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))
     {
@@ -3169,17 +3186,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))
@@ -3210,19 +3231,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:
@@ -3261,30 +3313,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
 }
 
 
@@ -3292,15 +3330,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);
@@ -3310,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;
 }
 
 
@@ -3327,7 +3387,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'
@@ -3386,7 +3446,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);
 
@@ -3425,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)
            {
@@ -3631,6 +3692,7 @@ tree_verify_flow_info (void)
 
        case SWITCH_EXPR:
          {
+           tree prev;
            edge e;
            size_t i, n;
            tree vec;
@@ -3649,6 +3711,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)
@@ -3704,7 +3794,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;
@@ -3714,17 +3804,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)
@@ -3734,7 +3831,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;
@@ -3864,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;
 
@@ -3915,7 +4012,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)
@@ -3937,7 +4034,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);
@@ -4183,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;
@@ -4577,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",
@@ -4623,7 +4761,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 */
@@ -4634,7 +4772,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.  */
@@ -4642,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;
 
@@ -4657,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
@@ -4682,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;
            }
        }
@@ -4726,7 +4889,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 */