OSDN Git Service

Tweak ABI & add moxie-uclinux target.
[pf3gnuchains/gcc-fork.git] / gcc / tree-cfg.c
index 07a46df..a6097ed 100644 (file)
@@ -82,6 +82,14 @@ static struct cfg_stats_d cfg_stats;
 /* Nonzero if we found a computed goto while building basic blocks.  */
 static bool found_computed_goto;
 
+/* Hash table to store last discriminator assigned for each locus.  */
+struct locus_discrim_map
+{
+  location_t locus;
+  int discriminator;
+};
+static htab_t discriminator_per_locus;
+
 /* Basic blocks and flowgraphs.  */
 static void make_blocks (gimple_seq);
 static void factor_computed_gotos (void);
@@ -91,6 +99,9 @@ static void make_edges (void);
 static void make_cond_expr_edges (basic_block);
 static void make_gimple_switch_edges (basic_block);
 static void make_goto_expr_edges (basic_block);
+static unsigned int locus_map_hash (const void *);
+static int locus_map_eq (const void *, const void *);
+static void assign_discriminator (location_t, basic_block);
 static edge gimple_redirect_edge_and_branch (edge, basic_block);
 static edge gimple_try_redirect_by_replacing_jump (edge, basic_block);
 static unsigned int split_critical_edges (void);
@@ -100,6 +111,7 @@ static inline bool stmt_starts_bb_p (gimple, gimple);
 static int gimple_verify_flow_info (void);
 static void gimple_make_forwarder_block (edge);
 static void gimple_cfg2vcg (FILE *);
+static gimple first_non_label_stmt (basic_block);
 
 /* Flowgraph optimization and cleanup.  */
 static void gimple_merge_blocks (basic_block, basic_block);
@@ -193,8 +205,11 @@ build_gimple_cfg (gimple_seq seq)
   group_case_labels ();
 
   /* Create the edges of the flowgraph.  */
+  discriminator_per_locus = htab_create (13, locus_map_hash, locus_map_eq,
+                                         free);
   make_edges ();
   cleanup_dead_labels ();
+  htab_delete (discriminator_per_locus);
 
   /* Debugging dumps.  */
 
@@ -314,7 +329,7 @@ factor_computed_gotos (void)
 
              /* Build a label for the new block which will contain the
                 factored computed goto.  */
