OSDN Git Service

2010-05-05 Andrew Pinski <andrew.pinski@caviumnetworks.com>
[pf3gnuchains/gcc-fork.git] / gcc / cfgexpand.c
index 3f7b1d2..319b183 100644 (file)
@@ -1,5 +1,5 @@
 /* A pass for lowering trees to RTL.
-   Copyright (C) 2004, 2005, 2006, 2007, 2008, 2009
+   Copyright (C) 2004, 2005, 2006, 2007, 2008, 2009, 2010
    Free Software Foundation, Inc.
 
 This file is part of GCC.
@@ -61,7 +61,7 @@ gimple_assign_rhs_to_tree (gimple stmt)
 {
   tree t;
   enum gimple_rhs_class grhs_class;
-    
+
   grhs_class = get_gimple_rhs_class (gimple_expr_code (stmt));
 
   if (grhs_class == GIMPLE_BINARY_RHS)
@@ -77,8 +77,12 @@ gimple_assign_rhs_to_tree (gimple stmt)
     {
       t = gimple_assign_rhs1 (stmt);
       /* Avoid modifying this tree in place below.  */
-      if (gimple_has_location (stmt) && CAN_HAVE_LOCATION_P (t)
-         && gimple_location (stmt) != EXPR_LOCATION (t))
+      if ((gimple_has_location (stmt) && CAN_HAVE_LOCATION_P (t)
+          && gimple_location (stmt) != EXPR_LOCATION (t))
+         || (gimple_block (stmt)
+             && currently_expanding_to_rtl
+             && EXPR_P (t)
+             && gimple_block (stmt) != TREE_BLOCK (t)))
        t = copy_node (t);
     }
   else
@@ -86,51 +90,13 @@ gimple_assign_rhs_to_tree (gimple stmt)
 
   if (gimple_has_location (stmt) && CAN_HAVE_LOCATION_P (t))
     SET_EXPR_LOCATION (t, gimple_location (stmt));
+  if (gimple_block (stmt) && currently_expanding_to_rtl && EXPR_P (t))
+    TREE_BLOCK (t) = gimple_block (stmt);
 
   return t;
 }
 
 
-/* Verify that there is exactly single jump instruction since last and attach
-   REG_BR_PROB note specifying probability.
-   ??? We really ought to pass the probability down to RTL expanders and let it
-   re-distribute it when the conditional expands into multiple conditionals.
-   This is however difficult to do.  */
-void
-add_reg_br_prob_note (rtx last, int probability)
-{
-  if (profile_status == PROFILE_ABSENT)
-    return;
-  for (last = NEXT_INSN (last); last && NEXT_INSN (last); last = NEXT_INSN (last))
-    if (JUMP_P (last))
-      {
-       /* It is common to emit condjump-around-jump sequence when we don't know
-          how to reverse the conditional.  Special case this.  */
-       if (!any_condjump_p (last)
-           || !JUMP_P (NEXT_INSN (last))
-           || !simplejump_p (NEXT_INSN (last))
-           || !NEXT_INSN (NEXT_INSN (last))
-           || !BARRIER_P (NEXT_INSN (NEXT_INSN (last)))
-           || !NEXT_INSN (NEXT_INSN (NEXT_INSN (last)))
-           || !LABEL_P (NEXT_INSN (NEXT_INSN (NEXT_INSN (last))))
-           || NEXT_INSN (NEXT_INSN (NEXT_INSN (NEXT_INSN (last)))))
-         goto failed;
-       gcc_assert (!find_reg_note (last, REG_BR_PROB, 0));
-       add_reg_note (last, REG_BR_PROB,
-                     GEN_INT (REG_BR_PROB_BASE - probability));
-       return;
-      }
-  if (!last || !JUMP_P (last) || !any_condjump_p (last))
-    goto failed;
-  gcc_assert (!find_reg_note (last, REG_BR_PROB, 0));
-  add_reg_note (last, REG_BR_PROB, GEN_INT (probability));
-  return;
-failed:
-  if (dump_file)
-    fprintf (dump_file, "Failed to add probability note\n");
-}
-
-
 #ifndef STACK_ALIGNMENT_NEEDED
 #define STACK_ALIGNMENT_NEEDED 1
 #endif
@@ -200,6 +166,9 @@ struct stack_var
 
   /* The next stack variable in the partition, or EOC.  */
   size_t next;
+
+  /* The numbers of conflicting stack variables.  */
+  bitmap conflicts;
 };
 
 #define EOC  ((size_t)-1)
@@ -213,11 +182,6 @@ static size_t stack_vars_num;
    is non-decreasing.  */
 static size_t *stack_vars_sorted;
 
-/* We have an interference graph between such objects.  This graph
-   is lower triangular.  */
-static bool *stack_vars_conflict;
-static size_t stack_vars_conflict_alloc;
-
 /* The phase of the stack frame.  This is the known misalignment of
    virtual_stack_vars_rtx from PREFERRED_STACK_BOUNDARY.  That is,
    (frame_offset+frame_phase) % PREFERRED_STACK_BOUNDARY == 0.  */
@@ -319,49 +283,28 @@ add_stack_var (tree decl)
   stack_vars[stack_vars_num].representative = stack_vars_num;
   stack_vars[stack_vars_num].next = EOC;
 
+  /* All variables initially conflict with no other.  */
+  stack_vars[stack_vars_num].conflicts = NULL;
+
   /* Ensure that this decl doesn't get put onto the list twice.  */
   set_rtl (decl, pc_rtx);
 
   stack_vars_num++;
 }
 
