OSDN Git Service

Upgrade to AutoGen 5 Template
[pf3gnuchains/gcc-fork.git] / gcc / function.c
index 259ccca..3721a60 100644 (file)
@@ -45,9 +45,7 @@ Boston, MA 02111-1307, USA.  */
 #include "flags.h"
 #include "except.h"
 #include "function.h"
-#include "insn-flags.h"
 #include "expr.h"
-#include "insn-codes.h"
 #include "regs.h"
 #include "hard-reg-set.h"
 #include "insn-config.h"
@@ -60,10 +58,6 @@ Boston, MA 02111-1307, USA.  */
 #include "ggc.h"
 #include "tm_p.h"
 
-#ifndef ACCUMULATE_OUTGOING_ARGS
-#define ACCUMULATE_OUTGOING_ARGS 0
-#endif
-
 #ifndef TRAMPOLINE_ALIGNMENT
 #define TRAMPOLINE_ALIGNMENT FUNCTION_BOUNDARY
 #endif
@@ -126,8 +120,10 @@ int current_function_sp_is_unchanging;
 int current_function_uses_only_leaf_regs;
 
 /* Nonzero once virtual register instantiation has been done.
-   assign_stack_local uses frame_pointer_rtx when this is nonzero.  */
-static int virtuals_instantiated;
+   assign_stack_local uses frame_pointer_rtx when this is nonzero.
+   calls.c:emit_library_call_value_1 uses it to set up
+   post-instantiation libcalls.  */
+int virtuals_instantiated;
 
 /* These variables hold pointers to functions to create and destroy
    target specific, per-function data structures.  */
@@ -294,7 +290,7 @@ static int contains         PARAMS ((rtx, varray_type));
 static void emit_return_into_block PARAMS ((basic_block, rtx));
 #endif
 static void put_addressof_into_stack PARAMS ((rtx, struct hash_table *));