-             factored_label_decl = create_artificial_label ();
+             factored_label_decl = create_artificial_label (UNKNOWN_LOCATION);
              factored_computed_goto_label
                = gimple_build_label (factored_label_decl);
              gsi_insert_after (&new_gsi, factored_computed_goto_label,
@@ -375,7 +390,29 @@ make_blocks (gimple_seq seq)
       /* If STMT is a basic block terminator, set START_NEW_BLOCK for the
         next iteration.  */
       if (stmt_ends_bb_p (stmt))
-       start_new_block = true;
+       {
+         /* If the stmt can make abnormal goto use a new temporary
+            for the assignment to the LHS.  This makes sure the old value
+            of the LHS is available on the abnormal edge.  Otherwise
+            we will end up with overlapping life-ranges for abnormal
+            SSA names.  */
+         if (gimple_has_lhs (stmt)
+             && stmt_can_make_abnormal_goto (stmt)
+             && is_gimple_reg_type (TREE_TYPE (gimple_get_lhs (stmt))))
+           {
+             tree lhs = gimple_get_lhs (stmt);
+             tree tmp = create_tmp_var (TREE_TYPE (lhs), NULL);
+             gimple s = gimple_build_assign (lhs, tmp);
+             gimple_set_location (s, gimple_location (stmt));
+             gimple_set_block (s, gimple_block (stmt));
+             gimple_set_lhs (stmt, tmp);
+             if (TREE_CODE (TREE_TYPE (tmp)) == COMPLEX_TYPE
+                 || TREE_CODE (TREE_TYPE (tmp)) == VECTOR_TYPE)
+               DECL_GIMPLE_REG_P (tmp) = 1;
+             gsi_insert_after (&i, s, GSI_SAME_STMT);
+           }
+         start_new_block = true;
+       }
 
       gsi_next (&i);
       first_stmt_of_seq = false;
@@ -439,11 +476,12 @@ fold_cond_expr_cond (void)
 
       if (stmt && gimple_code (stmt) == GIMPLE_COND)
        {
+         location_t loc = gimple_location (stmt);
          tree cond;
          bool zerop, onep;
 
          fold_defer_overflow_warnings ();
-         cond = fold_binary (gimple_cond_code (stmt), boolean_type_node,
+         cond = fold_binary_loc (loc, gimple_cond_code (stmt), boolean_type_node,
                              gimple_cond_lhs (stmt), gimple_cond_rhs (stmt));
          if (cond)
            {
@@ -628,7 +666,11 @@ make_edges (void)
        fallthru = true;
 
       if (fallthru)
-       make_edge (bb, bb->next_bb, EDGE_FALLTHRU);
+        {
+         make_edge (bb, bb->next_bb, EDGE_FALLTHRU);
+         if (last)
+            assign_discriminator (gimple_location (last), bb->next_bb);
+       }
     }
 
   if (root_omp_region)
@@ -638,6 +680,93 @@ make_edges (void)
   fold_cond_expr_cond ();
 }
 
+/* Trivial hash function for a location_t.  ITEM is a pointer to
+   a hash table entry that maps a location_t to a discriminator.  */
+
+static unsigned int
+locus_map_hash (const void *item)
+{
+  return ((const struct locus_discrim_map *) item)->locus;
+}
+
+/* Equality function for the locus-to-discriminator map.  VA and VB
+   point to the two hash table entries to compare.  */
+
+static int
+locus_map_eq (const void *va, const void *vb)
+{
+  const struct locus_discrim_map *a = (const struct locus_discrim_map *) va;
+  const struct locus_discrim_map *b = (const struct locus_discrim_map *) vb;
+  return a->locus == b->locus;
+}
+
+/* Find the next available discriminator value for LOCUS.  The
+   discriminator distinguishes among several basic blocks that
+   share a common locus, allowing for more accurate sample-based
+   profiling.  */
+
+static int
+next_discriminator_for_locus (location_t locus)
+{
+  struct locus_discrim_map item;
+  struct locus_discrim_map **slot;
+
+  item.locus = locus;
+  item.discriminator = 0;
+  slot = (struct locus_discrim_map **)
+      htab_find_slot_with_hash (discriminator_per_locus, (void *) &item,
+                                (hashval_t) locus, INSERT);
+  gcc_assert (slot);
+  if (*slot == HTAB_EMPTY_ENTRY)
+    {
+      *slot = XNEW (struct locus_discrim_map);
+      gcc_assert (*slot);
+      (*slot)->locus = locus;
+      (*slot)->discriminator = 0;
+    }
+  (*slot)->discriminator++;
+  return (*slot)->discriminator;
+}
+
+/* Return TRUE if LOCUS1 and LOCUS2 refer to the same source line.  */
+
+static bool
+same_line_p (location_t locus1, location_t locus2)
+{
+  expanded_location from, to;
+
+  if (locus1 == locus2)
+    return true;
+
+  from = expand_location (locus1);
+  to = expand_location (locus2);
+
+  if (from.line != to.line)
+    return false;
+  if (from.file == to.file)
+    return true;
+  return (from.file != NULL
+          && to.file != NULL
+          && strcmp (from.file, to.file) == 0);
+}
+
+/* Assign a unique discriminator value to block BB if it begins at the same
+   LOCUS as its predecessor block.  */
+
+static void
+assign_discriminator (location_t locus, basic_block bb)
+{
+  gimple first_in_to_bb, last_in_to_bb;
+
+  if (locus == 0 || bb->discriminator != 0)
+    return;
+
+  first_in_to_bb = first_non_label_stmt (bb);
+  last_in_to_bb = last_stmt (bb);
+  if ((first_in_to_bb && same_line_p (locus, gimple_location (first_in_to_bb)))
+      || (last_in_to_bb && same_line_p (locus, gimple_location (last_in_to_bb))))
+    bb->discriminator = next_discriminator_for_locus (locus);
+}
 
 /* Create the edges for a GIMPLE_COND starting at block BB.  */
 
@@ -649,10 +778,13 @@ make_cond_expr_edges (basic_block bb)
   basic_block then_bb, else_bb;
   tree then_label, else_label;
   edge e;
+  location_t entry_locus;
 
   gcc_assert (entry);
   gcc_assert (gimple_code (entry) == GIMPLE_COND);
 
+  entry_locus = gimple_location (entry);
+
   /* Entry basic blocks for each component.  */
   then_label = gimple_cond_true_label (entry);
   else_label = gimple_cond_false_label (entry);
@@ -662,12 +794,14 @@ make_cond_expr_edges (basic_block bb)
   else_stmt = first_stmt (else_bb);
 
   e = make_edge (bb, then_bb, EDGE_TRUE_VALUE);
+  assign_discriminator (entry_locus, then_bb);
   e->goto_locus = gimple_location (then_stmt);
   if (e->goto_locus)
     e->goto_block = gimple_block (then_stmt);
   e = make_edge (bb, else_bb, EDGE_FALSE_VALUE);
   if (e)
     {
+      assign_discriminator (entry_locus, else_bb);
       e->goto_locus = gimple_location (else_stmt);
       if (e->goto_locus)
        e->goto_block = gimple_block (else_stmt);
@@ -777,8 +911,11 @@ static void
 make_gimple_switch_edges (basic_block bb)
 {
   gimple entry = last_stmt (bb);
+  location_t entry_locus;
   size_t i, n;
 
+  entry_locus = gimple_location (entry);
+
   n = gimple_switch_num_labels (entry);
 
   for (i = 0; i < n; ++i)
@@ -786,6 +923,7 @@ make_gimple_switch_edges (basic_block bb)
       tree lab = CASE_LABEL (gimple_switch_label (entry, i));
       basic_block label_bb = label_to_block (lab);
       make_edge (bb, label_bb, 0);
+      assign_discriminator (entry_locus, label_bb);
     }
 }
 
@@ -858,8 +996,10 @@ make_goto_expr_edges (basic_block bb)
   if (simple_goto_p (goto_t))
     {
       tree dest = gimple_goto_dest (goto_t);
-      edge e = make_edge (bb, label_to_block (dest), EDGE_FALLTHRU);
+      basic_block label_bb = label_to_block (dest);
+      edge e = make_edge (bb, label_bb, EDGE_FALLTHRU);
       e->goto_locus = gimple_location (goto_t);
+      assign_discriminator (e->goto_locus, label_bb);
       if (e->goto_locus)
        e->goto_block = gimple_block (goto_t);
       gsi_remove (&last, true);
@@ -895,7 +1035,7 @@ static struct label_record
 
 /* Callback for for_each_eh_region.  Helper for cleanup_dead_labels.  */
 static void
-update_eh_label (struct eh_region *region)
+update_eh_label (struct eh_region_d *region)
 {
   tree old_label = get_eh_region_tree_label (region);
   if (old_label)
@@ -1190,7 +1330,7 @@ gimple_can_merge_blocks_p (basic_block a, basic_block b)
   if (!single_succ_p (a))
     return false;
 
-  if (single_succ_edge (a)->flags & EDGE_ABNORMAL)
+  if (single_succ_edge (a)->flags & (EDGE_ABNORMAL | EDGE_EH))
     return false;
 
   if (single_succ (a) != b)
@@ -1267,9 +1407,6 @@ replace_uses_by (tree name, tree val)
 
   FOR_EACH_IMM_USE_STMT (stmt, imm_iter, name)
     {
-      if (gimple_code (stmt) != GIMPLE_PHI)
-       push_stmt_changes (&stmt);
-
       FOR_EACH_IMM_USE_ON_STMT (use, imm_iter)
         {
          replace_exp (use, val);
@@ -1296,7 +1433,7 @@ replace_uses_by (tree name, tree val)
          if (cfgcleanup_altered_bbs)
            bitmap_set_bit (cfgcleanup_altered_bbs, gimple_bb (stmt)->index);
 
-         /* FIXME.  This should go in pop_stmt_changes.  */
+         /* FIXME.  This should go in update_stmt.  */
          for (i = 0; i < gimple_num_ops (stmt); i++)
            {
              tree op = gimple_op (stmt, i);
@@ -1308,8 +1445,7 @@ replace_uses_by (tree name, tree val)
            }
 
          maybe_clean_or_replace_eh_stmt (stmt, stmt);
-
-         pop_stmt_changes (&stmt);
+         update_stmt (stmt);
        }
     }
 
@@ -1438,7 +1574,7 @@ gimple_merge_blocks (basic_block a, basic_block b)
 
 
 /* Return the one of two successors of BB that is not reachable by a
-   reached by a complex edge, if there is one.  Else, return BB.  We use
+   complex edge, if there is one.  Else, return BB.  We use
    this in optimizations that use post-dominators for their heuristics,
    to catch the cases in C++ where function calls are involved.  */
 
@@ -1505,12 +1641,14 @@ remove_useless_stmts_warn_notreached (gimple_seq stmts)
     {
       gimple stmt = gsi_stmt (gsi);
 
+      if (gimple_no_warning_p (stmt)) return false;
+
       if (gimple_has_location (stmt))
         {
           location_t loc = gimple_location (stmt);
           if (LOCATION_LINE (loc) > 0)
            {
-              warning (OPT_Wunreachable_code, "%Hwill never be executed", &loc);
+              warning_at (loc, OPT_Wunreachable_code, "will never be executed");
               return true;
             }
         }
@@ -1552,7 +1690,8 @@ remove_useless_stmts_cond (gimple_stmt_iterator *gsi, struct rus_data *data)
   gimple stmt = gsi_stmt (*gsi);
 
   /* The folded result must still be a conditional statement.  */
-  fold_stmt_inplace (stmt);
+  fold_stmt (gsi);
+  gcc_assert (gsi_stmt (*gsi) == stmt);
 
   data->may_branch = true;
 
@@ -2022,18 +2161,6 @@ remove_useless_stmts_1 (gimple_stmt_iterator *gsi, struct rus_data *data)
           }
           break;
 
-        case GIMPLE_CHANGE_DYNAMIC_TYPE:
-         /* If we do not optimize remove GIMPLE_CHANGE_DYNAMIC_TYPE as
-            expansion is confused about them and we only remove them
-            during alias computation otherwise.  */
-         if (!optimize)
-           {
-             data->last_was_goto = false;
-             gsi_remove (gsi, false);
-             break;
-           }
-         /* Fallthru.  */
-
         default:
           data->last_was_goto = false;
           gsi_next (gsi);
@@ -2061,6 +2188,11 @@ remove_useless_stmts (void)
       remove_useless_stmts_1 (&gsi, &data);
     }
   while (data.repeat);
+
+#ifdef ENABLE_TYPES_CHECKING
+  verify_types_in_gimple_seq (gimple_body (current_function_decl));
+#endif
+
   return 0;
 }
 
@@ -2075,7 +2207,7 @@ struct gimple_opt_pass pass_remove_useless_stmts =
   NULL,                                        /* sub */
   NULL,                                        /* next */
   0,                                   /* static_pass_number */
-  0,                                   /* tv_id */
+  TV_NONE,                             /* tv_id */
   PROP_gimple_any,                     /* properties_required */
   0,                                   /* properties_provided */
   0,                                   /* properties_destroyed */
@@ -2183,7 +2315,7 @@ remove_bb (basic_block bb)
      loop above, so the last statement we process is the first statement
      in the block.  */
   if (loc > BUILTINS_LOCATION && LOCATION_LINE (loc) > 0)
-    warning (OPT_Wunreachable_code, "%Hwill never be executed", &loc);
+    warning_at (loc, OPT_Wunreachable_code, "will never be executed");
 
   remove_phi_nodes_and_edges_for_unreachable_block (bb);
   bb->il.gimple = NULL;
@@ -2678,6 +2810,17 @@ first_stmt (basic_block bb)
   return !gsi_end_p (i) ? gsi_stmt (i) : NULL;
 }
 
+/* Return the first non-label statement in basic block BB.  */
+
+static gimple
+first_non_label_stmt (basic_block bb)
+{
+  gimple_stmt_iterator i = gsi_start_bb (bb);
+  while (!gsi_end_p (i) && gimple_code (gsi_stmt (i)) == GIMPLE_LABEL)
+    gsi_next (&i);
+  return !gsi_end_p (i) ? gsi_stmt (i) : NULL;
+}
+
 /* Return the last statement in basic block BB.  */
 
 gimple
@@ -2743,7 +2886,7 @@ reinstall_phi_args (edge new_edge, edge old_edge)
  
       gcc_assert (result == gimple_phi_result (phi));
   
-      add_phi_arg (phi, arg, new_edge);
+      add_phi_arg (phi, arg, new_edge, redirect_edge_var_map_location (vm));
     }
   
   redirect_edge_var_map_clear (old_edge);