-/* Compute the linear index of a lower-triangular coordinate (I, J).  */
-
-static size_t
-triangular_index (size_t i, size_t j)
-{
-  if (i < j)
-    {
-      size_t t;
-      t = i, i = j, j = t;
-    }
-  return (i * (i + 1)) / 2 + j;
-}
-
-/* Ensure that STACK_VARS_CONFLICT is large enough for N objects.  */
-
-static void
-resize_stack_vars_conflict (size_t n)
-{
-  size_t size = triangular_index (n-1, n-1) + 1;
-
-  if (size <= stack_vars_conflict_alloc)
-    return;
-
-  stack_vars_conflict = XRESIZEVEC (bool, stack_vars_conflict, size);
-  memset (stack_vars_conflict + stack_vars_conflict_alloc, 0,
-         (size - stack_vars_conflict_alloc) * sizeof (bool));
-  stack_vars_conflict_alloc = size;
-}
-
 /* Make the decls associated with luid's X and Y conflict.  */
 
 static void
 add_stack_var_conflict (size_t x, size_t y)
 {
-  size_t index = triangular_index (x, y);
-  gcc_assert (index < stack_vars_conflict_alloc);
-  stack_vars_conflict[index] = true;
+  struct stack_var *a = &stack_vars[x];
+  struct stack_var *b = &stack_vars[y];
+  if (!a->conflicts)
+    a->conflicts = BITMAP_ALLOC (NULL);
+  if (!b->conflicts)
+    b->conflicts = BITMAP_ALLOC (NULL);
+  bitmap_set_bit (a->conflicts, y);
+  bitmap_set_bit (b->conflicts, x);
 }
 
 /* Check whether the decls associated with luid's X and Y conflict.  */
@@ -369,11 +312,13 @@ add_stack_var_conflict (size_t x, size_t y)
 static bool
 stack_var_conflict_p (size_t x, size_t y)
 {
-  size_t index = triangular_index (x, y);
-  gcc_assert (index < stack_vars_conflict_alloc);
-  return stack_vars_conflict[index];
+  struct stack_var *a = &stack_vars[x];
+  struct stack_var *b = &stack_vars[y];
+  if (!a->conflicts || !b->conflicts)
+    return false;
+  return bitmap_bit_p (a->conflicts, y);
 }
+
 /* Returns true if TYPE is or contains a union type.  */
 
 static bool
@@ -555,12 +500,12 @@ update_alias_info_with_stack_vars (void)
       for (j = i; j != EOC; j = stack_vars[j].next)
        {
          tree decl = stack_vars[j].decl;
-         unsigned int uid = DECL_UID (decl);
+         unsigned int uid = DECL_PT_UID (decl);
          /* We should never end up partitioning SSA names (though they
             may end up on the stack).  Neither should we allocate stack
             space to something that is unused and thus unreferenced.  */
          gcc_assert (DECL_P (decl)
-                     && referenced_var_lookup (uid));
+                     && referenced_var_lookup (DECL_UID (decl)));
          bitmap_set_bit (part, uid);
          *((bitmap *) pointer_map_insert (decls_to_partitions,
                                           (void *)(size_t) uid)) = part;
@@ -570,7 +515,7 @@ update_alias_info_with_stack_vars (void)
 
       /* Make the SSA name point to all partition members.  */
       pi = get_ptr_info (name);
-      pt_solution_set (&pi->pt, part);
+      pt_solution_set (&pi->pt, part, false, false);
     }
 
   /* Make all points-to sets that contain one member of a partition
@@ -595,8 +540,6 @@ update_alias_info_with_stack_vars (void)
 
       add_partitioned_vars_to_ptset (&cfun->gimple_df->escaped,
                                     decls_to_partitions, visited, temp);
-      add_partitioned_vars_to_ptset (&cfun->gimple_df->callused,
-                                    decls_to_partitions, visited, temp);
 
       pointer_set_destroy (visited);
       pointer_map_destroy (decls_to_partitions);
@@ -616,6 +559,9 @@ static void
 union_stack_vars (size_t a, size_t b, HOST_WIDE_INT offset)
 {
   size_t i, last;
+  struct stack_var *vb = &stack_vars[b];
+  bitmap_iterator bi;
+  unsigned u;
 
   /* Update each element of partition B with the given offset,
      and merge them into partition A.  */
@@ -632,9 +578,12 @@ union_stack_vars (size_t a, size_t b, HOST_WIDE_INT offset)
     stack_vars[a].alignb = stack_vars[b].alignb;
 
   /* Update the interference graph and merge the conflicts.  */
-  for (last = stack_vars_num, i = 0; i < last; ++i)
-    if (stack_var_conflict_p (b, i))
-      add_stack_var_conflict (a, i);
+  if (vb->conflicts)
+    {
+      EXECUTE_IF_SET_IN_BITMAP (vb->conflicts, 0, u, bi)
+       add_stack_var_conflict (a, stack_vars[u].representative);
+      BITMAP_FREE (vb->conflicts);
+    }
 }
 
 /* A subroutine of expand_used_vars.  Binpack the variables into
@@ -669,15 +618,6 @@ partition_stack_vars (void)
 
   qsort (stack_vars_sorted, n, sizeof (size_t), stack_var_size_cmp);
 
-  /* Special case: detect when all variables conflict, and thus we can't
-     do anything during the partitioning loop.  It isn't uncommon (with
-     C code at least) to declare all variables at the top of the function,
-     and if we're not inlining, then all variables will be in the same scope.
-     Take advantage of very fast libc routines for this scan.  */
-  gcc_assert (sizeof(bool) == sizeof(char));
-  if (memchr (stack_vars_conflict, false, stack_vars_conflict_alloc) == NULL)
-    return;
-
   for (si = 0; si < n; ++si)
     {
       size_t i = stack_vars_sorted[si];
@@ -962,7 +902,7 @@ defer_stack_allocation (tree var, bool toplevel)
 
 /* A subroutine of expand_used_vars.  Expand one variable according to
    its flavor.  Variables to be placed on the stack are not actually
-   expanded yet, merely recorded.  
+   expanded yet, merely recorded.
    When REALLY_EXPAND is false, only add stack values to be allocated.
    Return stack usage this variable is supposed to take.
 */
@@ -1035,6 +975,14 @@ expand_one_var (tree var, bool toplevel, bool really_expand)
       if (really_expand)
         expand_one_register_var (origvar);
     }
