]> gcc.gnu.org Git - gcc.git/blobdiff - gcc/function.c
re PR sanitizer/77823 (ICE: in ubsan_encode_value, at ubsan.c:137 with -fsanitize...
[gcc.git] / gcc / function.c
index cffe32322d2f00e46576b6ae076f925bfd85d219..0b1d16805ac4d2ae93f90ab79f0c4b21b975b8e6 100644 (file)
@@ -1,5 +1,5 @@
 /* Expands front end tree to back end RTL for GCC.
-   Copyright (C) 1987-2015 Free Software Foundation, Inc.
+   Copyright (C) 1987-2016 Free Software Foundation, Inc.
 
 This file is part of GCC.
 
@@ -34,57 +34,49 @@ along with GCC; see the file COPYING3.  If not see
 #include "config.h"
 #include "system.h"
 #include "coretypes.h"
-#include "tm.h"
+#include "backend.h"
+#include "target.h"
+#include "rtl.h"
+#include "tree.h"
+#include "gimple-expr.h"
+#include "cfghooks.h"
+#include "df.h"
+#include "memmodel.h"
+#include "tm_p.h"
+#include "stringpool.h"
+#include "expmed.h"
+#include "optabs.h"
+#include "regs.h"
+#include "emit-rtl.h"
+#include "recog.h"
 #include "rtl-error.h"
 #include "alias.h"
-#include "symtab.h"
-#include "tree.h"
 #include "fold-const.h"
 #include "stor-layout.h"
 #include "varasm.h"
-#include "stringpool.h"
-#include "flags.h"
 #include "except.h"
-#include "hard-reg-set.h"
-#include "function.h"
-#include "rtl.h"
-#include "insn-config.h"
-#include "expmed.h"
 #include "dojump.h"
 #include "explow.h"
 #include "calls.h"
-#include "emit-rtl.h"
-#include "stmt.h"
 #include "expr.h"
-#include "insn-codes.h"
-#include "optabs.h"
-#include "libfuncs.h"
-#include "regs.h"
-#include "recog.h"
+#include "optabs-tree.h"
 #include "output.h"
-#include "tm_p.h"
 #include "langhooks.h"
-#include "target.h"
 #include "common/common-target.h"
-#include "gimple-expr.h"
 #include "gimplify.h"
 #include "tree-pass.h"
-#include "predict.h"
-#include "dominance.h"
-#include "cfg.h"
 #include "cfgrtl.h"
 #include "cfganal.h"
 #include "cfgbuild.h"
 #include "cfgcleanup.h"
-#include "basic-block.h"
-#include "df.h"
-#include "params.h"
-#include "bb-reorder.h"
+#include "cfgexpand.h"
 #include "shrink-wrap.h"
 #include "toplev.h"
 #include "rtl-iter.h"
 #include "tree-chkp.h"
 #include "rtl-chkp.h"
+#include "tree-dfa.h"
+#include "tree-ssa.h"
 
 /* So we can assign to cfun in this file.  */
 #undef cfun
@@ -154,13 +146,12 @@ static bool contains (const_rtx, hash_table<insn_cache_hasher> *);
 static void prepare_function_start (void);
 static void do_clobber_return_reg (rtx, void *);
 static void do_use_return_reg (rtx, void *);
+
 \f
 /* Stack of nested functions.  */
 /* Keep track of the cfun stack.  */
 
-typedef struct function *function_p;
-
-static vec<function_p> function_context_stack;
+static vec<function *> function_context_stack;
 
 /* Save the current context for compilation of a nested function.
    This is called from language-specific code.  */
@@ -216,6 +207,7 @@ free_after_compilation (struct function *f)
   f->eh = NULL;
   f->machine = NULL;
   f->cfg = NULL;
+  f->curr_properties &= ~PROP_cfg;
 
   regno_reg_rtx = NULL;
 }