@@ -3107,11 +3250,12 @@ verify_types_in_gimple_min_lval (tree expr)
   return false;
 }
 
-/* Verify if EXPR is a valid GIMPLE reference expression.  Returns true
+/* Verify if EXPR is a valid GIMPLE reference expression.  If
+   REQUIRE_LVALUE is true verifies it is an lvalue.  Returns true
    if there is an error, otherwise false.  */
 
 static bool
-verify_types_in_gimple_reference (tree expr)
+verify_types_in_gimple_reference (tree expr, bool require_lvalue)
 {
   while (handled_component_p (expr))
     {
@@ -3183,7 +3327,8 @@ verify_types_in_gimple_reference (tree expr)
       expr = op;
     }
 
-  return verify_types_in_gimple_min_lval (expr);
+  return ((require_lvalue || !is_gimple_min_invariant (expr))
+         && verify_types_in_gimple_min_lval (expr));
 }
 
 /* Returns true if there is one pointer type in TYPE_POINTER_TO (SRC_OBJ)
@@ -3411,23 +3556,23 @@ verify_gimple_assign_unary (gimple stmt)
         return false;
       }
 
-    case TRUTH_NOT_EXPR:
-      {
-      }
+    case VEC_UNPACK_HI_EXPR:
+    case VEC_UNPACK_LO_EXPR:
+    case REDUC_MAX_EXPR:
+    case REDUC_MIN_EXPR:
+    case REDUC_PLUS_EXPR:
+    case VEC_UNPACK_FLOAT_HI_EXPR:
+    case VEC_UNPACK_FLOAT_LO_EXPR:
+      /* FIXME.  */
+      return false;
 