-static boolean purge_addressof_1 PARAMS ((rtx *, rtx, int, int,
+static bool purge_addressof_1 PARAMS ((rtx *, rtx, int, int,
                                          struct hash_table *));
 static void purge_single_hard_subreg_set PARAMS ((rtx));
 #ifdef HAVE_epilogue
@@ -305,7 +301,7 @@ static struct hash_entry *insns_for_mem_newfunc PARAMS ((struct hash_entry *,
                                                         struct hash_table *,
                                                         hash_table_key));
 static unsigned long insns_for_mem_hash PARAMS ((hash_table_key));
-static boolean insns_for_mem_comp PARAMS ((hash_table_key, hash_table_key));
+static bool insns_for_mem_comp PARAMS ((hash_table_key, hash_table_key));
 static int insns_for_mem_walk   PARAMS ((rtx *, void *));
 static void compute_insns_for_mem PARAMS ((rtx, rtx, struct hash_table *));
 static void mark_temp_slot PARAMS ((struct temp_slot *));
@@ -1338,7 +1334,9 @@ put_var_into_stack (decl)
   context = decl_function_context (decl);
 
   /* Get the current rtl used for this object and its original mode.  */
-  reg = TREE_CODE (decl) == SAVE_EXPR ? SAVE_EXPR_RTL (decl) : DECL_RTL (decl);
+  reg = (TREE_CODE (decl) == SAVE_EXPR 
+        ? SAVE_EXPR_RTL (decl) 
+        : DECL_RTL_IF_SET (decl));
 
   /* No need to do anything if decl has no rtx yet
      since in that case caller is setting TREE_ADDRESSABLE
@@ -1584,11 +1582,6 @@ fixup_var_refs (var, promoted_mode, unsignedp, ht)
          end_sequence ();
        }
     }
-
-  /* Scan the catch clauses for exception handling too.  */
-  push_to_full_sequence (catch_clauses, catch_clauses_last);
-  fixup_var_refs_insns (catch_clauses, var, promoted_mode, unsignedp, 0);
-  end_full_sequence (&catch_clauses, &catch_clauses_last);
 }
 \f
 /* REPLACEMENTS is a pointer to a list of the struct fixup_replacement and X is
@@ -1689,7 +1682,7 @@ fixup_var_refs_insns_with_hash (ht, var, promoted_mode, unsignedp)
       rtx insn = XEXP (insn_list, 0);
        
       if (INSN_P (insn))
-       fixup_var_refs_insn (insn, var, promoted_mode, unsignedp, 0);
+       fixup_var_refs_insn (insn, var, promoted_mode, unsignedp, 1);
 
       insn_list = XEXP (insn_list, 1);
     }
@@ -2151,7 +2144,7 @@ fixup_var_refs_1 (var, promoted_mode, loc, insn, replacements)
            {
              replacement = find_fixup_replacement (replacements, var);
              if (replacement->new == 0)
-               replacement->new = gen_reg_rtx (GET_MODE (var));
+               replacement->new = gen_reg_rtx (promoted_mode);
              SUBREG_REG (x) = replacement->new;
              return;
            }
@@ -2185,7 +2178,7 @@ fixup_var_refs_1 (var, promoted_mode, loc, insn, replacements)
        optimize_bit_field (x, insn, 0);
       if (GET_CODE (SET_SRC (x)) == SIGN_EXTRACT
          || GET_CODE (SET_SRC (x)) == ZERO_EXTRACT)
-       optimize_bit_field (x, insn, NULL_PTR);
+       optimize_bit_field (x, insn, 0);
 
       /* For a paradoxical SUBREG inside a ZERO_EXTRACT, load the object
         into a register and then store it back out.  */
@@ -2230,7 +2223,7 @@ fixup_var_refs_1 (var, promoted_mode, loc, insn, replacements)
          dest = XEXP (dest, 0);
 
        if (GET_CODE (src) == SUBREG)
-         src = XEXP (src, 0);
+         src = SUBREG_REG (src);
 
        /* If VAR does not appear at the top level of the SET
           just scan the lower levels of the tree.  */
@@ -2514,7 +2507,7 @@ fixup_memory_subreg (x, insn, uncritical)
      rtx insn;
      int uncritical;
 {
-  int offset = SUBREG_WORD (x) * UNITS_PER_WORD;
+  int offset = SUBREG_BYTE (x);
   rtx addr = XEXP (SUBREG_REG (x), 0);
   enum machine_mode mode = GET_MODE (x);
   rtx result;
@@ -2524,9 +2517,6 @@ fixup_memory_subreg (x, insn, uncritical)
       && ! uncritical)
     abort ();
 
-  if (BYTES_BIG_ENDIAN)
-    offset += (MIN (UNITS_PER_WORD, GET_MODE_SIZE (GET_MODE (SUBREG_REG (x))))
-              - MIN (UNITS_PER_WORD, GET_MODE_SIZE (mode)));
   addr = plus_constant (addr, offset);
   if (!flag_force_addr && memory_address_p (mode, addr))
     /* Shortcut if no insns need be emitted.  */
@@ -2720,7 +2710,8 @@ optimize_bit_field (body, insn, equiv_mem)
          offset /= BITS_PER_UNIT;
          if (GET_CODE (XEXP (bitfield, 0)) == SUBREG)
            {
-             offset += SUBREG_WORD (XEXP (bitfield, 0)) * UNITS_PER_WORD;
+             offset += (SUBREG_BYTE (XEXP (bitfield, 0))
+                        / UNITS_PER_WORD) * UNITS_PER_WORD;
              if (BYTES_BIG_ENDIAN)
                offset -= (MIN (UNITS_PER_WORD,
                                GET_MODE_SIZE (GET_MODE (XEXP (bitfield, 0))))
@@ -2745,7 +2736,7 @@ optimize_bit_field (body, insn, equiv_mem)
                {
                  rtx src = SET_SRC (body);
                  while (GET_CODE (src) == SUBREG
-                        && SUBREG_WORD (src) == 0)
+                        && SUBREG_BYTE (src) == 0)
                    src = SUBREG_REG (src);
                  if (GET_MODE (src) != GET_MODE (memref))
                    src = gen_lowpart (GET_MODE (memref), SET_SRC (body));
@@ -2766,7 +2757,7 @@ optimize_bit_field (body, insn, equiv_mem)
              rtx dest = SET_DEST (body);
 
              while (GET_CODE (dest) == SUBREG
-                    && SUBREG_WORD (dest) == 0
+                    && SUBREG_BYTE (dest) == 0
                     && (GET_MODE_CLASS (GET_MODE (dest))
                         == GET_MODE_CLASS (GET_MODE (SUBREG_REG (dest))))
                     && (GET_MODE_SIZE (GET_MODE (SUBREG_REG (dest)))
@@ -2969,7 +2960,7 @@ static rtx purge_addressof_replacements;
    the stack.  If the function returns FALSE then the replacement could not
    be made.  */
 
-static boolean
+static bool
 purge_addressof_1 (loc, insn, force, store, ht)
      rtx *loc;
      rtx insn;
@@ -2980,7 +2971,7 @@ purge_addressof_1 (loc, insn, force, store, ht)
   RTX_CODE code;
   int i, j;
   const char *fmt;
-  boolean result = true;
+  bool result = true;
 
   /* Re-start here to avoid recursion in common cases.  */
  restart:
@@ -3000,14 +2991,19 @@ purge_addressof_1 (loc, insn, force, store, ht)
       result &= purge_addressof_1 (&SET_SRC (x), insn, force, 0, ht);
       return result;
     }
-
-  else if (code == ADDRESSOF && GET_CODE (XEXP (x, 0)) == MEM)
+  else if (code == ADDRESSOF)
     {
+      rtx sub, insns;
+
+      if (GET_CODE (XEXP (x, 0)) != MEM)
+       {
+         put_addressof_into_stack (x, ht);
+         return true;
+       }
+         
       /* We must create a copy of the rtx because it was created by
         overwriting a REG rtx which is always shared.  */
-      rtx sub = copy_rtx (XEXP (XEXP (x, 0), 0));
-      rtx insns;
-
+      sub = copy_rtx (XEXP (XEXP (x, 0), 0));
       if (validate_change (insn, loc, sub, 0)
          || validate_replace_rtx (x, sub, insn))
        return true;
@@ -3076,7 +3072,7 @@ purge_addressof_1 (loc, insn, force, store, ht)
                       code did.  This is especially true of
                       REG_RETVAL.  */
 
-                   if (GET_CODE (z) == SUBREG && SUBREG_WORD (z) == 0)
+                   if (GET_CODE (z) == SUBREG && SUBREG_BYTE (z) == 0)
                      z = SUBREG_REG (z);
 
                    if (GET_MODE_SIZE (GET_MODE (x)) > UNITS_PER_WORD
@@ -3219,22 +3215,9 @@ purge_addressof_1 (loc, insn, force, store, ht)
            }
          goto restart;
        }
-    give_up:;
-      /* else give up and put it into the stack */
-    }
-
-  else if (code == ADDRESSOF)
-    {
-      put_addressof_into_stack (x, ht);
-      return true;
-    }
-  else if (code == SET)
-    {
-      result = purge_addressof_1 (&SET_DEST (x), insn, force, 1, ht);
-      result &= purge_addressof_1 (&SET_SRC (x), insn, force, 0, ht);
-      return result;
     }
 
+ give_up:
   /* Scan all subexpressions.  */
   fmt = GET_RTX_FORMAT (code);
   for (i = 0; i < GET_RTX_LENGTH (code); i++, fmt++)
@@ -3280,7 +3263,7 @@ insns_for_mem_hash (k)
 
 /* Return non-zero if K1 and K2 (two REGs) are the same.  */
 
-static boolean
+static bool
 insns_for_mem_comp (k1, k2)
      hash_table_key k1;
      hash_table_key k2;
@@ -3452,17 +3435,22 @@ purge_single_hard_subreg_set (pattern)
 {
   rtx reg = SET_DEST (pattern);
   enum machine_mode mode = GET_MODE (SET_DEST (pattern));
-  int word = 0;
-                 
-  while (GET_CODE (reg) == SUBREG)
+  int offset = 0;
+
+  if (GET_CODE (reg) == SUBREG && GET_CODE (SUBREG_REG (reg)) == REG
+      && REGNO (SUBREG_REG (reg)) < FIRST_PSEUDO_REGISTER)
     {
-      word += SUBREG_WORD (reg);
+      offset = subreg_regno_offset (REGNO (SUBREG_REG (reg)),
+                                   GET_MODE (SUBREG_REG (reg)),
+                                   SUBREG_BYTE (reg),
+                                   GET_MODE (reg));
       reg = SUBREG_REG (reg);
     }
-             
-  if (REGNO (reg) < FIRST_PSEUDO_REGISTER)
+
+                 
+  if (GET_CODE (reg) == REG && REGNO (reg) < FIRST_PSEUDO_REGISTER)
     {
-      reg = gen_rtx_REG (mode, REGNO (reg) + word);
+      reg = gen_rtx_REG (mode, REGNO (reg) + offset);
       SET_DEST (pattern) = reg;
     }
 }
@@ -3606,8 +3594,10 @@ instantiate_decls_1 (let, valid_only)
   tree t;
 
   for (t = BLOCK_VARS (let); t; t = TREE_CHAIN (t))
-    instantiate_decl (DECL_RTL (t), int_size_in_bytes (TREE_TYPE (t)),
-                     valid_only);
+    if (DECL_RTL_SET_P (t))
+      instantiate_decl (DECL_RTL (t), 
+                       int_size_in_bytes (TREE_TYPE (t)),
+                       valid_only);
 
   /* Process all subblocks.  */
   for (t = BLOCK_SUBBLOCKS (let); t; t = TREE_CHAIN (t))
@@ -4353,8 +4343,8 @@ assign_parms (fndecl)
          || TREE_CODE (parm) != PARM_DECL
          || passed_type == NULL)
        {
-         DECL_INCOMING_RTL (parm) = DECL_RTL (parm)
-           = gen_rtx_MEM (BLKmode, const0_rtx);
+         SET_DECL_RTL (parm, gen_rtx_MEM (BLKmode, const0_rtx));
+         DECL_INCOMING_RTL (parm) = DECL_RTL (parm);
          TREE_USED (parm) = 1;
          continue;
        }
@@ -4373,7 +4363,8 @@ assign_parms (fndecl)
         and avoid the usual things like emit_move_insn that could crash.  */
       if (nominal_mode == VOIDmode)
        {
-         DECL_INCOMING_RTL (parm) = DECL_RTL (parm) = const0_rtx;
+         SET_DECL_RTL (parm, const0_rtx);
+         DECL_INCOMING_RTL (parm) = DECL_RTL (parm);
          continue;
        }
 
@@ -4669,7 +4660,7 @@ assign_parms (fndecl)
                                     size_stored / UNITS_PER_WORD,
                                     int_size_in_bytes (TREE_TYPE (parm)));
            }