@@ -242,7 +234,7 @@ frame_offset_overflow (HOST_WIDE_INT offset, tree func)
 {
   unsigned HOST_WIDE_INT size = FRAME_GROWS_DOWNWARD ? -offset : offset;
 
-  if (size > ((unsigned HOST_WIDE_INT) 1 << (GET_MODE_BITSIZE (Pmode) - 1))
+  if (size > (HOST_WIDE_INT_1U << (GET_MODE_BITSIZE (Pmode) - 1))
               /* Leave room for the fixed part of the frame.  */
               - 64 * UNITS_PER_WORD)
     {
@@ -508,8 +500,7 @@ assign_stack_local_1 (machine_mode mode, HOST_WIDE_INT size,
   set_mem_align (x, alignment_in_bits);
   MEM_NOTRAP_P (x) = 1;
 
-  stack_slot_list
-    = gen_rtx_EXPR_LIST (VOIDmode, x, stack_slot_list);
+  vec_safe_push (stack_slot_list, x);
 
   if (frame_offset_overflow (frame_offset, current_function_decl))
     frame_offset = 0;
@@ -838,8 +829,7 @@ assign_stack_temp_for_type (machine_mode mode, HOST_WIDE_INT size,
              p->type = best_p->type;
              insert_slot_to_list (p, &avail_temp_slots);
 
-             stack_slot_list = gen_rtx_EXPR_LIST (VOIDmode, p->slot,
-                                                  stack_slot_list);
+             vec_safe_push (stack_slot_list, p->slot);
 
              best_p->size = rounded_size;
              best_p->full_size = rounded_size;
@@ -911,7 +901,7 @@ assign_stack_temp_for_type (machine_mode mode, HOST_WIDE_INT size,
 
   /* Create a new MEM rtx to avoid clobbering MEM flags of old slots.  */
   slot = gen_rtx_MEM (mode, XEXP (p->slot, 0));
-  stack_slot_list = gen_rtx_EXPR_LIST (VOIDmode, slot, stack_slot_list);
+  vec_safe_push (stack_slot_list, slot);
 
   /* If we know the alias set for the memory that will be used, use
      it.  If there's no TYPE, then we don't know anything about the
@@ -965,6 +955,10 @@ assign_temp (tree type_or_decl, int memory_required,
   unsignedp = TYPE_UNSIGNED (type);
 #endif
 
+  /* Allocating temporaries of TREE_ADDRESSABLE type must be done in the front
+     end.  See also create_tmp_var for the gimplification-time check.  */
+  gcc_assert (!TREE_ADDRESSABLE (type) && COMPLETE_TYPE_P (type));
+
   if (mode == BLKmode || memory_required)
     {
       HOST_WIDE_INT size = int_size_in_bytes (type);
@@ -1229,18 +1223,18 @@ init_temp_slots (void)
 
 /* Private type used by get_hard_reg_initial_reg, get_hard_reg_initial_val,
    and has_hard_reg_initial_val..  */
-typedef struct GTY(()) initial_value_pair {
+struct GTY(()) initial_value_pair {
   rtx hard_reg;
   rtx pseudo;
-} initial_value_pair;
+};
 /* ???  This could be a VEC but there is currently no way to define an
    opaque VEC type.  This could be worked around by defining struct
    initial_value_pair in function.h.  */
-typedef struct GTY(()) initial_value_struct {
+struct GTY(()) initial_value_struct {
   int num_entries;
   int max_entries;
   initial_value_pair * GTY ((length ("%h.num_entries"))) entries;
-} initial_value_struct;
+};
 
 /* If a pseudo represents an initial hard reg (or expression), return
    it, else return NULL_RTX.  */
@@ -1833,8 +1827,7 @@ instantiate_expr (tree *tp, int *walk_subtrees, void *data ATTRIBUTE_UNUSED)
          if (TREE_CODE (t) == PARM_DECL && DECL_NAMELESS (t)
              && DECL_INCOMING_RTL (t))
            instantiate_decl_rtl (DECL_INCOMING_RTL (t));
-         if ((TREE_CODE (t) == VAR_DECL
-              || TREE_CODE (t) == RESULT_DECL)
+         if ((VAR_P (t) || TREE_CODE (t) == RESULT_DECL)
              && DECL_HAS_VALUE_EXPR_P (t))
            {
              tree v = DECL_VALUE_EXPR (t);
@@ -1857,7 +1850,7 @@ instantiate_decls_1 (tree let)
     {
       if (DECL_RTL_SET_P (t))
        instantiate_decl_rtl (DECL_RTL (t));
-      if (TREE_CODE (t) == VAR_DECL && DECL_HAS_VALUE_EXPR_P (t))
+      if (VAR_P (t) && DECL_HAS_VALUE_EXPR_P (t))
        {
          tree v = DECL_VALUE_EXPR (t);
          walk_tree (&v, instantiate_expr, NULL, NULL);
@@ -2110,8 +2103,29 @@ aggregate_value_p (const_tree exp, const_tree fntype)
 bool
 use_register_for_decl (const_tree decl)
 {
-  if (!targetm.calls.allocate_stack_slots_for_args ())
-    return true;
+  if (TREE_CODE (decl) == SSA_NAME)
+    {
+      /* We often try to use the SSA_NAME, instead of its underlying
+        decl, to get type information and guide decisions, to avoid
+        differences of behavior between anonymous and named
+        variables, but in this one case we have to go for the actual
+        variable if there is one.  The main reason is that, at least
+        at -O0, we want to place user variables on the stack, but we
+        don't mind using pseudos for anonymous or ignored temps.
+        Should we take the SSA_NAME, we'd conclude all SSA_NAMEs
+        should go in pseudos, whereas their corresponding variables
+        might have to go on the stack.  So, disregarding the decl
+        here would negatively impact debug info at -O0, enable
+        coalescing between SSA_NAMEs that ought to get different
+        stack/pseudo assignments, and get the incoming argument
+        processing thoroughly confused by PARM_DECLs expected to live
+        in stack slots but assigned to pseudos.  */
+      if (!SSA_NAME_VAR (decl))
+       return TYPE_MODE (TREE_TYPE (decl)) != BLKmode
+         && !(flag_float_store && FLOAT_TYPE_P (TREE_TYPE (decl)));
+
+      decl = SSA_NAME_VAR (decl);
+    }
 
   /* Honor volatile.  */
   if (TREE_SIDE_EFFECTS (decl))
@@ -2121,6 +2135,47 @@ use_register_for_decl (const_tree decl)
   if (TREE_ADDRESSABLE (decl))
     return false;
 
+  /* RESULT_DECLs are a bit special in that they're assigned without
+     regard to use_register_for_decl, but we generally only store in
+     them.  If we coalesce their SSA NAMEs, we'd better return a
+     result that matches the assignment in expand_function_start.  */
+  if (TREE_CODE (decl) == RESULT_DECL)
+    {
+      /* If it's not an aggregate, we're going to use a REG or a
+        PARALLEL containing a REG.  */
+      if (!aggregate_value_p (decl, current_function_decl))
+       return true;
+
+      /* If expand_function_start determines the return value, we'll
+        use MEM if it's not by reference.  */
+      if (cfun->returns_pcc_struct
+         || (targetm.calls.struct_value_rtx
+             (TREE_TYPE (current_function_decl), 1)))
+       return DECL_BY_REFERENCE (decl);
+
+      /* Otherwise, we're taking an extra all.function_result_decl
+        argument.  It's set up in assign_parms_augmented_arg_list,
+        under the (negated) conditions above, and then it's used to
+        set up the RESULT_DECL rtl in assign_params, after looping
+        over all parameters.  Now, if the RESULT_DECL is not by
+        reference, we'll use a MEM either way.  */
+      if (!DECL_BY_REFERENCE (decl))
+       return false;
+
+      /* Otherwise, if RESULT_DECL is DECL_BY_REFERENCE, it will take
+        the function_result_decl's assignment.  Since it's a pointer,
+        we can short-circuit a number of the tests below, and we must
+        duplicat e them because we don't have the
+        function_result_decl to test.  */
+      if (!targetm.calls.allocate_stack_slots_for_args ())
+       return true;
+      /* We don't set DECL_IGNORED_P for the function_result_decl.  */
+      if (optimize)
+       return true;
+      /* We don't set DECL_REGISTER for the function_result_decl.  */
+      return false;
+    }
+
   /* Decl is implicitly addressible by bound stores and loads
      if it is an aggregate holding bounds.  */
   if (chkp_function_instrumented_p (current_function_decl)
@@ -2140,6 +2195,9 @@ use_register_for_decl (const_tree decl)
   if (flag_float_store && FLOAT_TYPE_P (TREE_TYPE (decl)))
     return false;
 
+  if (!targetm.calls.allocate_stack_slots_for_args ())
+    return true;
+
   /* If we're not interested in tracking debugging information for
      this decl, then we can certainly put it in a register.  */
   if (DECL_IGNORED_P (decl))
@@ -2320,6 +2378,9 @@ assign_parms_augmented_arg_list (struct assign_parm_data_all *all)
       DECL_ARTIFICIAL (decl) = 1;
       DECL_NAMELESS (decl) = 1;
       TREE_CONSTANT (decl) = 1;
+      /* We don't set DECL_IGNORED_P or DECL_REGISTER here.  If this
+        changes, the end of the RESULT_DECL handling block in
+        use_register_for_decl must be adjusted to match.  */
 
       DECL_CHAIN (decl) = all->orig_fnargs;
       all->orig_fnargs = decl;
@@ -2655,7 +2716,7 @@ assign_parm_find_stack_rtl (tree parm, struct assign_parm_data_one *data)
   else if (CONST_INT_P (offset_rtx))
     {
       align = INTVAL (offset_rtx) * BITS_PER_UNIT | boundary;
-      align = align & -align;
+      align = least_bit_hwi (align);
     }
   set_mem_align (stack_parm, align);
 
@@ -2820,17 +2881,49 @@ assign_parm_setup_block (struct assign_parm_data_all *all,
 {
   rtx entry_parm = data->entry_parm;
   rtx stack_parm = data->stack_parm;
+  rtx target_reg = NULL_RTX;
+  bool in_conversion_seq = false;
   HOST_WIDE_INT size;
   HOST_WIDE_INT size_stored;
 
   if (GET_CODE (entry_parm) == PARALLEL)
     entry_parm = emit_group_move_into_temps (entry_parm);
 
+  /* If we want the parameter in a pseudo, don't use a stack slot.  */
+  if (is_gimple_reg (parm) && use_register_for_decl (parm))
+    {
+      tree def = ssa_default_def (cfun, parm);
+      gcc_assert (def);
+      machine_mode mode = promote_ssa_mode (def, NULL);
+      rtx reg = gen_reg_rtx (mode);
+      if (GET_CODE (reg) != CONCAT)
+       stack_parm = reg;
+      else
+       {
+         target_reg = reg;
+         /* Avoid allocating a stack slot, if there isn't one
+            preallocated by the ABI.  It might seem like we should
+            always prefer a pseudo, but converting between
+            floating-point and integer modes goes through the stack
+            on various machines, so it's better to use the reserved
+            stack slot than to risk wasting it and allocating more
+            for the conversion.  */
+         if (stack_parm == NULL_RTX)
+           {
+             int save = generating_concat_p;
+             generating_concat_p = 0;
+             stack_parm = gen_reg_rtx (mode);
+             generating_concat_p = save;
+           }
+       }
+      data->stack_parm = NULL;
+    }
+
   size = int_size_in_bytes (data->passed_type);
   size_stored = CEIL_ROUND (size, UNITS_PER_WORD);
   if (stack_parm == 0)
     {
-      DECL_ALIGN (parm) = MAX (DECL_ALIGN (parm), BITS_PER_WORD);
+      SET_DECL_ALIGN (parm, MAX (DECL_ALIGN (parm), BITS_PER_WORD));
       stack_parm = assign_stack_local (BLKmode, size_stored,
                                       DECL_ALIGN (parm));
       if (GET_MODE_SIZE (GET_MODE (entry_parm)) == size)
@@ -2863,7 +2956,9 @@ assign_parm_setup_block (struct assign_parm_data_all *all,
       mem = validize_mem (copy_rtx (stack_parm));
 
       /* Handle values in multiple non-contiguous locations.  */
-      if (GET_CODE (entry_parm) == PARALLEL)
+      if (GET_CODE (entry_parm) == PARALLEL && !MEM_P (mem))
+       emit_group_store (mem, entry_parm, data->passed_type, size);
+      else if (GET_CODE (entry_parm) == PARALLEL)
        {
          push_to_sequence2 (all->first_conversion_insn,
                             all->last_conversion_insn);
@@ -2871,6 +2966,7 @@ assign_parm_setup_block (struct assign_parm_data_all *all,
          all->first_conversion_insn = get_insns ();
          all->last_conversion_insn = get_last_insn ();
          end_sequence ();
+         in_conversion_seq = true;
        }
 
       else if (size == 0)
@@ -2909,6 +3005,38 @@ assign_parm_setup_block (struct assign_parm_data_all *all,
              emit_move_insn (change_address (mem, mode, 0), reg);
            }
 
+#ifdef BLOCK_REG_PADDING
+         /* Storing the register in memory as a full word, as
+            move_block_from_reg below would do, and then using the
+            MEM in a smaller mode, has the effect of shifting right
+            if BYTES_BIG_ENDIAN.  If we're bypassing memory, the
+            shifting must be explicit.  */
+         else if (!MEM_P (mem))
+           {
+             rtx x;
+
+             /* If the assert below fails, we should have taken the
+                mode != BLKmode path above, unless we have downward
+                padding of smaller-than-word arguments on a machine
+                with little-endian bytes, which would likely require
+                additional changes to work correctly.  */
+             gcc_checking_assert (BYTES_BIG_ENDIAN
+                                  && (BLOCK_REG_PADDING (mode,
+                                                         data->passed_type, 1)
+                                      == upward));
+
+             int by = (UNITS_PER_WORD - size) * BITS_PER_UNIT;
+
+             x = gen_rtx_REG (word_mode, REGNO (entry_parm));
+             x = expand_shift (RSHIFT_EXPR, word_mode, x, by,
+                               NULL_RTX, 1);
+             x = force_reg (word_mode, x);
+             x = gen_lowpart_SUBREG (GET_MODE (mem), x);
+
+             emit_move_insn (mem, x);
+           }
+#endif
+
          /* Blocks smaller than a word on a BYTES_BIG_ENDIAN
             machine must be aligned to the left before storing
             to memory.  Note that the previous test doesn't
@@ -2934,6 +3062,16 @@ assign_parm_setup_block (struct assign_parm_data_all *all,
            move_block_from_reg (REGNO (entry_parm), mem,
                                 size_stored / UNITS_PER_WORD);
        }
+      else if (!MEM_P (mem))
+       {
+         gcc_checking_assert (size > UNITS_PER_WORD);
+#ifdef BLOCK_REG_PADDING
+         gcc_checking_assert (BLOCK_REG_PADDING (GET_MODE (mem),
+                                                 data->passed_type, 0)
+                              == upward);
+#endif
+         emit_move_insn (mem, entry_parm);
+       }
       else
        move_block_from_reg (REGNO (entry_parm), mem,
                             size_stored / UNITS_PER_WORD);
@@ -2946,10 +3084,27 @@ assign_parm_setup_block (struct assign_parm_data_all *all,
       all->first_conversion_insn = get_insns ();
       all->last_conversion_insn = get_last_insn ();
       end_sequence ();
+      in_conversion_seq = true;
+    }
+
+  if (target_reg)
+    {
+      if (!in_conversion_seq)
+       emit_move_insn (target_reg, stack_parm);
+      else
+       {
+         push_to_sequence2 (all->first_conversion_insn,
+                            all->last_conversion_insn);
+         emit_move_insn (target_reg, stack_parm);
+         all->first_conversion_insn = get_insns ();
+         all->last_conversion_insn = get_last_insn ();
+         end_sequence ();
+       }
+      stack_parm = target_reg;
     }
 
   data->stack_parm = stack_parm;
-  SET_DECL_RTL (parm, stack_parm);
+  set_parm_rtl (parm, stack_parm);
 }
 
 /* A subroutine of assign_parms.  Allocate a pseudo to hold the current
@@ -2965,6 +3120,7 @@ assign_parm_setup_reg (struct assign_parm_data_all *all, tree parm,
   int unsignedp = TYPE_UNSIGNED (TREE_TYPE (parm));
   bool did_conversion = false;
   bool need_conversion, moved;
+  rtx rtl;
 
   /* Store the parm in a pseudoregister during the function, but we may
      need to do it in a wider mode.  Using 2 here makes the result
@@ -2974,20 +3130,18 @@ assign_parm_setup_reg (struct assign_parm_data_all *all, tree parm,
                             TREE_TYPE (current_function_decl), 2);
 
   parmreg = gen_reg_rtx (promoted_nominal_mode);
-
   if (!DECL_ARTIFICIAL (parm))
     mark_user_reg (parmreg);
 
   /* If this was an item that we received a pointer to,
-     set DECL_RTL appropriately.  */
+     set rtl appropriately.  */
   if (data->passed_pointer)
     {
-      rtx x = gen_rtx_MEM (TYPE_MODE (TREE_TYPE (data->passed_type)), parmreg);
-      set_mem_attributes (x, parm, 1);
-      SET_DECL_RTL (parm, x);
+      rtl = gen_rtx_MEM (TYPE_MODE (TREE_TYPE (data->passed_type)), parmreg);
+      set_mem_attributes (rtl, parm, 1);
     }
   else
-    SET_DECL_RTL (parm, parmreg);
+    rtl = parmreg;
 
   assign_parm_remove_parallels (data);
 
@@ -3122,7 +3276,9 @@ assign_parm_setup_reg (struct assign_parm_data_all *all, tree parm,
 
       /* TREE_USED gets set erroneously during expand_assignment.  */
       save_tree_used = TREE_USED (parm);
+      SET_DECL_RTL (parm, rtl);
       expand_assignment (parm, make_tree (data->nominal_type, tempreg), false);
+      SET_DECL_RTL (parm, NULL_RTX);
       TREE_USED (parm) = save_tree_used;
       all->first_conversion_insn = get_insns ();
       all->last_conversion_insn = get_last_insn ();
@@ -3156,16 +3312,19 @@ assign_parm_setup_reg (struct assign_parm_data_all *all, tree parm,
          set_mem_attributes (parmreg, parm, 1);
        }
 
-      if (GET_MODE (parmreg) != GET_MODE (DECL_RTL (parm)))
+      /* We need to preserve an address based on VIRTUAL_STACK_VARS_REGNUM for
+        the debug info in case it is not legitimate.  */
+      if (GET_MODE (parmreg) != GET_MODE (rtl))
        {
-         rtx tempreg = gen_reg_rtx (GET_MODE (DECL_RTL (parm)));
+         rtx tempreg = gen_reg_rtx (GET_MODE (rtl));
          int unsigned_p = TYPE_UNSIGNED (TREE_TYPE (parm));
 
          push_to_sequence2 (all->first_conversion_insn,
                             all->last_conversion_insn);
-         emit_move_insn (tempreg, DECL_RTL (parm));
+         emit_move_insn (tempreg, rtl);
          tempreg = convert_to_mode (GET_MODE (parmreg), tempreg, unsigned_p);
-         emit_move_insn (parmreg, tempreg);
+         emit_move_insn (MEM_P (parmreg) ? copy_rtx (parmreg) : parmreg,
+                         tempreg);
          all->first_conversion_insn = get_insns ();
          all->last_conversion_insn = get_last_insn ();
          end_sequence ();
@@ -3173,15 +3332,17 @@ assign_parm_setup_reg (struct assign_parm_data_all *all, tree parm,
          did_conversion = true;
        }
       else
-       emit_move_insn (parmreg, DECL_RTL (parm));
+       emit_move_insn (MEM_P (parmreg) ? copy_rtx (parmreg) : parmreg, rtl);
 
-      SET_DECL_RTL (parm, parmreg);
+      rtl = parmreg;
 
       /* STACK_PARM is the pointer, not the parm, and PARMREG is
         now the parm.  */
       data->stack_parm = NULL;
     }
 
+  set_parm_rtl (parm, rtl);
+
   /* Mark the register as eliminable if we did no conversion and it was
      copied from memory at a fixed offset, and the arg pointer was not
      copied to a pseudo-reg.  If the arg pointer is a pseudo reg or the
@@ -3225,7 +3386,7 @@ assign_parm_setup_reg (struct assign_parm_data_all *all, tree parm,
                set_unique_reg_note (sinsn, REG_EQUIV, stackr);
            }
        }
-      else 
+      else
        set_dst_reg_note (linsn, REG_EQUIV, equiv_stack_parm, parmreg);
     }
 
@@ -3306,7 +3467,11 @@ assign_parm_setup_stack (struct assign_parm_data_all *all, tree parm,
                           BLOCK_OP_NORMAL);
        }
       else
-       emit_move_insn (dest, src);
+       {
+         if (!REG_P (src))
+           src = force_reg (GET_MODE (src), src);
+         emit_move_insn (dest, src);
+       }
     }
 
   if (to_conversion)
@@ -3316,7 +3481,7 @@ assign_parm_setup_stack (struct assign_parm_data_all *all, tree parm,
       end_sequence ();
     }
 
-  SET_DECL_RTL (parm, data->stack_parm);
+  set_parm_rtl (parm, data->stack_parm);
 }
 
 /* A subroutine of assign_parms.  If the ABI splits complex arguments, then
@@ -3370,7 +3535,7 @@ assign_parms_unsplit_complex (struct assign_parm_data_all *all,
            }
          else
            tmp = gen_rtx_CONCAT (DECL_MODE (parm), real, imag);
-         SET_DECL_RTL (parm, tmp);
+         set_parm_rtl (parm, tmp);
 
          real = DECL_INCOMING_RTL (fnargs[i]);
          imag = DECL_INCOMING_RTL (fnargs[i + 1]);
@@ -3585,7 +3750,9 @@ assign_parms (tree fndecl)
       else
        set_decl_incoming_rtl (parm, data.entry_parm, false);
 
-      /* Boudns should be loaded in the particular order to
+      assign_parm_adjust_stack_rtl (&data);
+
+      /* Bounds should be loaded in the particular order to
         have registers allocated correctly.  Collect info about
         input bounds and load them later.  */
       if (POINTER_BOUNDS_TYPE_P (data.passed_type))
@@ -3602,8 +3769,6 @@ assign_parms (tree fndecl)
        }
       else
        {
-         assign_parm_adjust_stack_rtl (&data);
-
          if (assign_parm_setup_block_p (&data))
            assign_parm_setup_block (&all, parm, &data);
          else if (data.passed_pointer || use_register_for_decl (parm))
@@ -3703,7 +3868,7 @@ assign_parms (tree fndecl)
 
       DECL_HAS_VALUE_EXPR_P (result) = 1;
 
-      SET_DECL_RTL (result, x);
+      set_parm_rtl (result, x);
     }
 
   /* We have aligned all the args, so add space for the pretend args.  */
@@ -4025,14 +4190,14 @@ locate_and_pad_parm (machine_mode passed_mode, tree type, int in_regs,
        locate->slot_offset.var = size_binop (MINUS_EXPR, ssize_int (0),
                                              initial_offset_ptr->var);
 
-       {
-         tree s2 = sizetree;
-         if (where_pad != none
-             && (!tree_fits_uhwi_p (sizetree)
-                 || (tree_to_uhwi (sizetree) * BITS_PER_UNIT) % round_boundary))
-           s2 = round_up (s2, round_boundary / BITS_PER_UNIT);
-         SUB_PARM_SIZE (locate->slot_offset, s2);
-       }
+      {
+       tree s2 = sizetree;
+       if (where_pad != none
+           && (!tree_fits_uhwi_p (sizetree)
+               || (tree_to_uhwi (sizetree) * BITS_PER_UNIT) % round_boundary))
+         s2 = round_up (s2, round_boundary / BITS_PER_UNIT);
+       SUB_PARM_SIZE (locate->slot_offset, s2);
+      }
 
       locate->slot_offset.constant += part_size_in_regs;
 
@@ -4209,7 +4374,7 @@ setjmp_vars_warning (bitmap setjmp_crosses, tree block)
 
   for (decl = BLOCK_VARS (block); decl; decl = DECL_CHAIN (decl))
     {
-      if (TREE_CODE (decl) == VAR_DECL
+      if (VAR_P (decl)
          && DECL_RTL_SET_P (decl)
          && REG_P (DECL_RTL (decl))
          && regno_clobbered_at_setjmp (setjmp_crosses, REGNO (DECL_RTL (decl))))
@@ -4554,7 +4719,7 @@ number_blocks (tree fn)
   /* For SDB and XCOFF debugging output, we start numbering the blocks
      from 1 within each function, rather than keeping a running
      count.  */
-#if defined (SDB_DEBUGGING_INFO) || defined (XCOFF_DEBUGGING_INFO)
+#if SDB_DEBUGGING_INFO || defined (XCOFF_DEBUGGING_INFO)
   if (write_symbols == SDB_DEBUG || write_symbols == XCOFF_DEBUG)
     next_block_index = 1;
 #endif
@@ -4643,12 +4808,13 @@ set_cfun (struct function *new_cfun)
     {
       cfun = new_cfun;
       invoke_set_current_function_hook (new_cfun ? new_cfun->decl : NULL_TREE);
+      redirect_edge_var_map_empty ();
     }
 }
 
 /* Initialized with NOGC, making this poisonous to the garbage collector.  */
 
-static vec<function_p> cfun_stack;
+static vec<function *> cfun_stack;
 
 /* Push the current cfun onto the stack, and set cfun to new_cfun.  Also set
    current_function_decl accordingly.  */
@@ -4735,6 +4901,21 @@ allocate_struct_function (tree fndecl, bool abstract_p)
   if (fndecl != NULL_TREE)
     {
       tree result = DECL_RESULT (fndecl);
+
+      if (!abstract_p)
+       {
+         /* Now that we have activated any function-specific attributes
+            that might affect layout, particularly vector modes, relayout
+            each of the parameters and the result.  */
+         relayout_decl (result);
+         for (tree parm = DECL_ARGUMENTS (fndecl); parm;
+              parm = DECL_CHAIN (parm))
+           relayout_decl (parm);
+
+         /* Similarly relayout the function decl.  */
+         targetm.target_option.relayout_function (fndecl);
+       }
+
       if (!abstract_p && aggregate_value_p (result, fndecl))
        {
 #ifdef PCC_STATIC_STRUCT_RETURN
@@ -4854,11 +5035,6 @@ init_dummy_function_start (void)
 void
 init_function_start (tree subr)
 {
-  if (subr && DECL_STRUCT_FUNCTION (subr))
-    set_cfun (DECL_STRUCT_FUNCTION (subr));
-  else
-    allocate_struct_function (subr, false);
-
   /* Initialize backend, if needed.  */
   initialize_rtl ();
 
@@ -4874,47 +5050,36 @@ init_function_start (tree subr)
 /* Expand code to verify the stack_protect_guard.  This is invoked at
    the end of a function to be protected.  */
 
-#ifndef HAVE_stack_protect_test
-# define HAVE_stack_protect_test               0
-# define gen_stack_protect_test(x, y, z)       (gcc_unreachable (), NULL_RTX)
-#endif
-
 void
 stack_protect_epilogue (void)
 {
   tree guard_decl = targetm.stack_protect_guard ();
   rtx_code_label *label = gen_label_rtx ();
-  rtx x, y, tmp;
+  rtx x, y;
+  rtx_insn *seq;
 
   x = expand_normal (crtl->stack_protect_guard);
-  y = expand_normal (guard_decl);
+  if (guard_decl)
+    y = expand_normal (guard_decl);
+  else
+    y = const0_rtx;
 
   /* Allow the target to compare Y with X without leaking either into
      a register.  */
-  switch ((int) (HAVE_stack_protect_test != 0))
-    {
-    case 1:
-      tmp = gen_stack_protect_test (x, y, label);
-      if (tmp)
-       {
-         emit_insn (tmp);
-         break;
-       }
-      /* FALLTHRU */
-
-    default:
-      emit_cmp_and_jump_insns (x, y, EQ, NULL_RTX, ptr_mode, 1, label);
-      break;
-    }
+  if (targetm.have_stack_protect_test ()
+      && ((seq = targetm.gen_stack_protect_test (x, y, label)) != NULL_RTX))
+    emit_insn (seq);
+  else
+    emit_cmp_and_jump_insns (x, y, EQ, NULL_RTX, ptr_mode, 1, label);
 
   /* The noreturn predictor has been moved to the tree level.  The rtl-level
      predictors estimate this branch about 20%, which isn't enough to get
      things moved out of line.  Since this is the only extant case of adding
      a noreturn function at the rtl level, it doesn't seem worth doing ought
      except adding the prediction by hand.  */
-  tmp = get_last_insn ();
+  rtx_insn *tmp = get_last_insn ();
   if (JUMP_P (tmp))
-    predict_insn_def (as_a <rtx_insn *> (tmp), PRED_NORETURN, TAKEN);
+    predict_insn_def (tmp, PRED_NORETURN, TAKEN);
 
   expand_call (targetm.stack_protect_fail (), NULL_RTX, /*ignore=*/true);
   free_temp_slots ();
@@ -4951,7 +5116,8 @@ expand_function_start (tree subr)
      before any library calls that assign parms might generate.  */
 
   /* Decide whether to return the value in memory or in a register.  */
-  if (aggregate_value_p (DECL_RESULT (subr), subr))
+  tree res = DECL_RESULT (subr);
+  if (aggregate_value_p (res, subr))
     {
       /* Returning something that won't go in a register.  */
       rtx value_address = 0;
@@ -4959,7 +5125,7 @@ expand_function_start (tree subr)
 #ifdef PCC_STATIC_STRUCT_RETURN
       if (cfun->returns_pcc_struct)
        {
-         int size = int_size_in_bytes (TREE_TYPE (DECL_RESULT (subr)));
+         int size = int_size_in_bytes (TREE_TYPE (res));
          value_address = assemble_static_space (size);
        }
       else
@@ -4978,29 +5144,38 @@ expand_function_start (tree subr)
       if (value_address)
        {
          rtx x = value_address;
-         if (!DECL_BY_REFERENCE (DECL_RESULT (subr)))
+         if (!DECL_BY_REFERENCE (res))
            {
-             x = gen_rtx_MEM (DECL_MODE (DECL_RESULT (subr)), x);
-             set_mem_attributes (x, DECL_RESULT (subr), 1);
+             x = gen_rtx_MEM (DECL_MODE (res), x);
+             set_mem_attributes (x, res, 1);
            }
-         SET_DECL_RTL (DECL_RESULT (subr), x);
+         set_parm_rtl (res, x);
        }
     }
-  else if (DECL_MODE (DECL_RESULT (subr)) == VOIDmode)
+  else if (DECL_MODE (res) == VOIDmode)
     /* If return mode is void, this decl rtl should not be used.  */
-    SET_DECL_RTL (DECL_RESULT (subr), NULL_RTX);
-  else
+    set_parm_rtl (res, NULL_RTX);
+  else 
     {
       /* Compute the return values into a pseudo reg, which we will copy
         into the true return register after the cleanups are done.  */
-      tree return_type = TREE_TYPE (DECL_RESULT (subr));
-      if (TYPE_MODE (return_type) != BLKmode
-         && targetm.calls.return_in_msb (return_type))
+      tree return_type = TREE_TYPE (res);
+
+      /* If we may coalesce this result, make sure it has the expected mode
+        in case it was promoted.  But we need not bother about BLKmode.  */
+      machine_mode promoted_mode
+       = flag_tree_coalesce_vars && is_gimple_reg (res)
+         ? promote_ssa_mode (ssa_default_def (cfun, res), NULL)
+         : BLKmode;
+
+      if (promoted_mode != BLKmode)
+       set_parm_rtl (res, gen_reg_rtx (promoted_mode));
+      else if (TYPE_MODE (return_type) != BLKmode
+              && targetm.calls.return_in_msb (return_type))
        /* expand_function_end will insert the appropriate padding in
           this case.  Use the return value's natural (unpadded) mode
           within the function proper.  */
-       SET_DECL_RTL (DECL_RESULT (subr),
-                     gen_reg_rtx (TYPE_MODE (return_type)));
+       set_parm_rtl (res, gen_reg_rtx (TYPE_MODE (return_type)));
       else
        {
          /* In order to figure out what mode to use for the pseudo, we
@@ -5011,25 +5186,24 @@ expand_function_start (tree subr)
          /* Structures that are returned in registers are not
             aggregate_value_p, so we may see a PARALLEL or a REG.  */
          if (REG_P (hard_reg))
-           SET_DECL_RTL (DECL_RESULT (subr),
-                         gen_reg_rtx (GET_MODE (hard_reg)));
+           set_parm_rtl (res, gen_reg_rtx (GET_MODE (hard_reg)));
          else
            {
              gcc_assert (GET_CODE (hard_reg) == PARALLEL);
-             SET_DECL_RTL (DECL_RESULT (subr), gen_group_rtx (hard_reg));
+             set_parm_rtl (res, gen_group_rtx (hard_reg));
            }
        }
 
       /* Set DECL_REGISTER flag so that expand_function_end will copy the
         result to the real return register(s).  */
-      DECL_REGISTER (DECL_RESULT (subr)) = 1;
+      DECL_REGISTER (res) = 1;
 
       if (chkp_function_instrumented_p (current_function_decl))
        {
-         tree return_type = TREE_TYPE (DECL_RESULT (subr));
+         tree return_type = TREE_TYPE (res);
          rtx bounds = targetm.calls.chkp_function_value_bounds (return_type,
                                                                 subr, 1);
-         SET_DECL_BOUNDS_RTL (DECL_RESULT (subr), bounds);
+         SET_DECL_BOUNDS_RTL (res, bounds);
        }
     }
 
@@ -5042,16 +5216,23 @@ expand_function_start (tree subr)
     {
       tree parm = cfun->static_chain_decl;
       rtx local, chain;
-     rtx_insn *insn;
+      rtx_insn *insn;
+      int unsignedp;
 
-      local = gen_reg_rtx (Pmode);
+      local = gen_reg_rtx (promote_decl_mode (parm, &unsignedp));
       chain = targetm.calls.static_chain (current_function_decl, true);
 
       set_decl_incoming_rtl (parm, chain, false);
-      SET_DECL_RTL (parm, local);
+      set_parm_rtl (parm, local);
       mark_reg_pointer (local, TYPE_ALIGN (TREE_TYPE (TREE_TYPE (parm))));
 
-      insn = emit_move_insn (local, chain);
+      if (GET_MODE (local) != GET_MODE (chain))
+       {
+         convert_move (local, chain, unsignedp);
+         insn = get_last_insn ();
+       }
+      else
+       insn = emit_move_insn (local, chain);
 
       /* Mark the register as eliminable, similar to parameters.  */
       if (MEM_P (chain)
@@ -5210,20 +5391,6 @@ use_return_register (void)
   diddle_return_value (do_use_return_reg, NULL);
 }
 
-/* Possibly warn about unused parameters.  */
-void
-do_warn_unused_parameter (tree fn)
-{
-  tree decl;
-
-  for (decl = DECL_ARGUMENTS (fn);
-       decl; decl = DECL_CHAIN (decl))
-    if (!TREE_USED (decl) && TREE_CODE (decl) == PARM_DECL
-       && DECL_NAME (decl) && !DECL_ARTIFICIAL (decl)
-       && !TREE_NO_WARNING (decl))
-      warning (OPT_Wunused_parameter, "unused parameter %q+D", decl);
-}
-
 /* Set the location of the insn chain starting at INSN to LOC.  */
 
 static void
@@ -5352,18 +5519,6 @@ expand_function_end (void)
                              decl_rtl);
              shift_return_value (GET_MODE (decl_rtl), true, real_decl_rtl);
            }
-         /* If a named return value dumped decl_return to memory, then
-            we may need to re-do the PROMOTE_MODE signed/unsigned
-            extension.  */
-         else if (GET_MODE (real_decl_rtl) != GET_MODE (decl_rtl))
-           {
-             int unsignedp = TYPE_UNSIGNED (TREE_TYPE (decl_result));
-             promote_function_mode (TREE_TYPE (decl_result),
-                                    GET_MODE (decl_rtl), &unsignedp,
-                                    TREE_TYPE (current_function_decl), 1);
-
-             convert_move (real_decl_rtl, decl_rtl, unsignedp);
-           }
          else if (GET_CODE (real_decl_rtl) == PARALLEL)
            {
              /* If expand_function_start has created a PARALLEL for decl_rtl,
@@ -5394,6 +5549,18 @@ expand_function_end (void)
              emit_move_insn (tmp, decl_rtl);
              emit_move_insn (real_decl_rtl, tmp);
            }
+         /* If a named return value dumped decl_return to memory, then
+            we may need to re-do the PROMOTE_MODE signed/unsigned
+            extension.  */
+         else if (GET_MODE (real_decl_rtl) != GET_MODE (decl_rtl))
+           {
+             int unsignedp = TYPE_UNSIGNED (TREE_TYPE (decl_result));
+             promote_function_mode (TREE_TYPE (decl_result),
+                                    GET_MODE (decl_rtl), &unsignedp,
+                                    TREE_TYPE (current_function_decl), 1);
+
+             convert_move (real_decl_rtl, decl_rtl, unsignedp);
+           }
          else
            emit_move_insn (real_decl_rtl, decl_rtl);
        }
@@ -5584,6 +5751,18 @@ contains (const_rtx insn, hash_table<insn_cache_hasher> *hash)
   return hash->find (const_cast<rtx> (insn)) != NULL;
 }
 
+int
+prologue_contains (const_rtx insn)
+{
+  return contains (insn, prologue_insn_hash);
+}
+
+int
+epilogue_contains (const_rtx insn)
+{
+  return contains (insn, epilogue_insn_hash);
+}
+
 int
 prologue_epilogue_contains (const_rtx insn)
 {
@@ -5594,48 +5773,16 @@ prologue_epilogue_contains (const_rtx insn)
   return 0;
 }
 
-/* Insert use of return register before the end of BB.  */
-
-static void
-emit_use_return_register_into_block (basic_block bb)
-{
-  start_sequence ();
-  use_return_register ();
-  rtx_insn *seq = get_insns ();
-  end_sequence ();
-  rtx_insn *insn = BB_END (bb);
-  if (HAVE_cc0 && reg_mentioned_p (cc0_rtx, PATTERN (insn)))
-    insn = prev_cc0_setter (insn);
-
-  emit_insn_before (seq, insn);
-}
-
-
-/* Create a return pattern, either simple_return or return, depending on
-   simple_p.  */
-
-static rtx_insn *
-gen_return_pattern (bool simple_p)
+void
+record_prologue_seq (rtx_insn *seq)
 {
-  return (simple_p
-         ? targetm.gen_simple_return ()
-         : targetm.gen_return ());
+  record_insns (seq, NULL, &prologue_insn_hash);
 }
 
-/* Insert an appropriate return pattern at the end of block BB.  This
-   also means updating block_for_insn appropriately.  SIMPLE_P is
-   the same as in gen_return_pattern and passed to it.  */
-
 void
-emit_return_into_block (bool simple_p, basic_block bb)
+record_epilogue_seq (rtx_insn *seq)
 {
-  rtx_jump_insn *jump = emit_jump_insn_after (gen_return_pattern (simple_p),
-                                             BB_END (bb));
-  rtx pat = PATTERN (jump);
-  if (GET_CODE (pat) == PARALLEL)
-    pat = XVECEXP (pat, 0, 0);
-  gcc_assert (ANY_RETURN_P (pat));
-  JUMP_LABEL (jump) = pat;
+  record_insns (seq, NULL, &epilogue_insn_hash);
 }
 
 /* Set JUMP_LABEL for a return insn.  */
@@ -5652,133 +5799,89 @@ set_return_jump_label (rtx_insn *returnjump)
     JUMP_LABEL (returnjump) = ret_rtx;
 }
 
-/* Return true if there are any active insns between HEAD and TAIL.  */
-bool
-active_insn_between (rtx_insn *head, rtx_insn *tail)
-{
-  while (tail)
-    {
-      if (active_insn_p (tail))
-       return true;
-      if (tail == head)
-       return false;
-      tail = PREV_INSN (tail);
-    }
-  return false;
-}
+/* Return a sequence to be used as the split prologue for the current
+   function, or NULL.  */
 
-/* LAST_BB is a block that exits, and empty of active instructions.
-   Examine its predecessors for jumps that can be converted to
-   (conditional) returns.  */
-vec<edge>
-convert_jumps_to_returns (basic_block last_bb, bool simple_p,
-                         vec<edge> unconverted ATTRIBUTE_UNUSED)
+static rtx_insn *
+make_split_prologue_seq (void)
 {
-  int i;
-  basic_block bb;
-  edge_iterator ei;
-  edge e;
-  auto_vec<basic_block> src_bbs (EDGE_COUNT (last_bb->preds));
+  if (!flag_split_stack
+      || lookup_attribute ("no_split_stack", DECL_ATTRIBUTES (cfun->decl)))
+    return NULL;
 
-  FOR_EACH_EDGE (e, ei, last_bb->preds)
-    if (e->src != ENTRY_BLOCK_PTR_FOR_FN (cfun))
-      src_bbs.quick_push (e->src);
+  start_sequence ();
+  emit_insn (targetm.gen_split_stack_prologue ());
+  rtx_insn *seq = get_insns ();
+  end_sequence ();
 
-  rtx_insn *label = BB_HEAD (last_bb);
+  record_insns (seq, NULL, &prologue_insn_hash);
+  set_insn_locations (seq, prologue_location);
 
-  FOR_EACH_VEC_ELT (src_bbs, i, bb)
-    {
-      rtx_insn *jump = BB_END (bb);
+  return seq;
+}
 
-      if (!JUMP_P (jump) || JUMP_LABEL (jump) != label)
-       continue;
+/* Return a sequence to be used as the prologue for the current function,
+   or NULL.  */
 
-      e = find_edge (bb, last_bb);
+static rtx_insn *
+make_prologue_seq (void)
+{
+  if (!targetm.have_prologue ())
+    return NULL;
 
-      /* If we have an unconditional jump, we can replace that
-        with a simple return instruction.  */
-      if (simplejump_p (jump))
-       {
-         /* The use of the return register might be present in the exit
-            fallthru block.  Either:
-            - removing the use is safe, and we should remove the use in
-            the exit fallthru block, or
-            - removing the use is not safe, and we should add it here.
-            For now, we conservatively choose the latter.  Either of the
-            2 helps in crossjumping.  */
-         emit_use_return_register_into_block (bb);
-
-         emit_return_into_block (simple_p, bb);
-         delete_insn (jump);
-       }
+  start_sequence ();
+  rtx_insn *seq = targetm.gen_prologue ();
+  emit_insn (seq);
+
+  /* Insert an explicit USE for the frame pointer
+     if the profiling is on and the frame pointer is required.  */
+  if (crtl->profile && frame_pointer_needed)
+    emit_use (hard_frame_pointer_rtx);
+
+  /* Retain a map of the prologue insns.  */
+  record_insns (seq, NULL, &prologue_insn_hash);
+  emit_note (NOTE_INSN_PROLOGUE_END);
+
+  /* Ensure that instructions are not moved into the prologue when
+     profiling is on.  The call to the profiling routine can be
+     emitted within the live range of a call-clobbered register.  */
+  if (!targetm.profile_before_prologue () && crtl->profile)
+    emit_insn (gen_blockage ());
 
-      /* If we have a conditional jump branching to the last
-        block, we can try to replace that with a conditional
-        return instruction.  */
-      else if (condjump_p (jump))
-       {
-         rtx dest;
+  seq = get_insns ();
+  end_sequence ();
+  set_insn_locations (seq, prologue_location);
 
-         if (simple_p)
-           dest = simple_return_rtx;
-         else
-           dest = ret_rtx;
-         if (!redirect_jump (as_a <rtx_jump_insn *> (jump), dest, 0))
-           {
-             if (targetm.have_simple_return () && simple_p)
-               {
-                 if (dump_file)
-                   fprintf (dump_file,
-                            "Failed to redirect bb %d branch.\n", bb->index);
-                 unconverted.safe_push (e);
-               }
-             continue;
-           }
+  return seq;
+}
 
-         /* See comment in simplejump_p case above.  */
-         emit_use_return_register_into_block (bb);
+/* Return a sequence to be used as the epilogue for the current function,
+   or NULL.  */
 
-         /* If this block has only one successor, it both jumps
-            and falls through to the fallthru block, so we can't
-            delete the edge.  */
-         if (single_succ_p (bb))
-           continue;
-       }
-      else
-       {
-         if (targetm.have_simple_return () && simple_p)
-           {
-             if (dump_file)
-               fprintf (dump_file,
-                        "Failed to redirect bb %d branch.\n", bb->index);
-             unconverted.safe_push (e);
-           }
-         continue;
-       }
+static rtx_insn *
+make_epilogue_seq (void)
+{
+  if (!targetm.have_epilogue ())
+    return NULL;
 
-      /* Fix up the CFG for the successful change we just made.  */
-      redirect_edge_succ (e, EXIT_BLOCK_PTR_FOR_FN (cfun));
-      e->flags &= ~EDGE_CROSSING;
-    }
-  src_bbs.release ();
-  return unconverted;
-}
+  start_sequence ();
+  emit_note (NOTE_INSN_EPILOGUE_BEG);
+  rtx_insn *seq = targetm.gen_epilogue ();
+  if (seq)
+    emit_jump_insn (seq);
 
-/* Emit a return insn for the exit fallthru block.  */
-basic_block
-emit_return_for_exit (edge exit_fallthru_edge, bool simple_p)
-{
-  basic_block last_bb = exit_fallthru_edge->src;
+  /* Retain a map of the epilogue insns.  */
+  record_insns (seq, NULL, &epilogue_insn_hash);
+  set_insn_locations (seq, epilogue_location);
 
-  if (JUMP_P (BB_END (last_bb)))
-    {
-      last_bb = split_edge (exit_fallthru_edge);
-      exit_fallthru_edge = single_succ_edge (last_bb);
-    }
-  emit_barrier_after (BB_END (last_bb));
-  emit_return_into_block (simple_p, last_bb);
-  exit_fallthru_edge->flags &= ~EDGE_FALLTHRU;
-  return last_bb;
+  seq = get_insns ();
+  rtx_insn *returnjump = get_last_insn ();
+  end_sequence ();
+
+  if (JUMP_P (returnjump))
+    set_return_jump_label (returnjump);
+
+  return seq;
 }
 
 
@@ -5833,156 +5936,56 @@ emit_return_for_exit (edge exit_fallthru_edge, bool simple_p)
 void
 thread_prologue_and_epilogue_insns (void)
 {
-  bool inserted;
-  vec<edge> unconverted_simple_returns = vNULL;
-  bitmap_head bb_flags;
-  rtx_insn *returnjump;
-  rtx_insn *epilogue_end ATTRIBUTE_UNUSED;
-  rtx_insn *prologue_seq ATTRIBUTE_UNUSED, *split_prologue_seq ATTRIBUTE_UNUSED;
-  edge e, entry_edge, orig_entry_edge, exit_fallthru_edge;
-  edge_iterator ei;
-
   df_analyze ();
 
-  rtl_profile_for_bb (ENTRY_BLOCK_PTR_FOR_FN (cfun));
-
-  inserted = false;
-  epilogue_end = NULL;
-  returnjump = NULL;
-
   /* Can't deal with multiple successors of the entry block at the
      moment.  Function should always have at least one entry
      point.  */
   gcc_assert (single_succ_p (ENTRY_BLOCK_PTR_FOR_FN (cfun)));
-  entry_edge = single_succ_edge (ENTRY_BLOCK_PTR_FOR_FN (cfun));
-  orig_entry_edge = entry_edge;
-
-  split_prologue_seq = NULL;
-  if (flag_split_stack
-      && (lookup_attribute ("no_split_stack", DECL_ATTRIBUTES (cfun->decl))
-         == NULL))
-    {
-#ifndef HAVE_split_stack_prologue
-      gcc_unreachable ();
-#else
-      gcc_assert (HAVE_split_stack_prologue);
-
-      start_sequence ();
-      emit_insn (gen_split_stack_prologue ());
-      split_prologue_seq = get_insns ();
-      end_sequence ();
-
-      record_insns (split_prologue_seq, NULL, &prologue_insn_hash);
-      set_insn_locations (split_prologue_seq, prologue_location);
-#endif
-    }
-
-  prologue_seq = NULL;
-#ifdef HAVE_prologue
-  if (HAVE_prologue)
-    {
-      start_sequence ();
-      rtx_insn *seq = safe_as_a <rtx_insn *> (gen_prologue ());
-      emit_insn (seq);
-
-      /* Insert an explicit USE for the frame pointer
-         if the profiling is on and the frame pointer is required.  */
-      if (crtl->profile && frame_pointer_needed)
-       emit_use (hard_frame_pointer_rtx);
-
-      /* Retain a map of the prologue insns.  */
-      record_insns (seq, NULL, &prologue_insn_hash);
-      emit_note (NOTE_INSN_PROLOGUE_END);
-
-      /* Ensure that instructions are not moved into the prologue when
-        profiling is on.  The call to the profiling routine can be
-        emitted within the live range of a call-clobbered register.  */
-      if (!targetm.profile_before_prologue () && crtl->profile)
-        emit_insn (gen_blockage ());
 
-      prologue_seq = get_insns ();
-      end_sequence ();
-      set_insn_locations (prologue_seq, prologue_location);
-    }
-#endif
+  edge entry_edge = single_succ_edge (ENTRY_BLOCK_PTR_FOR_FN (cfun));
+  edge orig_entry_edge = entry_edge;
 
-  bitmap_initialize (&bb_flags, &bitmap_default_obstack);
+  rtx_insn *split_prologue_seq = make_split_prologue_seq ();
+  rtx_insn *prologue_seq = make_prologue_seq ();
+  rtx_insn *epilogue_seq = make_epilogue_seq ();
 
   /* Try to perform a kind of shrink-wrapping, making sure the
      prologue/epilogue is emitted only around those parts of the
      function that require it.  */
+  try_shrink_wrapping (&entry_edge, prologue_seq);
 
-  try_shrink_wrapping (&entry_edge, orig_entry_edge, &bb_flags, prologue_seq);
+  /* If the target can handle splitting the prologue/epilogue into separate
+     components, try to shrink-wrap these components separately.  */
+  try_shrink_wrapping_separate (entry_edge->dest);
 
-  if (split_prologue_seq != NULL_RTX)
-    {
-      insert_insn_on_edge (split_prologue_seq, orig_entry_edge);
-      inserted = true;
-    }
-  if (prologue_seq != NULL_RTX)
+  /* If that did anything for any component we now need the generate the
+     "main" prologue again.  Because some targets require some of these
+     to be called in a specific order (i386 requires the split prologue
+     to be first, for example), we create all three sequences again here.
+     If this does not work for some target, that target should not enable
+     separate shrink-wrapping.  */
+  if (crtl->shrink_wrapped_separate)
     {
-      insert_insn_on_edge (prologue_seq, entry_edge);
-      inserted = true;
+      split_prologue_seq = make_split_prologue_seq ();
+      prologue_seq = make_prologue_seq ();
+      epilogue_seq = make_epilogue_seq ();
     }
 
-  /* If the exit block has no non-fake predecessors, we don't need
-     an epilogue.  */
-  FOR_EACH_EDGE (e, ei, EXIT_BLOCK_PTR_FOR_FN (cfun)->preds)
-    if ((e->flags & EDGE_FAKE) == 0)
-      break;
-  if (e == NULL)
-    goto epilogue_done;
-
   rtl_profile_for_bb (EXIT_BLOCK_PTR_FOR_FN (cfun));
 
-  exit_fallthru_edge = find_fallthru_edge (EXIT_BLOCK_PTR_FOR_FN (cfun)->preds);
-
-  if (targetm.have_simple_return () && entry_edge != orig_entry_edge)
-    exit_fallthru_edge
-       = get_unconverted_simple_return (exit_fallthru_edge, bb_flags,
-                                        &unconverted_simple_returns,
-                                        &returnjump);
-  if (targetm.have_return ())
-    {
-      if (exit_fallthru_edge == NULL)
-       goto epilogue_done;
-
-      if (optimize)
-       {
-         basic_block last_bb = exit_fallthru_edge->src;
-
-         if (LABEL_P (BB_HEAD (last_bb))
-             && !active_insn_between (BB_HEAD (last_bb), BB_END (last_bb)))
-           convert_jumps_to_returns (last_bb, false, vNULL);
-
-         if (EDGE_COUNT (last_bb->preds) != 0
-             && single_succ_p (last_bb))
-           {
-             last_bb = emit_return_for_exit (exit_fallthru_edge, false);
-             epilogue_end = returnjump = BB_END (last_bb);
-
-             /* Emitting the return may add a basic block.
-                Fix bb_flags for the added block.  */
-             if (targetm.have_simple_return ()
-                 && last_bb != exit_fallthru_edge->src)
-               bitmap_set_bit (&bb_flags, last_bb->index);
-
-             goto epilogue_done;
-           }
-       }
-    }
-
   /* A small fib -- epilogue is not yet completed, but we wish to re-use
      this marker for the splits of EH_RETURN patterns, and nothing else
      uses the flag in the meantime.  */
   epilogue_completed = 1;
 
-#ifdef HAVE_eh_return
   /* Find non-fallthru edges that end with EH_RETURN instructions.  On
      some targets, these get split to a special version of the epilogue
      code.  In order to be able to properly annotate these with unwind
      info, try to split them now.  If we get a valid split, drop an
      EPILOGUE_BEG note and mark the insns as epilogue insns.  */
+  edge e;
+  edge_iterator ei;
   FOR_EACH_EDGE (e, ei, EXIT_BLOCK_PTR_FOR_FN (cfun)->preds)
     {
       rtx_insn *prev, *last, *trial;
@@ -6001,111 +6004,86 @@ thread_prologue_and_epilogue_insns (void)
       record_insns (NEXT_INSN (prev), NEXT_INSN (trial), &epilogue_insn_hash);
       emit_note_after (NOTE_INSN_EPILOGUE_BEG, prev);
     }
-#endif
-
-  /* If nothing falls through into the exit block, we don't need an
-     epilogue.  */
 
-  if (exit_fallthru_edge == NULL)
-    goto epilogue_done;
+  edge exit_fallthru_edge = find_fallthru_edge (EXIT_BLOCK_PTR_FOR_FN (cfun)->preds);
 
-  if (HAVE_epilogue)
+  if (exit_fallthru_edge)
     {
-      start_sequence ();
-      epilogue_end = emit_note (NOTE_INSN_EPILOGUE_BEG);
-      rtx_insn *seq = as_a <rtx_insn *> (gen_epilogue ());
-      if (seq)
-       emit_jump_insn (seq);
-
-      /* Retain a map of the epilogue insns.  */
-      record_insns (seq, NULL, &epilogue_insn_hash);
-      set_insn_locations (seq, epilogue_location);
-
-      seq = get_insns ();
-      returnjump = get_last_insn ();
-      end_sequence ();
-
-      insert_insn_on_edge (seq, exit_fallthru_edge);
-      inserted = true;
-
-      if (JUMP_P (returnjump))
-       set_return_jump_label (returnjump);
-    }
-  else
-    {
-      basic_block cur_bb;
+      if (epilogue_seq)
+       {
+         insert_insn_on_edge (epilogue_seq, exit_fallthru_edge);
+         commit_edge_insertions ();
 
-      if (! next_active_insn (BB_END (exit_fallthru_edge->src)))
-       goto epilogue_done;
-      /* We have a fall-through edge to the exit block, the source is not
-         at the end of the function, and there will be an assembler epilogue
-         at the end of the function.
-         We can't use force_nonfallthru here, because that would try to
-        use return.  Inserting a jump 'by hand' is extremely messy, so
-        we take advantage of cfg_layout_finalize using
-        fixup_fallthru_exit_predecessor.  */
-      cfg_layout_initialize (0);
-      FOR_EACH_BB_FN (cur_bb, cfun)
-       if (cur_bb->index >= NUM_FIXED_BLOCKS
-           && cur_bb->next_bb->index >= NUM_FIXED_BLOCKS)
-         cur_bb->aux = cur_bb->next_bb;
-      cfg_layout_finalize ();
+         /* The epilogue insns we inserted may cause the exit edge to no longer
+            be fallthru.  */
+         FOR_EACH_EDGE (e, ei, EXIT_BLOCK_PTR_FOR_FN (cfun)->preds)
+           {
+             if (((e->flags & EDGE_FALLTHRU) != 0)
+                 && returnjump_p (BB_END (e->src)))
+               e->flags &= ~EDGE_FALLTHRU;
+           }
+       }
+      else if (next_active_insn (BB_END (exit_fallthru_edge->src)))
+       {
+         /* We have a fall-through edge to the exit block, the source is not
+            at the end of the function, and there will be an assembler epilogue
+            at the end of the function.
+            We can't use force_nonfallthru here, because that would try to
+            use return.  Inserting a jump 'by hand' is extremely messy, so
+            we take advantage of cfg_layout_finalize using
+            fixup_fallthru_exit_predecessor.  */
+         cfg_layout_initialize (0);
+         basic_block cur_bb;
+         FOR_EACH_BB_FN (cur_bb, cfun)
+           if (cur_bb->index >= NUM_FIXED_BLOCKS
+               && cur_bb->next_bb->index >= NUM_FIXED_BLOCKS)
+             cur_bb->aux = cur_bb->next_bb;
+         cfg_layout_finalize ();
+       }
     }
 
-epilogue_done:
+  /* Insert the prologue.  */
 
-  default_rtl_profile ();
+  rtl_profile_for_bb (ENTRY_BLOCK_PTR_FOR_FN (cfun));
 
-  if (inserted)
+  if (split_prologue_seq || prologue_seq)
     {
-      sbitmap blocks;
+      if (split_prologue_seq)
+       insert_insn_on_edge (split_prologue_seq, orig_entry_edge);
+
+      if (prologue_seq)
+       insert_insn_on_edge (prologue_seq, entry_edge);
 
       commit_edge_insertions ();
 
       /* Look for basic blocks within the prologue insns.  */
-      blocks = sbitmap_alloc (last_basic_block_for_fn (cfun));
+      auto_sbitmap blocks (last_basic_block_for_fn (cfun));
       bitmap_clear (blocks);
       bitmap_set_bit (blocks, entry_edge->dest->index);
       bitmap_set_bit (blocks, orig_entry_edge->dest->index);
       find_many_sub_basic_blocks (blocks);
-      sbitmap_free (blocks);
-
-      /* The epilogue insns we inserted may cause the exit edge to no longer
-        be fallthru.  */
-      FOR_EACH_EDGE (e, ei, EXIT_BLOCK_PTR_FOR_FN (cfun)->preds)
-       {
-         if (((e->flags & EDGE_FALLTHRU) != 0)
-             && returnjump_p (BB_END (e->src)))
-           e->flags &= ~EDGE_FALLTHRU;
-       }
     }
 
-  if (targetm.have_simple_return ())
-    convert_to_simple_return (entry_edge, orig_entry_edge, bb_flags,
-                             returnjump, unconverted_simple_returns);
+  default_rtl_profile ();
 
-#ifdef HAVE_sibcall_epilogue
   /* Emit sibling epilogues before any sibling call sites.  */
-  for (ei = ei_start (EXIT_BLOCK_PTR_FOR_FN (cfun)->preds); (e =
-                                                            ei_safe_edge (ei));
-                                                            )
-    {
-      basic_block bb = e->src;
-      rtx_insn *insn = BB_END (bb);
-      rtx ep_seq;
-
-      if (!CALL_P (insn)
-         || ! SIBLING_CALL_P (insn)
-         || (targetm.have_simple_return ()
-             && entry_edge != orig_entry_edge
-             && !bitmap_bit_p (&bb_flags, bb->index)))
+  for (ei = ei_start (EXIT_BLOCK_PTR_FOR_FN (cfun)->preds);
+       (e = ei_safe_edge (ei));
+       ei_next (&ei))
+    {
+      /* Skip those already handled, the ones that run without prologue.  */
+      if (e->flags & EDGE_IGNORE)
        {
-         ei_next (&ei);
+         e->flags &= ~EDGE_IGNORE;
          continue;
        }
 
-      ep_seq = gen_sibcall_epilogue ();
-      if (ep_seq)
+      rtx_insn *insn = BB_END (e->src);
+
+      if (!(CALL_P (insn) && SIBLING_CALL_P (insn)))
+       continue;
+
+      if (rtx_insn *ep_seq = targetm.gen_sibcall_epilogue ())
        {
          start_sequence ();
          emit_note (NOTE_INSN_EPILOGUE_BEG);
@@ -6121,11 +6099,9 @@ epilogue_done:
 
          emit_insn_before (seq, insn);
        }
-      ei_next (&ei);
     }
-#endif
 
-  if (epilogue_end)
+  if (epilogue_seq)
     {
       rtx_insn *insn, *next;
 
@@ -6134,17 +6110,15 @@ epilogue_done:
         of such a note.  Also possibly move
         NOTE_INSN_FUNCTION_BEG notes, as those can be relevant for debug
         info generation.  */
-      for (insn = epilogue_end; insn; insn = next)
+      for (insn = epilogue_seq; insn; insn = next)
        {
          next = NEXT_INSN (insn);
          if (NOTE_P (insn)
              && (NOTE_KIND (insn) == NOTE_INSN_FUNCTION_BEG))
-           reorder_insns (insn, insn, PREV_INSN (epilogue_end));
+           reorder_insns (insn, insn, PREV_INSN (epilogue_seq));
        }
     }
 
-  bitmap_clear (&bb_flags);
-
   /* Threading the prologue and epilogue changes the artificial refs
      in the entry and exit blocks.  */
   epilogue_completed = 1;
@@ -6157,10 +6131,10 @@ epilogue_done:
 void
 reposition_prologue_and_epilogue_notes (void)
 {
-#if ! defined (HAVE_prologue) && ! defined (HAVE_sibcall_epilogue)
-  if (!HAVE_epilogue)
+  if (!targetm.have_prologue ()
+      && !targetm.have_epilogue ()
+      && !targetm.have_sibcall_epilogue ())
     return;
-#endif
 
   /* Since the hash table is created on demand, the fact that it is
      non-null is a signal that it is non-empty.  */
@@ -6433,8 +6407,10 @@ make_pass_leaf_regs (gcc::context *ctxt)
 static unsigned int
 rest_of_handle_thread_prologue_and_epilogue (void)
 {
+  /* prepare_shrink_wrap is sensitive to the block structure of the control
+     flow graph, so clean it up first.  */
   if (optimize)
-    cleanup_cfg (CLEANUP_EXPENSIVE);
+    cleanup_cfg (0);
 
   /* On some machines, the prologue and epilogue code, or parts thereof,
      can be represented as RTL.  Doing so lets us schedule insns between
@@ -6442,9 +6418,13 @@ rest_of_handle_thread_prologue_and_epilogue (void)
      scheduling to operate in the epilogue.  */
   thread_prologue_and_epilogue_insns ();
 
+  /* Some non-cold blocks may now be only reachable from cold blocks.
+     Fix that up.  */
+  fixup_partitions ();
+
   /* Shrink-wrapping can result in unreachable edges in the epilogue,
      see PR57320.  */
-  cleanup_cfg (0);
+  cleanup_cfg (optimize ? CLEANUP_EXPENSIVE : 0);
 
   /* The stack usage info is finalized during prologue expansion.  */
   if (flag_stack_usage_info)
@@ -6642,7 +6622,7 @@ match_asm_constraints_1 (rtx_insn *insn, rtx *p_sets, int noutputs)
 void
 add_local_decl (struct function *fun, tree d)
 {
-  gcc_assert (TREE_CODE (d) == VAR_DECL);
+  gcc_assert (VAR_P (d));
   vec_safe_push (fun->local_decls, d);
 }
 
This page took 0.071204 seconds and 5 git commands to generate.