+    case TRUTH_NOT_EXPR:
     case NEGATE_EXPR:
     case ABS_EXPR:
     case BIT_NOT_EXPR:
     case PAREN_EXPR:
     case NON_LVALUE_EXPR:
     case CONJ_EXPR:
-    case REDUC_MAX_EXPR:
-    case REDUC_MIN_EXPR:
-    case REDUC_PLUS_EXPR:
-    case VEC_UNPACK_HI_EXPR:
-    case VEC_UNPACK_LO_EXPR:
-    case VEC_UNPACK_FLOAT_HI_EXPR:
-    case VEC_UNPACK_FLOAT_LO_EXPR:
       break;
 
     default:
@@ -3498,17 +3643,21 @@ verify_gimple_assign_binary (gimple stmt)
 
     case LSHIFT_EXPR:
     case RSHIFT_EXPR:
-      if (FIXED_POINT_TYPE_P (rhs1_type)
-         && INTEGRAL_TYPE_P (rhs2_type)
-         && useless_type_conversion_p (lhs_type, rhs1_type))
-       return false;
-      /* Fall through.  */
-
     case LROTATE_EXPR:
     case RROTATE_EXPR:
       {
-       if (!INTEGRAL_TYPE_P (rhs1_type)
-           || !INTEGRAL_TYPE_P (rhs2_type)
+       /* Shifts and rotates are ok on integral types, fixed point
+          types and integer vector types.  */
+       if ((!INTEGRAL_TYPE_P (rhs1_type)
+            && !FIXED_POINT_TYPE_P (rhs1_type)
+            && !(TREE_CODE (rhs1_type) == VECTOR_TYPE
+                 && TREE_CODE (TREE_TYPE (rhs1_type)) == INTEGER_TYPE))
+           || (!INTEGRAL_TYPE_P (rhs2_type)
+               /* Vector shifts of vectors are also ok.  */
+               && !(TREE_CODE (rhs1_type) == VECTOR_TYPE
+                    && TREE_CODE (TREE_TYPE (rhs1_type)) == INTEGER_TYPE
+                    && TREE_CODE (rhs2_type) == VECTOR_TYPE
+                    && TREE_CODE (TREE_TYPE (rhs2_type)) == INTEGER_TYPE))
            || !useless_type_conversion_p (lhs_type, rhs1_type))
          {
            error ("type mismatch in shift expression");
@@ -3526,7 +3675,8 @@ verify_gimple_assign_binary (gimple stmt)
       {
        if (TREE_CODE (rhs1_type) != VECTOR_TYPE
            || !(INTEGRAL_TYPE_P (TREE_TYPE (rhs1_type))
-                || FIXED_POINT_TYPE_P (TREE_TYPE (rhs1_type)))
+                || FIXED_POINT_TYPE_P (TREE_TYPE (rhs1_type))
+                || SCALAR_FLOAT_TYPE_P (TREE_TYPE (rhs1_type)))
            || (!INTEGRAL_TYPE_P (rhs2_type)
                && (TREE_CODE (rhs2_type) != VECTOR_TYPE
                    || !INTEGRAL_TYPE_P (TREE_TYPE (rhs2_type))))
@@ -3538,12 +3688,66 @@ verify_gimple_assign_binary (gimple stmt)
            debug_generic_expr (rhs2_type);
            return true;
          }
+       /* For shifting a vector of floating point components we
+          only allow shifting by a constant multiple of the element size.  */
+       if (SCALAR_FLOAT_TYPE_P (TREE_TYPE (rhs1_type))
+           && (TREE_CODE (rhs2) != INTEGER_CST
+               || !div_if_zero_remainder (EXACT_DIV_EXPR, rhs2,
+                                          TYPE_SIZE (TREE_TYPE (rhs1_type)))))
+         {
+           error ("non-element sized vector shift of floating point vector");
+           return true;
+         }
 
        return false;
       }
 
+    case PLUS_EXPR:
+      {
+       /* We use regular PLUS_EXPR for vectors.
+          ???  This just makes the checker happy and may not be what is
+          intended.  */
+       if (TREE_CODE (lhs_type) == VECTOR_TYPE
+           && POINTER_TYPE_P (TREE_TYPE (lhs_type)))
+         {
+           if (TREE_CODE (rhs1_type) != VECTOR_TYPE
+               || TREE_CODE (rhs2_type) != VECTOR_TYPE)
+             {
+               error ("invalid non-vector operands to vector valued plus");
+               return true;
+             }
+           lhs_type = TREE_TYPE (lhs_type);
+           rhs1_type = TREE_TYPE (rhs1_type);
+           rhs2_type = TREE_TYPE (rhs2_type);
+           /* PLUS_EXPR is commutative, so we might end up canonicalizing
+              the pointer to 2nd place.  */
+           if (POINTER_TYPE_P (rhs2_type))
+             {
+               tree tem = rhs1_type;
+               rhs1_type = rhs2_type;
+               rhs2_type = tem;
+             }
+           goto do_pointer_plus_expr_check;
+         }
+      }
+    /* Fallthru.  */
+    case MINUS_EXPR:
+      {
+       if (POINTER_TYPE_P (lhs_type)
+           || POINTER_TYPE_P (rhs1_type)
+           || POINTER_TYPE_P (rhs2_type))
+         {
+           error ("invalid (pointer) operands to plus/minus");
+           return true;
+         }
+
+       /* Continue with generic binary expression handling.  */
+       break;
+      }
+
     case POINTER_PLUS_EXPR:
       {
+do_pointer_plus_expr_check:
        if (!POINTER_TYPE_P (rhs1_type)
            || !useless_type_conversion_p (lhs_type, rhs1_type)
            || !useless_type_conversion_p (sizetype, rhs2_type))
@@ -3599,20 +3803,19 @@ verify_gimple_assign_binary (gimple stmt)
         connected to the operand types.  */
       return verify_gimple_comparison (lhs_type, rhs1, rhs2);
 
-    case PLUS_EXPR:
-    case MINUS_EXPR:
-      {
-       if (POINTER_TYPE_P (lhs_type)
-           || POINTER_TYPE_P (rhs1_type)
-           || POINTER_TYPE_P (rhs2_type))
-         {
-           error ("invalid (pointer) operands to plus/minus");
-           return true;
-         }
-
-       /* Continue with generic binary expression handling.  */
-       break;
-      }
+    case WIDEN_SUM_EXPR:
+    case WIDEN_MULT_EXPR:
+    case VEC_WIDEN_MULT_HI_EXPR:
+    case VEC_WIDEN_MULT_LO_EXPR:
+    case VEC_PACK_TRUNC_EXPR:
+    case VEC_PACK_SAT_EXPR:
+    case VEC_PACK_FIX_TRUNC_EXPR:
+    case VEC_EXTRACT_EVEN_EXPR:
+    case VEC_EXTRACT_ODD_EXPR:
+    case VEC_INTERLEAVE_HIGH_EXPR:
+    case VEC_INTERLEAVE_LOW_EXPR:
+      /* FIXME.  */
+      return false;
 
     case MULT_EXPR:
     case TRUNC_DIV_EXPR:
@@ -3630,17 +3833,6 @@ verify_gimple_assign_binary (gimple stmt)
     case BIT_IOR_EXPR:
     case BIT_XOR_EXPR:
     case BIT_AND_EXPR:
-    case WIDEN_SUM_EXPR:
-    case WIDEN_MULT_EXPR:
-    case VEC_WIDEN_MULT_HI_EXPR:
-    case VEC_WIDEN_MULT_LO_EXPR:
-    case VEC_PACK_TRUNC_EXPR:
-    case VEC_PACK_SAT_EXPR:
-    case VEC_PACK_FIX_TRUNC_EXPR:
-    case VEC_EXTRACT_EVEN_EXPR:
-    case VEC_EXTRACT_ODD_EXPR:
-    case VEC_INTERLEAVE_HIGH_EXPR:
-    case VEC_INTERLEAVE_LOW_EXPR:
       /* Continue with generic binary expression handling.  */
       break;
 
@@ -3683,7 +3875,7 @@ verify_gimple_assign_single (gimple stmt)
     }
 
   if (handled_component_p (lhs))
-    res |= verify_types_in_gimple_reference (lhs);
+    res |= verify_types_in_gimple_reference (lhs, true);
 
   /* Special codes we cannot handle via their class.  */
   switch (rhs_code)
@@ -3697,11 +3889,8 @@ verify_gimple_assign_single (gimple stmt)
            return true;
          }
 
-       if (!one_pointer_to_useless_type_conversion_p (lhs_type, TREE_TYPE (op))
-           /* FIXME: a longstanding wart, &a == &a[0].  */
-           && (TREE_CODE (TREE_TYPE (op)) != ARRAY_TYPE
-               || !one_pointer_to_useless_type_conversion_p (lhs_type,
-                     TREE_TYPE (TREE_TYPE (op)))))
+       if (!one_pointer_to_useless_type_conversion_p (lhs_type,
+                                                      TREE_TYPE (op)))
          {
            error ("type mismatch in address expression");
            debug_generic_stmt (lhs_type);
@@ -3709,7 +3898,7 @@ verify_gimple_assign_single (gimple stmt)
            return true;
          }
 
-       return verify_types_in_gimple_reference (op);
+       return verify_types_in_gimple_reference (op, true);
       }
 
     /* tcc_reference  */