-         DECL_RTL (parm) = stack_parm;
+         SET_DECL_RTL (parm, stack_parm);
        }
       else if (! ((! optimize
                   && ! DECL_REGISTER (parm)
@@ -4701,13 +4692,17 @@ assign_parms (fndecl)
             appropriately.  */
          if (passed_pointer)
            {
-             DECL_RTL (parm)
-               = gen_rtx_MEM (TYPE_MODE (TREE_TYPE (passed_type)), parmreg);
+             SET_DECL_RTL (parm,
+                           gen_rtx_MEM (TYPE_MODE (TREE_TYPE (passed_type)), 
+                                        parmreg));
              set_mem_attributes (DECL_RTL (parm), parm, 1);
            }
          else
-           DECL_RTL (parm) = parmreg;
-
+           {
+             SET_DECL_RTL (parm, parmreg);
+             maybe_set_unchanging (DECL_RTL (parm), parm);
+           }
+             
          /* Copy the value into the register.  */
          if (nominal_mode != passed_mode
              || promoted_nominal_mode != promoted_mode)
@@ -4739,6 +4734,20 @@ assign_parms (fndecl)
              push_to_sequence (conversion_insns);
              tempreg = convert_to_mode (nominal_mode, tempreg, unsignedp);
 
+             if (GET_CODE (tempreg) == SUBREG
+                 && GET_MODE (tempreg) == nominal_mode
+                 && GET_CODE (SUBREG_REG (tempreg)) == REG
+                 && nominal_mode == passed_mode
+                 && GET_MODE (SUBREG_REG (tempreg)) == GET_MODE (entry_parm)
+                 && GET_MODE_SIZE (GET_MODE (tempreg))
+                    < GET_MODE_SIZE (GET_MODE (entry_parm)))
+               {
+                 /* The argument is already sign/zero extended, so note it
+                    into the subreg.  */
+                 SUBREG_PROMOTED_VAR_P (tempreg) = 1;
+                 SUBREG_PROMOTED_UNSIGNED_P (tempreg) = unsignedp;
+               }
+
              /* TREE_USED gets set erroneously during expand_assignment.  */
              save_tree_used = TREE_USED (parm);
              expand_assignment (parm,
@@ -4770,12 +4779,13 @@ assign_parms (fndecl)
              if (GET_MODE (parmreg) != GET_MODE (DECL_RTL (parm)))
                {
                  rtx tempreg = gen_reg_rtx (GET_MODE (DECL_RTL (parm)));
-
+                 int unsigned_p = TREE_UNSIGNED (TREE_TYPE (parm));
                  push_to_sequence (conversion_insns);
                  emit_move_insn (tempreg, DECL_RTL (parm));
-                 DECL_RTL (parm)
-                   = convert_to_mode (GET_MODE (parmreg), tempreg,
-                                      TREE_UNSIGNED (TREE_TYPE (parm)));
+                 SET_DECL_RTL (parm,
+                               convert_to_mode (GET_MODE (parmreg), 
+                                                tempreg,
+                                                unsigned_p));
                  emit_move_insn (parmreg, DECL_RTL (parm));
                  conversion_insns = get_insns();
                  did_conversion = 1;
@@ -4783,7 +4793,7 @@ assign_parms (fndecl)
                }
              else
                emit_move_insn (parmreg, DECL_RTL (parm));
-             DECL_RTL (parm) = parmreg;
+             SET_DECL_RTL (parm, parmreg);
              /* STACK_PARM is the pointer, not the parm, and PARMREG is
                 now the parm.  */
              stack_parm = 0;
@@ -5018,7 +5028,7 @@ assign_parms (fndecl)
              conversion_insns = get_insns ();
              end_sequence ();
            }
-         DECL_RTL (parm) = stack_parm;
+         SET_DECL_RTL (parm, stack_parm);
        }
 
       /* If this "parameter" was the place where we are receiving the
@@ -5027,8 +5037,8 @@ assign_parms (fndecl)
        {
          tree result = DECL_RESULT (fndecl);
 
-         DECL_RTL (result)
-           = gen_rtx_MEM (DECL_MODE (result), DECL_RTL (parm));
+         SET_DECL_RTL (result,
+                       gen_rtx_MEM (DECL_MODE (result), DECL_RTL (parm)));
 
          set_mem_attributes (DECL_RTL (result), result, 1);
        }
@@ -5087,7 +5097,9 @@ assign_parms (fndecl)
      to include tree.h.  Do this here so it gets done when an inlined
      function gets output.  */
 
-  current_function_return_rtx = DECL_RTL (DECL_RESULT (fndecl));
+  current_function_return_rtx
+    = (DECL_RTL_SET_P (DECL_RESULT (fndecl))
+       ? DECL_RTL (DECL_RESULT (fndecl)) : NULL_RTX);
 }
 \f
 /* Indicate whether REGNO is an incoming argument to the current function
@@ -6197,7 +6209,7 @@ init_function_start (subr, filename, line)
   /* Make sure first insn is a note even if we don't want linenums.
      This makes sure the first insn will never be deleted.
      Also, final expects a note to appear there.  */
-  emit_note (NULL_PTR, NOTE_INSN_DELETED);
+  emit_note (NULL, NOTE_INSN_DELETED);
 
   /* Set flags used by final.c.  */
   if (aggregate_value_p (DECL_RESULT (subr)))
@@ -6309,20 +6321,10 @@ expand_function_start (subr, parms_have_cleanups)
   else
     cleanup_label = 0;
 
-  /* Make the label for return statements to jump to, if this machine
-     does not have a one-instruction return and uses an epilogue,
-     or if it returns a structure, or if it has parm cleanups.  */
-#ifdef HAVE_return
-  if (cleanup_label == 0 && HAVE_return
-      && ! current_function_instrument_entry_exit
-      && ! current_function_returns_pcc_struct
-      && ! (current_function_returns_struct && ! optimize))
-    return_label = 0;
-  else
-    return_label = gen_label_rtx ();
-#else
+  /* Make the label for return statements to jump to.  Do not special
+     case machines with special return instructions -- they will be
+     handled later during jump, ifcvt, or epilogue creation.  */
   return_label = gen_label_rtx ();
-#endif
 
   /* Initialize rtx used to return the value.  */
   /* Do this before assign_parms so that we copy the struct value address
@@ -6354,16 +6356,19 @@ expand_function_start (subr, parms_have_cleanups)
        }
       if (value_address)
        {
-         DECL_RTL (DECL_RESULT (subr))
-           = gen_rtx_MEM (DECL_MODE (DECL_RESULT (subr)), value_address);
+         SET_DECL_RTL (DECL_RESULT (subr),
+                       gen_rtx_MEM (DECL_MODE (DECL_RESULT (subr)), 
+                                    value_address));
          set_mem_attributes (DECL_RTL (DECL_RESULT (subr)),
                              DECL_RESULT (subr), 1);
        }
     }
   else if (DECL_MODE (DECL_RESULT (subr)) == VOIDmode)
     /* If return mode is void, this decl rtl should not be used.  */
-    DECL_RTL (DECL_RESULT (subr)) = 0;
-  else if (parms_have_cleanups || current_function_instrument_entry_exit)
+    SET_DECL_RTL (DECL_RESULT (subr), NULL_RTX);
+  else if (parms_have_cleanups
+          || current_function_instrument_entry_exit
+          || (flag_exceptions && USING_SJLJ_EXCEPTIONS))
     {
       /* If function will end with cleanup code for parms,
         compute the return values into a pseudo reg,
@@ -6379,13 +6384,17 @@ expand_function_start (subr, parms_have_cleanups)
       mode = promote_mode (type, mode, &unsignedp, 1);
 #endif
 
-      DECL_RTL (DECL_RESULT (subr)) = gen_reg_rtx (mode);
+      SET_DECL_RTL (DECL_RESULT (subr), gen_reg_rtx (mode));
+      /* Needed because we may need to move this to memory
+        in case it's a named return value whose address is taken.  */
+      DECL_REGISTER (DECL_RESULT (subr)) = 1;
     }
   else
-    /* Scalar, returned in a register.  */
     {
-      DECL_RTL (DECL_RESULT (subr))
-       = hard_function_value (TREE_TYPE (DECL_RESULT (subr)), subr, 1);
+      /* Scalar, returned in a register.  */
+      SET_DECL_RTL (DECL_RESULT (subr),
+                   hard_function_value (TREE_TYPE (DECL_RESULT (subr)), 
+                                        subr, 1));
 
       /* Mark this reg as the function's return value.  */
       if (GET_CODE (DECL_RTL (DECL_RESULT (subr))) == REG)
@@ -6413,10 +6422,10 @@ expand_function_start (subr, parms_have_cleanups)
      The move is supposed to make sdb output more accurate.  */
   /* Indicate the beginning of the function body,
      as opposed to parm setup.  */
-  emit_note (NULL_PTR, NOTE_INSN_FUNCTION_BEG);
+  emit_note (NULL, NOTE_INSN_FUNCTION_BEG);
 
   if (GET_CODE (get_last_insn ()) != NOTE)
-    emit_note (NULL_PTR, NOTE_INSN_DELETED);
+    emit_note (NULL, NOTE_INSN_DELETED);
   parm_birth_insn = get_last_insn ();
 
   context_display = 0;
@@ -6488,7 +6497,7 @@ expand_function_start (subr, parms_have_cleanups)
   /* After the display initializations is where the tail-recursion label
      should go, if we end up needing one.   Ensure we have a NOTE here
      since some things (like trampolines) get placed before this.  */
-  tail_recursion_reentry = emit_note (NULL_PTR, NOTE_INSN_DELETED);
+  tail_recursion_reentry = emit_note (NULL, NOTE_INSN_DELETED);
 
   /* Evaluate now the sizes of any types declared among the arguments.  */
   for (tem = nreverse (get_pending_sizes ()); tem; tem = TREE_CHAIN (tem))
@@ -6746,7 +6755,7 @@ expand_function_end (filename, line, end_bindings)
   /* Mark the end of the function body.
      If control reaches this insn, the function can drop through
      without returning a value.  */
-  emit_note (NULL_PTR, NOTE_INSN_FUNCTION_END);
+  emit_note (NULL, NOTE_INSN_FUNCTION_END);
 
   /* Must mark the last line number note in the function, so that the test
      coverage code can avoid counting the last line twice.  This just tells
@@ -6754,63 +6763,40 @@ expand_function_end (filename, line, end_bindings)
      already exists a copy of this note somewhere above.  This line number
      note is still needed for debugging though, so we can't delete it.  */
   if (flag_test_coverage)
-    emit_note (NULL_PTR, NOTE_INSN_REPEATED_LINE_NUMBER);
+    emit_note (NULL, NOTE_INSN_REPEATED_LINE_NUMBER);
 
   /* Output a linenumber for the end of the function.
      SDB depends on this.  */
   emit_line_note_force (filename, line);
 
+  /* Before the return label (if any), clobber the return
+     registers so that they are not propogated live to the rest of
+     the function.  This can only happen with functions that drop
+     through; if there had been a return statement, there would
+     have either been a return rtx, or a jump to the return label.  */
+  {
+    rtx before, after;
+    
+    before = get_last_insn ();
+    clobber_return_register ();
+    after = get_last_insn ();
+    
+    if (before != after)
+      cfun->x_clobber_return_insn = after;
+  }
+
   /* Output the label for the actual return from the function,
      if one is expected.  This happens either because a function epilogue
      is used instead of a return instruction, or because a return was done
      with a goto in order to run local cleanups, or because of pcc-style
      structure returning.  */
-
   if (return_label)
-    {
-      rtx before, after;
-
-      /* Before the return label, clobber the return registers so that
-         they are not propogated live to the rest of the function.  This
-        can only happen with functions that drop through; if there had
-        been a return statement, there would have either been a return
-        rtx, or a jump to the return label.  */
-
-      before = get_last_insn ();
-      clobber_return_register ();
-      after = get_last_insn ();
-
-      if (before != after)
-       cfun->x_clobber_return_insn = after;
-
-      emit_label (return_label);
-    }
+    emit_label (return_label);
 
   /* C++ uses this.  */
   if (end_bindings)
     expand_end_bindings (0, 0, 0);
 
-  /* Now handle any leftover exception regions that may have been
-     created for the parameters.  */
-  {
-    rtx last = get_last_insn ();
-    rtx label;
-
-    expand_leftover_cleanups ();
-
-    /* If there are any catch_clauses remaining, output them now.  */
-    emit_insns (catch_clauses);
-    catch_clauses = catch_clauses_last = NULL_RTX;
-    /* If the above emitted any code, may sure we jump around it.  */
-    if (last != get_last_insn ())
-      {
-       label = gen_label_rtx ();
-       last = emit_jump_insn_after (gen_jump (label), last);
-       last = emit_barrier_after (last);
-       emit_label (label);
-      }
-  }
-
   if (current_function_instrument_entry_exit)
     {
       rtx fun = DECL_RTL (current_function_decl);
@@ -6826,6 +6812,11 @@ expand_function_end (filename, line, end_bindings)
                         Pmode);
     }
 
+  /* Let except.c know where it should emit the call to unregister
+     the function context for sjlj exceptions.  */
+  if (flag_exceptions && USING_SJLJ_EXCEPTIONS)
+    sjlj_emit_function_exit_after (get_last_insn ());
+
   /* If we had calls to alloca, and this machine needs
      an accurate stack pointer to exit the function,
      insert some code to save and restore the stack pointer.  */
@@ -6843,7 +6834,7 @@ expand_function_end (filename, line, end_bindings)
   /* If scalar return value was computed in a pseudo-reg, or was a named
      return value that got dumped to the stack, copy that to the hard
      return register.  */
-  if (DECL_RTL (DECL_RESULT (current_function_decl)) != 0)
+  if (DECL_RTL_SET_P (DECL_RESULT (current_function_decl)))
     {
       tree decl_result = DECL_RESULT (current_function_decl);
       rtx decl_rtl = DECL_RTL (decl_result);
@@ -6884,6 +6875,10 @@ expand_function_end (filename, line, end_bindings)
 
              convert_move (real_decl_rtl, decl_rtl, unsignedp);
            }
+         else if (GET_CODE (real_decl_rtl) == PARALLEL)
+           emit_group_load (real_decl_rtl, decl_rtl,
+                            int_size_in_bytes (TREE_TYPE (decl_result)),
+                            TYPE_ALIGN (TREE_TYPE (decl_result)));
          else
            emit_move_insn (real_decl_rtl, decl_rtl);
 
@@ -6933,16 +6928,16 @@ expand_function_end (filename, line, end_bindings)
       current_function_return_rtx = outgoing;
     }
 