+  else if (!host_integerp (DECL_SIZE_UNIT (var), 1))
+    {
+      if (really_expand)
+       {
+         error ("size of variable %q+D is too large", var);
+         expand_one_error_var (var);
+       }
+    }
   else if (defer_stack_allocation (var, toplevel))
     add_stack_var (origvar);
   else
@@ -1074,15 +1022,13 @@ expand_used_vars_for_block (tree block, bool toplevel)
   /* Since we do not track exact variable lifetimes (which is not even
      possible for variables whose address escapes), we mirror the block
      tree in the interference graph.  Here we cause all variables at this
-     level, and all sublevels, to conflict.  Do make certain that a
-     variable conflicts with itself.  */
+     level, and all sublevels, to conflict.  */
   if (old_sv_num < this_sv_num)
     {
       new_sv_num = stack_vars_num;
-      resize_stack_vars_conflict (new_sv_num);
 
       for (i = old_sv_num; i < new_sv_num; ++i)
-       for (j = i < this_sv_num ? i+1 : this_sv_num; j-- > old_sv_num ;)
+       for (j = i < this_sv_num ? i : this_sv_num; j-- > old_sv_num ;)
          add_stack_var_conflict (i, j);
     }
 }
@@ -1250,42 +1196,23 @@ create_stack_guard (void)
 static HOST_WIDE_INT
 account_used_vars_for_block (tree block, bool toplevel)
 {
-  size_t i, j, old_sv_num, this_sv_num, new_sv_num;
   tree t;
   HOST_WIDE_INT size = 0;
 
-  old_sv_num = toplevel ? 0 : stack_vars_num;
-
   /* Expand all variables at this level.  */
   for (t = BLOCK_VARS (block); t ; t = TREE_CHAIN (t))
     if (TREE_USED (t))
       size += expand_one_var (t, toplevel, false);
 
-  this_sv_num = stack_vars_num;
-
   /* Expand all variables at containing levels.  */
   for (t = BLOCK_SUBBLOCKS (block); t ; t = BLOCK_CHAIN (t))
     size += account_used_vars_for_block (t, false);
 
-  /* Since we do not track exact variable lifetimes (which is not even
-     possible for variables whose address escapes), we mirror the block
-     tree in the interference graph.  Here we cause all variables at this
-     level, and all sublevels, to conflict.  Do make certain that a
-     variable conflicts with itself.  */
-  if (old_sv_num < this_sv_num)
-    {
-      new_sv_num = stack_vars_num;
-      resize_stack_vars_conflict (new_sv_num);
-
-      for (i = old_sv_num; i < new_sv_num; ++i)
-       for (j = i < this_sv_num ? i+1 : this_sv_num; j-- > old_sv_num ;)
-         add_stack_var_conflict (i, j);
-    }
   return size;
 }
 
 /* Prepare for expanding variables.  */
-static void 
+static void
 init_vars_expansion (void)
 {
   tree t;
@@ -1305,13 +1232,13 @@ init_vars_expansion (void)
 static void
 fini_vars_expansion (void)
 {
+  size_t i, n = stack_vars_num;
+  for (i = 0; i < n; i++)
+    BITMAP_FREE (stack_vars[i].conflicts);
   XDELETEVEC (stack_vars);
   XDELETEVEC (stack_vars_sorted);
-  XDELETEVEC (stack_vars_conflict);
   stack_vars = NULL;
   stack_vars_alloc = stack_vars_num = 0;
-  stack_vars_conflict = NULL;
-  stack_vars_conflict_alloc = 0;
 }
 
 /* Make a fair guess for the size of the stack frame of the current
@@ -1360,6 +1287,7 @@ static void
 expand_used_vars (void)
 {
   tree t, next, outer_block = DECL_INITIAL (current_function_decl);
+  tree maybe_local_decls = NULL_TREE;
   unsigned i;
 
   /* Compute the phase of the stack frame for this function.  */
@@ -1408,8 +1336,7 @@ expand_used_vars (void)
       if (is_gimple_reg (var))
        {
          TREE_USED (var) = 0;
-         ggc_free (t);
-         continue;
+         goto next;
        }
       /* We didn't set a block for static or extern because it's hard
         to tell the difference between a global variable (re)declared
@@ -1430,20 +1357,29 @@ expand_used_vars (void)
       TREE_USED (var) = 1;
 
       if (expand_now)
+       expand_one_var (var, true, true);
+
+    next:
+      if (DECL_ARTIFICIAL (var) && !DECL_IGNORED_P (var))
        {
-         expand_one_var (var, true, true);
-         if (DECL_ARTIFICIAL (var) && !DECL_IGNORED_P (var))
-           {
-             rtx rtl = DECL_RTL_IF_SET (var);
+         rtx rtl = DECL_RTL_IF_SET (var);
 
-             /* Keep artificial non-ignored vars in cfun->local_decls
-                chain until instantiate_decls.  */
-             if (rtl && (MEM_P (rtl) || GET_CODE (rtl) == CONCAT))
-               {
-                 TREE_CHAIN (t) = cfun->local_decls;
-                 cfun->local_decls = t;
-                 continue;
-               }
+         /* Keep artificial non-ignored vars in cfun->local_decls
+            chain until instantiate_decls.  */
+         if (rtl && (MEM_P (rtl) || GET_CODE (rtl) == CONCAT))
+           {
+             TREE_CHAIN (t) = cfun->local_decls;
+             cfun->local_decls = t;
+             continue;
+           }
+         else if (rtl == NULL_RTX)
+           {
+             /* If rtl isn't set yet, which can happen e.g. with
+                -fstack-protector, retry before returning from this
+                function.  */
+             TREE_CHAIN (t) = maybe_local_decls;
+             maybe_local_decls = t;
+             continue;
            }
        }
 