@@ -3732,7 +3921,7 @@ verify_gimple_assign_single (gimple stmt)
          debug_generic_stmt (rhs1);
          return true;
        }
-      return res || verify_types_in_gimple_reference (rhs1);
+      return res || verify_types_in_gimple_reference (rhs1, false);
 
     /* tcc_constant  */
     case SSA_NAME:
@@ -3908,7 +4097,7 @@ verify_gimple_phi (gimple stmt)
        }
       if (!useless_type_conversion_p (type, TREE_TYPE (arg)))
        {
-         error ("Incompatible types in PHI argument");
+         error ("Incompatible types in PHI argument %u", i);
          debug_generic_stmt (type);
          debug_generic_stmt (TREE_TYPE (arg));
          return true;
@@ -3964,10 +4153,6 @@ verify_types_in_gimple_stmt (gimple stmt)
     case GIMPLE_ASM:
       return false;
 
-    case GIMPLE_CHANGE_DYNAMIC_TYPE:
-      return (!is_gimple_val (gimple_cdt_location (stmt))
-             || !POINTER_TYPE_P (TREE_TYPE (gimple_cdt_location (stmt))));
-
     case GIMPLE_PHI:
       return verify_gimple_phi (stmt);
 
@@ -4088,7 +4273,7 @@ verify_stmt (gimple_stmt_iterator *gsi)
   if (addr)
     {
       debug_generic_expr (addr);
-      inform (input_location, "in statement");
+      inform (gimple_location (gsi_stmt (*gsi)), "in statement");
       debug_gimple_stmt (stmt);
       return true;
     }
@@ -4100,7 +4285,10 @@ verify_stmt (gimple_stmt_iterator *gsi)
      to match.  */
   if (lookup_stmt_eh_region (stmt) >= 0)
     {
-      if (!stmt_could_throw_p (stmt))
+      /* During IPA passes, ipa-pure-const sets nothrow flags on calls
+         and they are updated on statements only after fixup_cfg
+        is executed at beggining of expansion stage.  */
+      if (!stmt_could_throw_p (stmt) && cgraph_state != CGRAPH_STATE_IPA_SSA)
        {
          error ("statement marked for throw, but doesn%'t");
          goto fail;
@@ -4254,6 +4442,14 @@ verify_stmts (void)
                  err |= true;
                }
            }
+
+#ifdef ENABLE_TYPES_CHECKING
+         if (verify_gimple_phi (phi))
+           {
+             debug_gimple_stmt (phi);
+             err |= true;
+           }
+#endif
        }
 
       for (gsi = gsi_start_bb (bb); !gsi_end_p (gsi); )