+  /* If this is an implementation of throw, do what's necessary to
+     communicate between __builtin_eh_return and the epilogue.  */
+  expand_eh_return ();
+
   /* ??? This should no longer be necessary since stupid is no longer with
      us, but there are some parts of the compiler (eg reload_combine, and
      sh mach_dep_reorg) that still try and compute their own lifetime info
      instead of using the general framework.  */
   use_return_register ();
 
-  /* If this is an implementation of __throw, do what's necessary to
-     communicate between __builtin_eh_return and the epilogue.  */
-  expand_eh_return ();
-
   /* Output a return insn if we are using one.
      Otherwise, let the rtl chain end here, to drop through
      into the epilogue.  */
@@ -7381,7 +7376,13 @@ epilogue_done:
         there are line number notes before where we inserted the
         prologue we should move them, and (2) we should generate a
         note before the end of the first basic block, if there isn't
-        one already there.  */
+        one already there.
+
+        ??? This behaviour is completely broken when dealing with
+        multiple entry functions.  We simply place the note always
+        into first basic block and let alternate entry points
+        to be missed.
+       */
 
       for (insn = prologue_end; insn; insn = prev)
        {
@@ -7399,7 +7400,7 @@ epilogue_done:
 
       /* Find the last line number note in the first block.  */
       for (insn = BASIC_BLOCK (0)->end;
-          insn != prologue_end;
+          insn != prologue_end && insn;
           insn = PREV_INSN (insn))
        if (GET_CODE (insn) == NOTE && NOTE_LINE_NUMBER (insn) > 0)
          break;
@@ -7484,6 +7485,9 @@ reposition_prologue_and_epilogue_notes (f)
                BLOCK_HEAD (0) = next;
 
              remove_insn (note);
+             /* Avoid placing note between CODE_LABEL and BASIC_BLOCK note.  */
+             if (GET_CODE (insn) == CODE_LABEL)
+               insn = NEXT_INSN (insn);
              add_insn_after (note, insn);
            }
        }