@@ -1503,6 +1439,28 @@ expand_used_vars (void)
       fini_vars_expansion ();
     }
 
+  /* If there were any artificial non-ignored vars without rtl
+     found earlier, see if deferred stack allocation hasn't assigned
+     rtl to them.  */
+  for (t = maybe_local_decls; t; t = next)
+    {
+      tree var = TREE_VALUE (t);
+      rtx rtl = DECL_RTL_IF_SET (var);
+
+      next = TREE_CHAIN (t);
+
+      /* Keep artificial non-ignored vars in cfun->local_decls
+        chain until instantiate_decls.  */
+      if (rtl && (MEM_P (rtl) || GET_CODE (rtl) == CONCAT))
+       {
+         TREE_CHAIN (t) = cfun->local_decls;
+         cfun->local_decls = t;
+         continue;
+       }
+
+      ggc_free (t);
+    }
+
   /* If the target requires that FRAME_OFFSET be aligned, do it.  */
   if (STACK_ALIGNMENT_NEEDED)
     {
@@ -1554,7 +1512,7 @@ label_rtx_for_bb (basic_block bb ATTRIBUTE_UNUSED)
     return (rtx) *elt;
 
   /* Find the tree label if it is present.  */
-     
+
   for (gsi = gsi_start_bb (bb); !gsi_end_p (gsi); gsi_next (&gsi))
     {
       lab_stmt = gsi_stmt (gsi);
@@ -1576,10 +1534,11 @@ label_rtx_for_bb (basic_block bb ATTRIBUTE_UNUSED)
 
 /* A subroutine of expand_gimple_cond.  Given E, a fallthrough edge
    of a basic block where we just expanded the conditional at the end,
-   possibly clean up the CFG and instruction sequence.  */
+   possibly clean up the CFG and instruction sequence.  LAST is the
+   last instruction before the just emitted jump sequence.  */
 
 static void
-maybe_cleanup_end_of_block (edge e)
+maybe_cleanup_end_of_block (edge e, rtx last)
 {
   /* Special case: when jumpif decides that the condition is
      trivial it emits an unconditional jump (and the necessary
@@ -1594,7 +1553,6 @@ maybe_cleanup_end_of_block (edge e)
      normally isn't there in a cleaned CFG), fix it here.  */
   if (BARRIER_P (get_last_insn ()))
     {
-      basic_block bb = e->src;
       rtx insn;
       remove_edge (e);
       /* Now, we have a single successor block, if we have insns to
@@ -1610,7 +1568,7 @@ maybe_cleanup_end_of_block (edge e)
       /* Make sure we have an unconditional jump.  Otherwise we're
         confused.  */
       gcc_assert (JUMP_P (insn) && !any_condjump_p (insn));
-      for (insn = PREV_INSN (insn); insn != BB_HEAD (bb);)
+      for (insn = PREV_INSN (insn); insn != last;)
        {
          insn = PREV_INSN (insn);
          if (JUMP_P (NEXT_INSN (insn)))
@@ -1651,13 +1609,35 @@ expand_gimple_cond (basic_block bb, gimple stmt)
       && bitmap_bit_p (SA.values, SSA_NAME_VERSION (op0)))
     {
       gimple second = SSA_NAME_DEF_STMT (op0);
-      if (gimple_code (second) == GIMPLE_ASSIGN
-         && TREE_CODE_CLASS (gimple_assign_rhs_code (second))
-            == tcc_comparison)
+      if (gimple_code (second) == GIMPLE_ASSIGN)
        {
-         code = gimple_assign_rhs_code (second);
-         op0 = gimple_assign_rhs1 (second);
-         op1 = gimple_assign_rhs2 (second);
+         enum tree_code code2 = gimple_assign_rhs_code (second);
+         if (TREE_CODE_CLASS (code2) == tcc_comparison)
+           {
+             code = code2;
+             op0 = gimple_assign_rhs1 (second);
+             op1 = gimple_assign_rhs2 (second);
+           }
+         /* If jumps are cheap turn some more codes into
+            jumpy sequences.  */
+         else if (BRANCH_COST (optimize_insn_for_speed_p (), false) < 4)
+           {
+             if ((code2 == BIT_AND_EXPR
+                  && TYPE_PRECISION (TREE_TYPE (op0)) == 1
+                  && TREE_CODE (gimple_assign_rhs2 (second)) != INTEGER_CST)
+                 || code2 == TRUTH_AND_EXPR)
+               {
+                 code = TRUTH_ANDIF_EXPR;
+                 op0 = gimple_assign_rhs1 (second);
+                 op1 = gimple_assign_rhs2 (second);
+               }
+             else if (code2 == BIT_IOR_EXPR || code2 == TRUTH_OR_EXPR)
+               {
+                 code = TRUTH_ORIF_EXPR;
+                 op0 = gimple_assign_rhs1 (second);
+                 op1 = gimple_assign_rhs2 (second);
+               }
+           }
        }
     }
 
@@ -1678,8 +1658,8 @@ expand_gimple_cond (basic_block bb, gimple stmt)
      two-way jump that needs to be decomposed into two basic blocks.  */
   if (false_edge->dest == bb->next_bb)
     {
-      jumpif_1 (code, op0, op1, label_rtx_for_bb (true_edge->dest));
-      add_reg_br_prob_note (last, true_edge->probability);
+      jumpif_1 (code, op0, op1, label_rtx_for_bb (true_edge->dest),
+               true_edge->probability);
       maybe_dump_rtl_for_gimple_stmt (stmt, last);
       if (true_edge->goto_locus)
        {
@@ -1689,13 +1669,13 @@ expand_gimple_cond (basic_block bb, gimple stmt)
        }
       true_edge->goto_block = NULL;
       false_edge->flags |= EDGE_FALLTHRU;
-      maybe_cleanup_end_of_block (false_edge);
+      maybe_cleanup_end_of_block (false_edge, last);
       return NULL;
     }
   if (true_edge->dest == bb->next_bb)
     {
-      jumpifnot_1 (code, op0, op1, label_rtx_for_bb (false_edge->dest));
-      add_reg_br_prob_note (last, false_edge->probability);
+      jumpifnot_1 (code, op0, op1, label_rtx_for_bb (false_edge->dest),
+                  false_edge->probability);
       maybe_dump_rtl_for_gimple_stmt (stmt, last);
       if (false_edge->goto_locus)
        {
@@ -1705,12 +1685,12 @@ expand_gimple_cond (basic_block bb, gimple stmt)
        }
       false_edge->goto_block = NULL;
       true_edge->flags |= EDGE_FALLTHRU;
-      maybe_cleanup_end_of_block (true_edge);
+      maybe_cleanup_end_of_block (true_edge, last);
       return NULL;
     }
 
-  jumpif_1 (code, op0, op1, label_rtx_for_bb (true_edge->dest));
-  add_reg_br_prob_note (last, true_edge->probability);
+  jumpif_1 (code, op0, op1, label_rtx_for_bb (true_edge->dest),
+           true_edge->probability);
   last = get_last_insn ();
   if (false_edge->goto_locus)
     {
@@ -1761,15 +1741,31 @@ expand_call_stmt (gimple stmt)
   tree exp;
   tree lhs = gimple_call_lhs (stmt);
   size_t i;
+  bool builtin_p;
+  tree decl;
 
   exp = build_vl_exp (CALL_EXPR, gimple_call_num_args (stmt) + 3);
 
   CALL_EXPR_FN (exp) = gimple_call_fn (stmt);
+  decl = gimple_call_fndecl (stmt);
+  builtin_p = decl && DECL_BUILT_IN (decl);
+
   TREE_TYPE (exp) = gimple_call_return_type (stmt);
   CALL_EXPR_STATIC_CHAIN (exp) = gimple_call_chain (stmt);
 
   for (i = 0; i < gimple_call_num_args (stmt); i++)
-    CALL_EXPR_ARG (exp, i) = gimple_call_arg (stmt, i);
+    {
+      tree arg = gimple_call_arg (stmt, i);
+      gimple def;
+      /* TER addresses into arguments of builtin functions so we have a
+        chance to infer more correct alignment information.  See PR39954.  */
+      if (builtin_p
+         && TREE_CODE (arg) == SSA_NAME
+         && (def = get_gimple_for_ssa_name (arg))
+         && gimple_assign_rhs_code (def) == ADDR_EXPR)
+       arg = gimple_assign_rhs1 (def);
+      CALL_EXPR_ARG (exp, i) = arg;
+    }
 
   if (gimple_has_side_effects (stmt))
     TREE_SIDE_EFFECTS (exp) = 1;
@@ -2231,7 +2227,6 @@ expand_debug_expr (tree exp)
   int unsignedp = TYPE_UNSIGNED (TREE_TYPE (exp));
   addr_space_t as;
   enum machine_mode address_mode;
-  enum machine_mode pointer_mode;
 
   switch (TREE_CODE_CLASS (TREE_CODE (exp)))
     {
@@ -2239,6 +2234,7 @@ expand_debug_expr (tree exp)
       switch (TREE_CODE (exp))
        {
        case COND_EXPR:
+       case DOT_PROD_EXPR:
          goto ternary;
 
        case TRUTH_ANDIF_EXPR:
@@ -2347,8 +2343,7 @@ expand_debug_expr (tree exp)
              || mode == VOIDmode)
            return NULL;
 
-         op0 = DECL_RTL (exp);
-         SET_DECL_RTL (exp, NULL);
+         op0 = make_decl_rtl_for_debug (exp);
          if (!MEM_P (op0)
              || GET_CODE (XEXP (op0, 0)) != SYMBOL_REF
              || SYMBOL_REF_DECL (XEXP (op0, 0)) != exp)
@@ -2357,7 +2352,12 @@ expand_debug_expr (tree exp)
       else
        op0 = copy_rtx (op0);
 
-      if (GET_MODE (op0) == BLKmode)
+      if (GET_MODE (op0) == BLKmode
+         /* If op0 is not BLKmode, but BLKmode is, adjust_mode
+            below would ICE.  While it is likely a FE bug,
+            try to be robust here.  See PR43166.  */
+         || mode == BLKmode
+         || (mode == VOIDmode && GET_MODE (op0) != VOIDmode))
        {
          gcc_assert (MEM_P (op0));
          op0 = adjust_address_nv (op0, mode, 0);
@@ -2378,7 +2378,10 @@ expand_debug_expr (tree exp)
 
        if (inner_mode == VOIDmode)
          {
-           inner_mode = TYPE_MODE (TREE_TYPE (TREE_OPERAND (exp, 0)));
+           if (TREE_CODE (exp) == SSA_NAME)
+             inner_mode = TYPE_MODE (TREE_TYPE (exp));
+           else
+             inner_mode = TYPE_MODE (TREE_TYPE (TREE_OPERAND (exp, 0)));
            if (mode == inner_mode)
              return op0;
          }
@@ -2394,6 +2397,7 @@ expand_debug_expr (tree exp)
          }
        else if (FLOAT_MODE_P (mode))
          {
+           gcc_assert (TREE_CODE (exp) != SSA_NAME);
            if (TYPE_UNSIGNED (TREE_TYPE (TREE_OPERAND (exp, 0))))
              op0 = simplify_gen_unary (UNSIGNED_FLOAT, mode, op0, inner_mode);
            else
@@ -2427,17 +2431,15 @@ expand_debug_expr (tree exp)
        return NULL;
 
       if (POINTER_TYPE_P (TREE_TYPE (exp)))
-       as = TYPE_ADDR_SPACE (TREE_TYPE (TREE_TYPE (exp)));
+       {
+         as = TYPE_ADDR_SPACE (TREE_TYPE (TREE_TYPE (exp)));
+         address_mode = targetm.addr_space.address_mode (as);
+       }
       else
-       as = ADDR_SPACE_GENERIC;
-
-      address_mode = targetm.addr_space.address_mode (as);
-      pointer_mode = targetm.addr_space.pointer_mode (as);
-
-      gcc_assert (GET_MODE (op0) == address_mode
-                 || GET_MODE (op0) == pointer_mode
-                 || GET_CODE (op0) == CONST_INT
-                 || GET_CODE (op0) == CONST_DOUBLE);
+       {
+         as = ADDR_SPACE_GENERIC;
+         address_mode = Pmode;
+       }
 
       if (TREE_CODE (exp) == ALIGN_INDIRECT_REF)
        {
@@ -2457,19 +2459,11 @@ expand_debug_expr (tree exp)
        return NULL;
 
       op0 = expand_debug_expr
-       (tree_mem_ref_addr (build_pointer_type (TREE_TYPE (exp)),
-                           exp));
+           (tree_mem_ref_addr (build_pointer_type (TREE_TYPE (exp)), exp));
       if (!op0)
        return NULL;
 
       as = TYPE_ADDR_SPACE (TREE_TYPE (exp));
-      address_mode = targetm.addr_space.address_mode (as);
-      pointer_mode = targetm.addr_space.pointer_mode (as);
-
-      gcc_assert (GET_MODE (op0) == address_mode
-                 || GET_MODE (op0) == pointer_mode
-                 || GET_CODE (op0) == CONST_INT
-                 || GET_CODE (op0) == CONST_DOUBLE);
 
       op0 = gen_rtx_MEM (mode, op0);
 
@@ -2506,7 +2500,8 @@ expand_debug_expr (tree exp)
          {
            enum machine_mode addrmode, offmode;
 
-           gcc_assert (MEM_P (op0));
+           if (!MEM_P (op0))
+             return NULL;
 
            op0 = XEXP (op0, 0);
            addrmode = GET_MODE (op0);
@@ -2585,8 +2580,9 @@ expand_debug_expr (tree exp)
            if (bitpos >= GET_MODE_BITSIZE (opmode))
              return NULL;
 
-           return simplify_gen_subreg (mode, op0, opmode,
-                                       bitpos / BITS_PER_UNIT);
+           if ((bitpos % GET_MODE_BITSIZE (mode)) == 0)
+             return simplify_gen_subreg (mode, op0, opmode,
+                                         bitpos / BITS_PER_UNIT);
          }
 
        return simplify_gen_ternary (SCALAR_INT_MODE_P (GET_MODE (op0))
@@ -2620,6 +2616,22 @@ expand_debug_expr (tree exp)
        return gen_rtx_FIX (mode, op0);
 
     case POINTER_PLUS_EXPR:
+      /* For the rare target where pointers are not the same size as
+        size_t, we need to check for mis-matched modes and correct
+        the addend.  */
+      if (op0 && op1
+         && GET_MODE (op0) != VOIDmode && GET_MODE (op1) != VOIDmode
+         && GET_MODE (op0) != GET_MODE (op1))
+       {
+         if (GET_MODE_BITSIZE (GET_MODE (op0)) < GET_MODE_BITSIZE (GET_MODE (op1)))
+           op1 = gen_rtx_TRUNCATE (GET_MODE (op0), op1);
+         else
+           /* We always sign-extend, regardless of the signedness of
+              the operand, because the operand is always unsigned
+              here even if the original C expression is signed.  */
+           op1 = gen_rtx_SIGN_EXTEND (GET_MODE (op0), op1);
+       }
+      /* Fall through.  */
     case PLUS_EXPR:
       return gen_rtx_PLUS (mode, op0, op1);
 
@@ -2936,20 +2948,106 @@ expand_debug_expr (tree exp)
 
     case SSA_NAME:
       {
-       int part = var_to_partition (SA.map, exp);
+       gimple g = get_gimple_for_ssa_name (exp);
+       if (g)
+         {
+           op0 = expand_debug_expr (gimple_assign_rhs_to_tree (g));
+           if (!op0)
+             return NULL;
+         }
+       else
+         {
+           int part = var_to_partition (SA.map, exp);
 
-       if (part == NO_PARTITION)
-         return NULL;
+           if (part == NO_PARTITION)
+             return NULL;
 
-       gcc_assert (part >= 0 && (unsigned)part < SA.map->num_partitions);
+           gcc_assert (part >= 0 && (unsigned)part < SA.map->num_partitions);
 
-       op0 = SA.partition_to_pseudo[part];
+           op0 = SA.partition_to_pseudo[part];
+         }
        goto adjust_mode;
       }
 
     case ERROR_MARK:
       return NULL;
 
+    /* Vector stuff.  For most of the codes we don't have rtl codes.  */
+    case REALIGN_LOAD_EXPR:
+    case REDUC_MAX_EXPR:
+    case REDUC_MIN_EXPR:
+    case REDUC_PLUS_EXPR:
+    case VEC_COND_EXPR:
+    case VEC_EXTRACT_EVEN_EXPR:
+    case VEC_EXTRACT_ODD_EXPR:
+    case VEC_INTERLEAVE_HIGH_EXPR:
+    case VEC_INTERLEAVE_LOW_EXPR:
+    case VEC_LSHIFT_EXPR:
+    case VEC_PACK_FIX_TRUNC_EXPR:
+    case VEC_PACK_SAT_EXPR:
+    case VEC_PACK_TRUNC_EXPR:
+    case VEC_RSHIFT_EXPR:
+    case VEC_UNPACK_FLOAT_HI_EXPR:
+    case VEC_UNPACK_FLOAT_LO_EXPR:
+    case VEC_UNPACK_HI_EXPR:
+    case VEC_UNPACK_LO_EXPR:
+    case VEC_WIDEN_MULT_HI_EXPR:
+    case VEC_WIDEN_MULT_LO_EXPR:
+      return NULL;
+
+   /* Misc codes.  */
+    case ADDR_SPACE_CONVERT_EXPR:
+    case FIXED_CONVERT_EXPR:
+    case OBJ_TYPE_REF:
+    case WITH_SIZE_EXPR:
+      return NULL;
+
+    case DOT_PROD_EXPR:
+      if (SCALAR_INT_MODE_P (GET_MODE (op0))
+         && SCALAR_INT_MODE_P (mode))
+       {
+         if (TYPE_UNSIGNED (TREE_TYPE (TREE_OPERAND (exp, 0))))
+           op0 = gen_rtx_ZERO_EXTEND (mode, op0);
+         else
+           op0 = gen_rtx_SIGN_EXTEND (mode, op0);
+         if (TYPE_UNSIGNED (TREE_TYPE (TREE_OPERAND (exp, 1))))
+           op1 = gen_rtx_ZERO_EXTEND (mode, op1);
+         else
+           op1 = gen_rtx_SIGN_EXTEND (mode, op1);
+         op0 = gen_rtx_MULT (mode, op0, op1);
+         return gen_rtx_PLUS (mode, op0, op2);
+       }
+      return NULL;
+
+    case WIDEN_MULT_EXPR:
+      if (SCALAR_INT_MODE_P (GET_MODE (op0))
+         && SCALAR_INT_MODE_P (mode))
+       {
+         enum machine_mode inner_mode = GET_MODE (op0);
+         if (TYPE_UNSIGNED (TREE_TYPE (TREE_OPERAND (exp, 0))))
+           op0 = simplify_gen_unary (ZERO_EXTEND, mode, op0, inner_mode);
+         else
+           op0 = simplify_gen_unary (SIGN_EXTEND, mode, op0, inner_mode);
+         if (TYPE_UNSIGNED (TREE_TYPE (TREE_OPERAND (exp, 1))))
+           op1 = simplify_gen_unary (ZERO_EXTEND, mode, op1, inner_mode);
+         else
+           op1 = simplify_gen_unary (SIGN_EXTEND, mode, op1, inner_mode);
+         return gen_rtx_MULT (mode, op0, op1);
+       }
+      return NULL;
+
+    case WIDEN_SUM_EXPR:
+      if (SCALAR_INT_MODE_P (GET_MODE (op0))
+         && SCALAR_INT_MODE_P (mode))
+       {
+         if (TYPE_UNSIGNED (TREE_TYPE (TREE_OPERAND (exp, 0))))
+           op0 = gen_rtx_ZERO_EXTEND (mode, op0);
+         else
+           op0 = gen_rtx_SIGN_EXTEND (mode, op0);
+         return gen_rtx_PLUS (mode, op0, op1);
+       }
+      return NULL;
+
     default:
     flag_unsupported:
 #ifdef ENABLE_CHECKING
@@ -3100,6 +3198,105 @@ expand_gimple_basic_block (basic_block bb)
       basic_block new_bb;
 
       stmt = gsi_stmt (gsi);
+
+      /* If this statement is a non-debug one, and we generate debug
+        insns, then this one might be the last real use of a TERed
+        SSA_NAME, but where there are still some debug uses further
+        down.  Expanding the current SSA name in such further debug
+        uses by their RHS might lead to wrong debug info, as coalescing
+        might make the operands of such RHS be placed into the same
+        pseudo as something else.  Like so:
+          a_1 = a_0 + 1;   // Assume a_1 is TERed and a_0 is dead
+          use(a_1);
+          a_2 = ...
+           #DEBUG ... => a_1
+        As a_0 and a_2 don't overlap in lifetime, assume they are coalesced.
+        If we now would expand a_1 by it's RHS (a_0 + 1) in the debug use,
+        the write to a_2 would actually have clobbered the place which
+        formerly held a_0.
+
+        So, instead of that, we recognize the situation, and generate
+        debug temporaries at the last real use of TERed SSA names:
+          a_1 = a_0 + 1;
+           #DEBUG #D1 => a_1
+          use(a_1);
+          a_2 = ...
+           #DEBUG ... => #D1
+        */
+      if (MAY_HAVE_DEBUG_INSNS
+         && SA.values
+         && !is_gimple_debug (stmt))
+       {
+         ssa_op_iter iter;
+         tree op;
+         gimple def;
+
+         location_t sloc = get_curr_insn_source_location ();
+         tree sblock = get_curr_insn_block ();
+
+         /* Look for SSA names that have their last use here (TERed
+            names always have only one real use).  */
+         FOR_EACH_SSA_TREE_OPERAND (op, stmt, iter, SSA_OP_USE)
+           if ((def = get_gimple_for_ssa_name (op)))
+             {
+               imm_use_iterator imm_iter;
+               use_operand_p use_p;
+               bool have_debug_uses = false;
+
+               FOR_EACH_IMM_USE_FAST (use_p, imm_iter, op)
+                 {
+                   if (gimple_debug_bind_p (USE_STMT (use_p)))
+                     {
+                       have_debug_uses = true;
+                       break;
+                     }
+                 }
+
+               if (have_debug_uses)
+                 {
+                   /* OP is a TERed SSA name, with DEF it's defining
+                      statement, and where OP is used in further debug
+                      instructions.  Generate a debug temporary, and
+                      replace all uses of OP in debug insns with that
+                      temporary.  */
+                   gimple debugstmt;
+                   tree value = gimple_assign_rhs_to_tree (def);
+                   tree vexpr = make_node (DEBUG_EXPR_DECL);
+                   rtx val;
+                   enum machine_mode mode;
+
+                   set_curr_insn_source_location (gimple_location (def));
+                   set_curr_insn_block (gimple_block (def));
+
+                   DECL_ARTIFICIAL (vexpr) = 1;
+                   TREE_TYPE (vexpr) = TREE_TYPE (value);
+                   if (DECL_P (value))
+                     mode = DECL_MODE (value);
+                   else
+                     mode = TYPE_MODE (TREE_TYPE (value));
+                   DECL_MODE (vexpr) = mode;
+
+                   val = gen_rtx_VAR_LOCATION
+                       (mode, vexpr, (rtx)value, VAR_INIT_STATUS_INITIALIZED);
+
+                   val = emit_debug_insn (val);
+
+                   FOR_EACH_IMM_USE_STMT (debugstmt, imm_iter, op)
+                     {
+                       if (!gimple_debug_bind_p (debugstmt))
+                         continue;
+
+                       FOR_EACH_IMM_USE_ON_STMT (use_p, imm_iter)
+                         SET_USE (use_p, vexpr);
+
+                       update_stmt (debugstmt);
+                     }
+                 }
+             }
+         set_curr_insn_source_location (sloc);
+         set_curr_insn_block (sblock);
+       }
+
       currently_expanding_gimple_stmt = stmt;
 
       /* Expand this statement, then evaluate the resulting RTL and
@@ -3152,6 +3349,13 @@ expand_gimple_basic_block (basic_block bb)
                  INSN_VAR_LOCATION_LOC (val) = (rtx)value;
                }
 
+             /* In order not to generate too many debug temporaries,
+                we delink all uses of debug statements we already expanded.
+                Therefore debug statements between definition and real
+                use of TERed SSA names will continue to use the SSA name,
+                and not be replaced with debug temps.  */
+             delink_stmt_imm_use (stmt);
+
              gsi = nsi;
              gsi_next (&nsi);
              if (gsi_end_p (nsi))
@@ -3188,7 +3392,7 @@ expand_gimple_basic_block (basic_block bb)
                  /* Ignore this stmt if it is in the list of
                     replaceable expressions.  */
                  if (SA.values
-                     && bitmap_bit_p (SA.values, 
+                     && bitmap_bit_p (SA.values,
                                       SSA_NAME_VERSION (DEF_FROM_PTR (def_p))))
                    continue;
                }
@@ -3435,7 +3639,8 @@ discover_nonconstant_array_refs (void)
     for (gsi = gsi_start_bb (bb); !gsi_end_p (gsi); gsi_next (&gsi))
       {
        gimple stmt = gsi_stmt (gsi);
-       walk_gimple_op (stmt, discover_nonconstant_array_refs_r, NULL);
+       if (!is_gimple_debug (stmt))
+         walk_gimple_op (stmt, discover_nonconstant_array_refs_r, NULL);
       }
 }
 
@@ -3451,7 +3656,7 @@ expand_stack_alignment (void)
 
   if (! SUPPORTS_STACK_ALIGNMENT)
     return;
-  
+
   if (cfun->calls_alloca
       || cfun->has_nonlocal_label
       || crtl->has_nonlocal_goto)
@@ -3496,7 +3701,7 @@ expand_stack_alignment (void)
   /* Target has to redefine TARGET_GET_DRAP_RTX to support stack
      alignment.  */
   gcc_assert (targetm.calls.get_drap_rtx != NULL);
-  drap_rtx = targetm.calls.get_drap_rtx (); 
+  drap_rtx = targetm.calls.get_drap_rtx ();
 
   /* stack_realign_drap and drap_rtx must match.  */
   gcc_assert ((stack_realign_drap != 0) == (drap_rtx != NULL));
@@ -3575,11 +3780,13 @@ gimple_expand_cfg (void)
   if (warn_stack_protect)
     {
       if (cfun->calls_alloca)
-       warning (OPT_Wstack_protector, 
-                "not protecting local variables: variable length buffer");
+       warning (OPT_Wstack_protector,
+                "stack protector not protecting local variables: "
+                 "variable length buffer");
       if (has_short_buffer && !crtl->stack_protect_guard)
-       warning (OPT_Wstack_protector, 
-                "not protecting function: no buffer at least %d bytes long",
+       warning (OPT_Wstack_protector,
+                "stack protector not protecting function: "
+                 "all local arrays are less than %d bytes long",
                 (int) PARAM_VALUE (PARAM_SSP_BUFFER_SIZE));
     }
 
@@ -3649,6 +3856,9 @@ gimple_expand_cfg (void)
   execute_free_datastructures ();
   finish_out_of_ssa (&SA);
 
+  /* We are no longer in SSA form.  */
+  cfun->gimple_df->in_ssa_p = false;
+
   /* Expansion is used by optimization passes too, set maybe_hot_insn_p
      conservatively to true until they are all profile aware.  */
   pointer_map_destroy (lab_rtx_for_bb);
@@ -3769,7 +3979,8 @@ struct rtl_opt_pass pass_expand =
   NULL,                                 /* next */
   0,                                    /* static_pass_number */
   TV_EXPAND,                           /* tv_id */
-  PROP_ssa | PROP_gimple_leh | PROP_cfg,/* properties_required */
+  PROP_ssa | PROP_gimple_leh | PROP_cfg
+    | PROP_gimple_lcx,                 /* properties_required */
   PROP_rtl,                             /* properties_provided */
   PROP_ssa | PROP_trees,               /* properties_destroyed */
   TODO_verify_ssa | TODO_verify_flow