@@ -4273,6 +4469,7 @@ verify_stmts (void)
          if (gimple_bb (stmt) != bb)
            {
              error ("gimple_bb (stmt) is set to a wrong basic block");
+             debug_gimple_stmt (stmt);
              err |= true;
            }
 
@@ -4290,6 +4487,14 @@ verify_stmts (void)
            }
 
          err |= verify_stmt (&gsi);
+
+#ifdef ENABLE_TYPES_CHECKING
+         if (verify_types_in_gimple_stmt (gsi_stmt (gsi)))
+           {
+             debug_gimple_stmt (stmt);
+             err |= true;
+           }
+#endif
          addr = walk_gimple_op (gsi_stmt (gsi), verify_node_sharing, &wi);
          if (addr)
            {
@@ -4635,7 +4840,8 @@ gimple_make_forwarder_block (edge fallthru)
       new_phi = create_phi_node (var, bb);
       SSA_NAME_DEF_STMT (var) = new_phi;
       gimple_phi_set_result (phi, make_ssa_name (SSA_NAME_VAR (var), phi));
-      add_phi_arg (new_phi, gimple_phi_result (phi), fallthru);
+      add_phi_arg (new_phi, gimple_phi_result (phi), fallthru, 
+                  UNKNOWN_LOCATION);
     }
 
   /* Add the arguments we have stored on edges.  */
@@ -4674,7 +4880,7 @@ gimple_block_label (basic_block bb)
        }
     }
 
-  label = create_artificial_label ();
+  label = create_artificial_label (UNKNOWN_LOCATION);
   stmt = gimple_build_label (label);
   gsi_insert_before (&s, stmt, GSI_NEW_STMT);
   return label;
@@ -4741,10 +4947,13 @@ gimple_redirect_edge_and_branch (edge e, basic_block dest)
   if (e->dest == dest)
     return NULL;
 
+  if (e->flags & EDGE_EH)
+    return redirect_eh_edge (e, dest);
+
   gsi = gsi_last_bb (bb);
   stmt = gsi_end_p (gsi) ? NULL : gsi_stmt (gsi);
 
-  switch (stmt ? gimple_code (stmt) : ERROR_MARK)
+  switch (stmt ? gimple_code (stmt) : GIMPLE_ERROR_MARK)
     {
     case GIMPLE_COND:
       /* For COND_EXPR, we only need to redirect the edge.  */
@@ -4833,7 +5042,7 @@ gimple_redirect_edge_and_branch (edge e, basic_block dest)
 static bool
 gimple_can_remove_branch_p (const_edge e)
 {
-  if (e->flags & EDGE_ABNORMAL)
+  if (e->flags & (EDGE_ABNORMAL | EDGE_EH))
     return false;
 
   return true;
@@ -5031,7 +5240,8 @@ add_phi_args_after_copy_edge (edge e_copy)
       phi = gsi_stmt (psi);
       phi_copy = gsi_stmt (psi_copy);
       def = PHI_ARG_DEF_FROM_EDGE (phi, e);
-      add_phi_arg (phi_copy, def, e_copy);
+      add_phi_arg (phi_copy, def, e_copy, 
+                  gimple_phi_arg_location_from_edge (phi, e));
     }
 }
 
@@ -5830,7 +6040,7 @@ new_label_mapper (tree decl, void *data)
   m = XNEW (struct tree_map);
   m->hash = DECL_UID (decl);
   m->base.from = decl;
-  m->to = create_artificial_label ();
+  m->to = create_artificial_label (UNKNOWN_LOCATION);
   LABEL_DECL_UID (m->to) = LABEL_DECL_UID (decl);
   if (LABEL_DECL_UID (m->to) >= cfun->cfg->last_label_uid)
     cfun->cfg->last_label_uid = LABEL_DECL_UID (m->to) + 1;
@@ -6622,20 +6832,6 @@ gimple_purge_dead_abnormal_call_edges (basic_block bb)
   return changed;
 }
 
-/* Stores all basic blocks dominated by BB to DOM_BBS.  */
-
-static void
-get_all_dominated_blocks (basic_block bb, VEC (basic_block, heap) **dom_bbs)
-{
-  basic_block son;
-
-  VEC_safe_push (basic_block, heap, *dom_bbs, bb);
-  for (son = first_dom_son (CDI_DOMINATORS, bb);
-       son;
-       son = next_dom_son (CDI_DOMINATORS, son))
-    get_all_dominated_blocks (son, dom_bbs);
-}
-
 /* Removes edge E and all the blocks dominated by it, and updates dominance
    information.  The IL in E->src needs to be updated separately.
    If dominance info is not available, only the edge E is removed.*/
@@ -6695,7 +6891,7 @@ remove_edge_and_dominated_blocks (edge e)
                    get_immediate_dominator (CDI_DOMINATORS, e->dest)->index);
   else
     {
-      get_all_dominated_blocks (e->dest, &bbs_to_remove);
+      bbs_to_remove = get_all_dominated_blocks (CDI_DOMINATORS, e->dest);
       for (i = 0; VEC_iterate (basic_block, bbs_to_remove, i, bb); i++)
        {
          FOR_EACH_EDGE (f, ei, bb->succs)
@@ -6864,7 +7060,7 @@ gimple_lv_adjust_loop_header_phi (basic_block first, basic_block second,
       phi1 = gsi_stmt (psi1);
       phi2 = gsi_stmt (psi2);
       def = PHI_ARG_DEF (phi2, e2->dest_idx);
-      add_phi_arg (phi1, def, e);
+      add_phi_arg (phi1, def, e, gimple_phi_arg_location_from_edge (phi2, e2));
     }
 }
 
@@ -6947,10 +7143,31 @@ split_critical_edges (void)
   FOR_ALL_BB (bb)
     {
       FOR_EACH_EDGE (e, ei, bb->succs)
-       if (EDGE_CRITICAL_P (e) && !(e->flags & EDGE_ABNORMAL))
-         {
+        {
+         if (EDGE_CRITICAL_P (e) && !(e->flags & EDGE_ABNORMAL))
            split_edge (e);
-         }
+         /* PRE inserts statements to edges and expects that 
+            since split_critical_edges was done beforehand, committing edge
+            insertions will not split more edges.  In addition to critical
+            edges we must split edges that have multiple successors and
+            end by control flow statements, such as RESX. 
+            Go ahead and split them too.  This matches the logic in
+            gimple_find_edge_insert_loc.  */
+         else if ((!single_pred_p (e->dest)
+                   || phi_nodes (e->dest)
+                   || e->dest == EXIT_BLOCK_PTR)
+                  && e->src != ENTRY_BLOCK_PTR
+                  && !(e->flags & EDGE_ABNORMAL))
+           {
+             gimple_stmt_iterator gsi;
+
+             gsi = gsi_last_bb (e->src);
+             if (!gsi_end_p (gsi)
+                 && stmt_ends_bb_p (gsi_stmt (gsi))
+                 && gimple_code (gsi_stmt (gsi)) != GIMPLE_RETURN)
+               split_edge (e);
+           }
+       }
     }
   end_recording_case_labels ();
   return 0;
@@ -6971,7 +7188,7 @@ struct gimple_opt_pass pass_split_crit_edges =
   PROP_no_crit_edges,            /* properties_provided */
   0,                             /* properties_destroyed */
   0,                             /* todo_flags_start */
-  TODO_dump_func                 /* todo_flags_finish */
+  TODO_dump_func | TODO_verify_flow  /* todo_flags_finish */
  }
 };
 
@@ -6984,8 +7201,9 @@ gimplify_build3 (gimple_stmt_iterator *gsi, enum tree_code code,
                 tree type, tree a, tree b, tree c)
 {
   tree ret;
+  location_t loc = gimple_location (gsi_stmt (*gsi));
 
-  ret = fold_build3 (code, type, a, b, c);
+  ret = fold_build3_loc (loc, code, type, a, b, c);
   STRIP_NOPS (ret);
 
   return force_gimple_operand_gsi (gsi, ret, true, NULL, true,
@@ -7001,7 +7219,7 @@ gimplify_build2 (gimple_stmt_iterator *gsi, enum tree_code code,
 {
   tree ret;
 
-  ret = fold_build2 (code, type, a, b);
+  ret = fold_build2_loc (gimple_location (gsi_stmt (*gsi)), code, type, a, b);
   STRIP_NOPS (ret);
 
   return force_gimple_operand_gsi (gsi, ret, true, NULL, true,
@@ -7017,7 +7235,7 @@ gimplify_build1 (gimple_stmt_iterator *gsi, enum tree_code code, tree type,
 {
   tree ret;
 
-  ret = fold_build1 (code, type, a);
+  ret = fold_build1_loc (gimple_location (gsi_stmt (*gsi)), code, type, a);
   STRIP_NOPS (ret);
 
   return force_gimple_operand_gsi (gsi, ret, true, NULL, true,
@@ -7050,7 +7268,7 @@ execute_warn_function_return (void)
        }
       if (location == UNKNOWN_LOCATION)
        location = cfun->function_end_locus;
-      warning (0, "%H%<noreturn%> function does return", &location);
+      warning_at (location, 0, "%<noreturn%> function does return");
     }
 
   /* If we see "return;" in some basic block, then we do reach the end
@@ -7114,7 +7332,7 @@ struct gimple_opt_pass pass_warn_function_return =
   NULL,                                        /* sub */
   NULL,                                        /* next */
   0,                                   /* static_pass_number */
-  0,                                   /* tv_id */
+  TV_NONE,                             /* tv_id */
   PROP_cfg,                            /* properties_required */
   0,                                   /* properties_provided */
   0,                                   /* properties_destroyed */
@@ -7132,9 +7350,9 @@ execute_warn_function_noreturn (void)
       && !TREE_THIS_VOLATILE (cfun->decl)
       && EDGE_COUNT (EXIT_BLOCK_PTR->preds) == 0
       && !lang_hooks.missing_noreturn_ok_p (cfun->decl))
-    warning (OPT_Wmissing_noreturn, "%Jfunction might be possible candidate "
-            "for attribute %<noreturn%>",
-            cfun->decl);
+    warning_at (DECL_SOURCE_LOCATION (cfun->decl), OPT_Wmissing_noreturn,
+               "function might be possible candidate "
+               "for attribute %<noreturn%>");
   return 0;
 }
 
@@ -7148,7 +7366,7 @@ struct gimple_opt_pass pass_warn_function_noreturn =
   NULL,                                        /* sub */
   NULL,                                        /* next */
   0,                                   /* static_pass_number */
-  0,                                   /* tv_id */
+  TV_NONE,                             /* tv_id */
   PROP_cfg,                            /* properties_required */
   0,                                   /* properties_provided */
   0,                                   /* properties_destroyed */
@@ -7156,3 +7374,100 @@ struct gimple_opt_pass pass_warn_function_noreturn =
   0                                    /* todo_flags_finish */
  }
 };
+
+
+/* Walk a gimplified function and warn for functions whose return value is
+   ignored and attribute((warn_unused_result)) is set.  This is done before
+   inlining, so we don't have to worry about that.  */
+
+static void
+do_warn_unused_result (gimple_seq seq)
+{
+  tree fdecl, ftype;
+  gimple_stmt_iterator i;
+
+  for (i = gsi_start (seq); !gsi_end_p (i); gsi_next (&i))
+    {
+      gimple g = gsi_stmt (i);
+
+      switch (gimple_code (g))
+       {
+       case GIMPLE_BIND:
+         do_warn_unused_result (gimple_bind_body (g));
+         break;
+       case GIMPLE_TRY:
+         do_warn_unused_result (gimple_try_eval (g));
+         do_warn_unused_result (gimple_try_cleanup (g));
+         break;
+       case GIMPLE_CATCH:
+         do_warn_unused_result (gimple_catch_handler (g));
+         break;
+       case GIMPLE_EH_FILTER:
+         do_warn_unused_result (gimple_eh_filter_failure (g));
+         break;
+
+       case GIMPLE_CALL:
+         if (gimple_call_lhs (g))
+           break;
+
+         /* This is a naked call, as opposed to a GIMPLE_CALL with an
+            LHS.  All calls whose value is ignored should be
+            represented like this.  Look for the attribute.  */
+         fdecl = gimple_call_fndecl (g);
+         ftype = TREE_TYPE (TREE_TYPE (gimple_call_fn (g)));
+
+         if (lookup_attribute ("warn_unused_result", TYPE_ATTRIBUTES (ftype)))
+           {
+             location_t loc = gimple_location (g);
+
+             if (fdecl)
+               warning_at (loc, OPT_Wunused_result,
+                           "ignoring return value of %qD, "
+                           "declared with attribute warn_unused_result",
+                           fdecl);
+             else
+               warning_at (loc, OPT_Wunused_result,
+                           "ignoring return value of function "
+                           "declared with attribute warn_unused_result");
+           }
+         break;
+
+       default:
+         /* Not a container, not a call, or a call whose value is used.  */
+         break;
+       }
+    }
+}
+
+static unsigned int
+run_warn_unused_result (void)
+{
+  do_warn_unused_result (gimple_body (current_function_decl));
+  return 0;
+}
+
+static bool
+gate_warn_unused_result (void)
+{
+  return flag_warn_unused_result;
+}
+
+struct gimple_opt_pass pass_warn_unused_result =
+{
+  {
+    GIMPLE_PASS,
+    "warn_unused_result",              /* name */
+    gate_warn_unused_result,           /* gate */
+    run_warn_unused_result,            /* execute */
+    NULL,                              /* sub */
+    NULL,                              /* next */
+    0,                                 /* static_pass_number */
+    TV_NONE,                           /* tv_id */
+    PROP_gimple_any,                   /* properties_required */
+    0,                                 /* properties_provided */
+    0,                                 /* properties_destroyed */
+    0,                                 /* todo_flags_start */
+    0,                                 /* todo_flags_finish */
+  }
+};
+