OSDN Git Service

2000-08-10 Alexandre Petit-Bianco <apbianco@cygnus.com>
[pf3gnuchains/gcc-fork.git] / gcc / integrate.c
index ca200e8..2cf8813 100644 (file)
@@ -1,5 +1,6 @@
 /* Procedure integration for GNU CC.
-   Copyright (C) 1988, 91, 93-98, 1999, 2000 Free Software Foundation, Inc.
+   Copyright (C) 1988, 1991, 1993, 1994, 1995, 1996, 1997, 1998,
+   1999, 2000 Free Software Foundation, Inc.
    Contributed by Michael Tiemann (tiemann@cygnus.com)
 
 This file is part of GNU CC.
@@ -61,25 +62,33 @@ extern struct obstack *function_maybepermanent_obstack;
    ? (1 + (3 * list_length (DECL_ARGUMENTS (DECL))) / 2) \
    : (8 * (8 + list_length (DECL_ARGUMENTS (DECL)))))
 #endif
+
+/* Decide whether a function with a target specific attribute 
+   attached can be inlined.  By default we disallow this.  */
+#ifndef FUNCTION_ATTRIBUTE_INLINABLE_P
+#define FUNCTION_ATTRIBUTE_INLINABLE_P(FNDECL) 0
+#endif
 \f
-static rtvec initialize_for_inline     PROTO((tree));
-static void note_modified_parmregs     PROTO((rtx, rtx, void *));
-static void integrate_parm_decls       PROTO((tree, struct inline_remap *,
-                                              rtvec));
-static tree integrate_decl_tree                PROTO((tree,
-                                              struct inline_remap *));
-static void subst_constants            PROTO((rtx *, rtx,
-                                              struct inline_remap *, int));
-static void set_block_origin_self      PROTO((tree));
-static void set_decl_origin_self       PROTO((tree));
-static void set_block_abstract_flags   PROTO((tree, int));
-static void process_reg_param          PROTO((struct inline_remap *, rtx,
-                                              rtx));
-void set_decl_abstract_flags           PROTO((tree, int));
-static rtx expand_inline_function_eh_labelmap PROTO((rtx));
-static void mark_stores                 PROTO((rtx, rtx, void *));
-static int compare_blocks               PROTO((const PTR, const PTR));
-static int find_block                   PROTO((const PTR, const PTR));
+static rtvec initialize_for_inline     PARAMS ((tree));
+static void note_modified_parmregs     PARAMS ((rtx, rtx, void *));
+static void integrate_parm_decls       PARAMS ((tree, struct inline_remap *,
+                                                rtvec));
+static tree integrate_decl_tree                PARAMS ((tree,
+                                                struct inline_remap *));
+static void subst_constants            PARAMS ((rtx *, rtx,
+                                                struct inline_remap *, int));
+static void set_block_origin_self      PARAMS ((tree));
+static void set_block_abstract_flags   PARAMS ((tree, int));
+static void process_reg_param          PARAMS ((struct inline_remap *, rtx,
+                                                rtx));
+void set_decl_abstract_flags           PARAMS ((tree, int));
+static rtx expand_inline_function_eh_labelmap PARAMS ((rtx));
+static void mark_stores                 PARAMS ((rtx, rtx, void *));
+static void save_parm_insns            PARAMS ((rtx, rtx));
+static void copy_insn_list              PARAMS ((rtx, struct inline_remap *,
+                                                rtx));
+static int compare_blocks               PARAMS ((const PTR, const PTR));
+static int find_block                   PARAMS ((const PTR, const PTR));
 
 /* The maximum number of instructions accepted for inlining a
    function.  Increasing values mean more agressive inlining.
@@ -182,7 +191,8 @@ function_cannot_inline_p (fndecl)
     return N_("inline functions not supported for this return value type");
 
   /* We can't inline functions that return structures of varying size.  */
-  if (int_size_in_bytes (TREE_TYPE (TREE_TYPE (fndecl))) < 0)
+  if (TREE_CODE (TREE_TYPE (TREE_TYPE (fndecl))) != VOID_TYPE
+      && int_size_in_bytes (TREE_TYPE (TREE_TYPE (fndecl))) < 0)
     return N_("function with varying-size return value cannot be inline");
 
   /* Cannot inline a function with a varying size argument or one that
@@ -191,7 +201,8 @@ function_cannot_inline_p (fndecl)
     {
       if (int_size_in_bytes (TREE_TYPE (parms)) < 0)
        return N_("function with varying-size parameter cannot be inline");
-      else if (TYPE_TRANSPARENT_UNION (TREE_TYPE (parms)))
+      else if (TREE_CODE (TREE_TYPE (parms)) == UNION_TYPE
+              && TYPE_TRANSPARENT_UNION (TREE_TYPE (parms)))
        return N_("function with transparent unit parameter cannot be inline");
     }
 
@@ -200,7 +211,7 @@ function_cannot_inline_p (fndecl)
       for (ninsns = 0, insn = get_first_nonparm_insn ();
           insn && ninsns < max_insns;
           insn = NEXT_INSN (insn))
-       if (GET_RTX_CLASS (GET_CODE (insn)) == 'i')
+       if (INSN_P (insn))
          ninsns++;
 
       if (ninsns >= max_insns)
@@ -235,7 +246,14 @@ function_cannot_inline_p (fndecl)
   if (result && GET_CODE (result) == PARALLEL)
     return N_("inline functions not supported for this return value type");
 
-  return 0;
+  /* If the function has a target specific attribute attached to it,
+     then we assume that we should not inline it.  This can be overriden
+     by the target if it defines FUNCTION_ATTRIBUTE_INLINABLE_P.  */
+  if (DECL_MACHINE_ATTRIBUTES (fndecl)
+      && ! FUNCTION_ATTRIBUTE_INLINABLE_P (fndecl))
+    return N_("function with target specific attribute(s) cannot be inlined");
+
+  return NULL;
 }
 \f
 /* Map pseudo reg number into the PARM_DECL for the parm living in the reg.
@@ -311,9 +329,14 @@ copy_decl_for_inlining (decl, from_fn, to_fn)
 
   /* Copy the declaration.  */
   if (TREE_CODE (decl) == PARM_DECL || TREE_CODE (decl) == RESULT_DECL)
-    /* For a parameter, we must make an equivalent VAR_DECL, not a
-       new PARM_DECL.  */
-    copy = build_decl (VAR_DECL, DECL_NAME (decl), TREE_TYPE (decl));
+    {
+      /* For a parameter, we must make an equivalent VAR_DECL, not a
+        new PARM_DECL.  */
+      copy = build_decl (VAR_DECL, DECL_NAME (decl), TREE_TYPE (decl));
+      TREE_ADDRESSABLE (copy) = TREE_ADDRESSABLE (decl);
+      TREE_READONLY (copy) = TREE_READONLY (decl);
+      TREE_THIS_VOLATILE (copy) = TREE_THIS_VOLATILE (decl);
+    }
   else
     {
       copy = copy_node (decl);
@@ -420,15 +443,7 @@ save_for_inline_nocopy (fndecl)
      Otherwise, we have to copy its value into a new register and track
      the new register's life.  */
   in_nonparm_insns = 0;
-  for (insn = NEXT_INSN (insn); insn; insn = NEXT_INSN (insn))
-    {
-      if (insn == first_nonparm_insn)
-       in_nonparm_insns = 1;
-
-      if (GET_RTX_CLASS (GET_CODE (insn)) == 'i')
-       /* Record what interesting things happen to our parameters.  */
-       note_stores (PATTERN (insn), note_modified_parmregs, NULL);
-    }
+  save_parm_insns (insn, first_nonparm_insn);
 
   /* We have now allocated all that needs to be allocated permanently
      on the rtx obstack.  Set our high-water mark, so that we
@@ -445,6 +460,46 @@ save_for_inline_nocopy (fndecl)
   /* Clean up.  */
   free (parmdecl_map);
 }
+
+/* Scan the chain of insns to see what happens to our PARM_DECLs.  If a
+   PARM_DECL is used but never modified, we can substitute its rtl directly
+   when expanding inline (and perform constant folding when its incoming
+   value is constant). Otherwise, we have to copy its value into a new
+   register and track the new register's life.  */
+
+static void
+save_parm_insns (insn, first_nonparm_insn)
+    rtx insn;
+    rtx first_nonparm_insn;
+{
+  if (insn == NULL_RTX)
+    return;
+
+  for (insn = NEXT_INSN (insn); insn; insn = NEXT_INSN (insn))
+    {
+      if (insn == first_nonparm_insn)
+       in_nonparm_insns = 1;
+
+      if (INSN_P (insn))
+       {
+         /* Record what interesting things happen to our parameters.  */
+         note_stores (PATTERN (insn), note_modified_parmregs, NULL);
+
+         /* If this is a CALL_PLACEHOLDER insn then we need to look into the
+            three attached sequences: normal call, sibling call and tail
+            recursion. */
+         if (GET_CODE (insn) == CALL_INSN
+             && GET_CODE (PATTERN (insn)) == CALL_PLACEHOLDER)
+           {
+             int i;
+
+             for (i = 0; i < 3; i++)
+               save_parm_insns (XEXP (PATTERN (insn), i),
+                                first_nonparm_insn);
+           }
+       }
+    }
+}
 \f
 /* Note whether a parameter is modified or not.  */
 
@@ -521,8 +576,8 @@ compare_blocks (v1, v2)
      const PTR v1;
      const PTR v2;
 {
-  tree b1 = *((tree *) v1);
-  tree b2 = *((tree *) v2);
+  tree b1 = *((const tree *) v1);
+  tree b2 = *((const tree *) v2);
 
   return ((char *) BLOCK_ABSTRACT_ORIGIN (b1) 
          - (char *) BLOCK_ABSTRACT_ORIGIN (b2));
@@ -536,10 +591,10 @@ find_block (v1, v2)
      const PTR v1;
      const PTR v2;
 {
-  tree b1 = (tree) v1;
-  tree b2 = *((tree *) v2);
+  const union tree_node *b1 = (const union tree_node *) v1;
+  tree b2 = *((const tree *) v2);
 
-  return ((char *) b1 - (char *) BLOCK_ABSTRACT_ORIGIN (b2));
+  return ((const char *) b1 - (char *) BLOCK_ABSTRACT_ORIGIN (b2));
 }
 
 /* Integrate the procedure defined by FNDECL.  Note that this function
@@ -573,13 +628,11 @@ expand_inline_function (fndecl, parms, target, ignore, type,
               : parm_insns);
   tree *arg_trees;
   rtx *arg_vals;
-  rtx insn;
   int max_regno;
   register int i;
   int min_labelno = inl_f->emit->x_first_label_num;
   int max_labelno = inl_f->inl_max_label_num;
   int nargs;
-  rtx local_return_label = 0;
   rtx loc;
   rtx stack_save = 0;
   rtx temp;
@@ -602,6 +655,9 @@ expand_inline_function (fndecl, parms, target, ignore, type,
 
   nargs = list_length (DECL_ARGUMENTS (fndecl));
 
+  if (cfun->preferred_stack_boundary < inl_f->preferred_stack_boundary)
+    cfun->preferred_stack_boundary = inl_f->preferred_stack_boundary;
+
   /* Check that the parms type match and that sufficient arguments were
      passed.  Since the appropriate conversions or default promotions have
      already been applied, the machine modes should match exactly.  */
@@ -715,8 +771,7 @@ expand_inline_function (fndecl, parms, target, ignore, type,
       if (arg_vals[i] != 0 && GET_CODE (arg_vals[i]) == REG
          && POINTER_TYPE_P (TREE_TYPE (formal)))
        mark_reg_pointer (arg_vals[i],
-                         (TYPE_ALIGN (TREE_TYPE (TREE_TYPE (formal)))
-                          / BITS_PER_UNIT));
+                         TYPE_ALIGN (TREE_TYPE (TREE_TYPE (formal))));
     }
        
   /* Allocate the structures we use to remap things.  */
@@ -1082,7 +1137,100 @@ expand_inline_function (fndecl, parms, target, ignore, type,
   if (inl_f->calls_alloca)
     emit_stack_save (SAVE_BLOCK, &stack_save, NULL_RTX);
 
-  /* Now copy the insns one by one.  Do this in two passes, first the insns and
+  /* Now copy the insns one by one.  */
+  copy_insn_list (insns, map, static_chain_value);
+
+  /* Restore the stack pointer if we saved it above.  */
+  if (inl_f->calls_alloca)
+    emit_stack_restore (SAVE_BLOCK, stack_save, NULL_RTX);
+
+  if (! cfun->x_whole_function_mode_p)
+    /* In statement-at-a-time mode, we just tell the front-end to add
+       this block to the list of blocks at this binding level.  We
+       can't do it the way it's done for function-at-a-time mode the
+       superblocks have not been created yet.  */
+    insert_block (block);
+  else
+    {
+      BLOCK_CHAIN (block) 
+       = BLOCK_CHAIN (DECL_INITIAL (current_function_decl));
+      BLOCK_CHAIN (DECL_INITIAL (current_function_decl)) = block;
+    }
+
+  /* End the scope containing the copied formal parameter variables
+     and copied LABEL_DECLs.  We pass NULL_TREE for the variables list
+     here so that expand_end_bindings will not check for unused
+     variables.  That's already been checked for when the inlined
+     function was defined.  */
+  expand_end_bindings (NULL_TREE, 1, 1);
+
+  /* Must mark the line number note after inlined functions as a repeat, so
+     that the test coverage code can avoid counting the call twice.  This
+     just tells the code to ignore the immediately following line note, since
+     there already exists a copy of this note before the expanded inline call.
+     This line number note is still needed for debugging though, so we can't
+     delete it.  */
+  if (flag_test_coverage)
+    emit_note (0, NOTE_INSN_REPEATED_LINE_NUMBER);
+
+  emit_line_note (input_filename, lineno);
+
+  /* If the function returns a BLKmode object in a register, copy it
+     out of the temp register into a BLKmode memory object. */
+  if (target 
+      && TYPE_MODE (TREE_TYPE (TREE_TYPE (fndecl))) == BLKmode
+      && ! aggregate_value_p (TREE_TYPE (TREE_TYPE (fndecl))))
+    target = copy_blkmode_from_reg (0, target, TREE_TYPE (TREE_TYPE (fndecl)));
+  
+  if (structure_value_addr)
+    {
+      target = gen_rtx_MEM (TYPE_MODE (type),
+                           memory_address (TYPE_MODE (type),
+                                           structure_value_addr));
+      set_mem_attributes (target, type, 1);
+    }
+
+  /* Make sure we free the things we explicitly allocated with xmalloc.  */
+  if (real_label_map)
+    free (real_label_map);
+  VARRAY_FREE (map->const_equiv_varray);
+  free (map->reg_map);
+  VARRAY_FREE (map->block_map);
+  free (map->insn_map);
+  free (map);
+  free (arg_vals);
+  free (arg_trees);
+
+  inlining = inlining_previous;
+
+  return target;
+}
+
+/* Make copies of each insn in the given list using the mapping
+   computed in expand_inline_function. This function may call itself for
+   insns containing sequences.
+   
+   Copying is done in two passes, first the insns and then their REG_NOTES,
+   just like save_for_inline.
+
+   If static_chain_value is non-zero, it represents the context-pointer
+   register for the function. */
+
+static void
+copy_insn_list (insns, map, static_chain_value)
+    rtx insns;
+    struct inline_remap *map;
+    rtx static_chain_value;
+{
+  register int i;
+  rtx insn;
+  rtx temp;
+  rtx local_return_label = NULL_RTX;
+#ifdef HAVE_cc0
+  rtx cc0_insn = 0;
+#endif
+
+  /* Copy the insns one by one.  Do this in two passes, first the insns and
      then their REG_NOTES, just like save_for_inline.  */
 
   /* This loop is very similar to the loop in copy_loop_body in unroll.c.  */
@@ -1253,7 +1401,7 @@ expand_inline_function (fndecl, parms, target, ignore, type,
 
          /* If this used to be a conditional jump insn but whose branch
             direction is now know, we must do something special.  */
-         if (condjump_p (insn) && ! simplejump_p (insn) && map->last_pc_value)
+         if (any_condjump_p (insn) && onlyjump_p (insn) && map->last_pc_value)
            {
 #ifdef HAVE_cc0
              /* If the previous insn set cc0 for us, delete it.  */
@@ -1276,11 +1424,50 @@ expand_inline_function (fndecl, parms, target, ignore, type,
          break;
 
        case CALL_INSN:
+         /* If this is a CALL_PLACEHOLDER insn then we need to copy the
+            three attached sequences: normal call, sibling call and tail
+            recursion. */
+         if (GET_CODE (PATTERN (insn)) == CALL_PLACEHOLDER)
+           {
+             rtx sequence[3];
+             rtx tail_label;
+
+             for (i = 0; i < 3; i++)
+               {
+                 rtx seq;
+                 
+                 sequence[i] = NULL_RTX;
+                 seq = XEXP (PATTERN (insn), i);
+                 if (seq)
+                   {
+                     start_sequence ();
+                     copy_insn_list (seq, map, static_chain_value);
+                     sequence[i] = get_insns ();
+                     end_sequence ();
+                   }
+               }
+
+             /* Find the new tail recursion label.  
+                It will already be substituted into sequence[2].  */
+             tail_label = copy_rtx_and_substitute (XEXP (PATTERN (insn), 3),
+                                                   map, 0);
+
+             copy = emit_call_insn (gen_rtx_CALL_PLACEHOLDER (VOIDmode, 
+                                                       sequence[0],
+                                                       sequence[1],
+                                                       sequence[2],
+                                                       tail_label));
+             break;
+           }
+
          pattern = copy_rtx_and_substitute (PATTERN (insn), map, 0);
          copy = emit_call_insn (pattern);
 
+         SIBLING_CALL_P (copy) = SIBLING_CALL_P (insn);
+
          /* Because the USAGE information potentially contains objects other
             than hard registers, we need to copy it.  */
+
          CALL_INSN_FUNCTION_USAGE (copy)
            = copy_rtx_and_substitute (CALL_INSN_FUNCTION_USAGE (insn),
                                       map, 0);
@@ -1292,7 +1479,7 @@ expand_inline_function (fndecl, parms, target, ignore, type,
 #endif
          try_constants (copy, map);
 
-         /* Be lazy and assume CALL_INSNs clobber all hard registers.  */
+             /* Be lazy and assume CALL_INSNs clobber all hard registers.  */
          for (i = 0; i < FIRST_PSEUDO_REGISTER; i++)
            VARRAY_CONST_EQUIV (map->const_equiv_varray, i).rtx = 0;
          break;
@@ -1309,14 +1496,23 @@ expand_inline_function (fndecl, parms, target, ignore, type,
          break;
 
        case NOTE:
-         /* It is important to discard function-end and function-beg notes,
-            so we have only one of each in the current function.
-            Also, NOTE_INSN_DELETED notes aren't useful (save_for_inline
+         /* NOTE_INSN_FUNCTION_END and NOTE_INSN_FUNCTION_BEG are 
+            discarded because it is important to have only one of 
+            each in the current function.
+
+            NOTE_INSN_DELETED notes aren't useful (save_for_inline
             deleted these in the copy used for continuing compilation,
-            not the copy used for inlining).  */
+            not the copy used for inlining).
+
+            NOTE_INSN_BASIC_BLOCK is discarded because the saved bb
+            pointer (which will soon be dangling) confuses flow's
+            attempts to preserve bb structures during the compilation
+            of a function.  */
+
          if (NOTE_LINE_NUMBER (insn) != NOTE_INSN_FUNCTION_END
              && NOTE_LINE_NUMBER (insn) != NOTE_INSN_FUNCTION_BEG
-             && NOTE_LINE_NUMBER (insn) != NOTE_INSN_DELETED)
+             && NOTE_LINE_NUMBER (insn) != NOTE_INSN_DELETED
+             && NOTE_LINE_NUMBER (insn) != NOTE_INSN_BASIC_BLOCK)
            {
              copy = emit_note (NOTE_SOURCE_FILE (insn),
                                NOTE_LINE_NUMBER (insn));
@@ -1381,86 +1577,29 @@ expand_inline_function (fndecl, parms, target, ignore, type,
      are valid across the entire function.  */
   map->const_age++;
   for (insn = insns; insn; insn = NEXT_INSN (insn))
-    if (GET_RTX_CLASS (GET_CODE (insn)) == 'i'
+    if (INSN_P (insn)
        && map->insn_map[INSN_UID (insn)]
        && REG_NOTES (insn))
       {
-       rtx tem = copy_rtx_and_substitute (REG_NOTES (insn), map, 0);
+       rtx next, note = copy_rtx_and_substitute (REG_NOTES (insn), map, 0);
 
        /* We must also do subst_constants, in case one of our parameters
           has const type and constant value.  */
-       subst_constants (&tem, NULL_RTX, map, 0);
+       subst_constants (&note, NULL_RTX, map, 0);
        apply_change_group ();
-       REG_NOTES (map->insn_map[INSN_UID (insn)]) = tem;
+       REG_NOTES (map->insn_map[INSN_UID (insn)]) = note;
+
+       /* Finally, delete any REG_LABEL notes from the chain.  */                
+       for (; note; note = next)
+         {
+           next = XEXP (note, 1);
+           if (REG_NOTE_KIND (note) == REG_LABEL)
+             remove_note (map->insn_map[INSN_UID (insn)], note);
+         }
       }
 
   if (local_return_label)
     emit_label (local_return_label);
-
-  /* Restore the stack pointer if we saved it above.  */
-  if (inl_f->calls_alloca)
-    emit_stack_restore (SAVE_BLOCK, stack_save, NULL_RTX);
-
-  if (! cfun->x_whole_function_mode_p)
-    /* In statement-at-a-time mode, we just tell the front-end to add
-       this block to the list of blocks at this binding level.  We
-       can't do it the way it's done for function-at-a-time mode the
-       superblocks have not been created yet.  */
-    insert_block (block);
-  else
-    {
-      BLOCK_CHAIN (block) 
-       = BLOCK_CHAIN (DECL_INITIAL (current_function_decl));
-      BLOCK_CHAIN (DECL_INITIAL (current_function_decl)) = block;
-    }
-
-  /* End the scope containing the copied formal parameter variables
-     and copied LABEL_DECLs.  We pass NULL_TREE for the variables list
-     here so that expand_end_bindings will not check for unused
-     variables.  That's already been checked for when the inlined
-     function was defined.  */
-  expand_end_bindings (NULL_TREE, 1, 1);
-
-  /* Must mark the line number note after inlined functions as a repeat, so
-     that the test coverage code can avoid counting the call twice.  This
-     just tells the code to ignore the immediately following line note, since
-     there already exists a copy of this note before the expanded inline call.
-     This line number note is still needed for debugging though, so we can't
-     delete it.  */
-  if (flag_test_coverage)
-    emit_note (0, NOTE_REPEATED_LINE_NUMBER);
-
-  emit_line_note (input_filename, lineno);
-
-  /* If the function returns a BLKmode object in a register, copy it
-     out of the temp register into a BLKmode memory object. */
-  if (target 
-      && TYPE_MODE (TREE_TYPE (TREE_TYPE (fndecl))) == BLKmode
-      && ! aggregate_value_p (TREE_TYPE (TREE_TYPE (fndecl))))
-    target = copy_blkmode_from_reg (0, target, TREE_TYPE (TREE_TYPE (fndecl)));
-  
-  if (structure_value_addr)
-    {
-      target = gen_rtx_MEM (TYPE_MODE (type),
-                           memory_address (TYPE_MODE (type),
-                                           structure_value_addr));
-      MEM_SET_IN_STRUCT_P (target, 1);
-    }
-
-  /* Make sure we free the things we explicitly allocated with xmalloc.  */
-  if (real_label_map)
-    free (real_label_map);
-  VARRAY_FREE (map->const_equiv_varray);
-  free (map->reg_map);
-  VARRAY_FREE (map->block_map);
-  free (map->insn_map);
-  free (map);
-  free (arg_vals);
-  free (arg_trees);
-
-  inlining = inlining_previous;
-
-  return target;
 }
 \f
 /* Given a chain of PARM_DECLs, ARGS, copy each decl into a VAR_DECL,
@@ -1619,13 +1758,17 @@ copy_rtx_and_substitute (orig, map, for_lhs)
            {
              rtx loc, seq;
              int size = get_func_frame_size (DECL_SAVED_INSNS (map->fndecl));
-
 #ifdef FRAME_GROWS_DOWNWARD
+             int alignment
+               = (DECL_SAVED_INSNS (map->fndecl)->stack_alignment_needed
+                  / BITS_PER_UNIT);
+
              /* In this case, virtual_stack_vars_rtx points to one byte
                 higher than the top of the frame area.  So make sure we
                 allocate a big enough chunk to keep the frame pointer
                 aligned like a real one.  */
-             size = CEIL_ROUND (size, BIGGEST_ALIGNMENT / BITS_PER_UNIT);
+             if (alignment)
+               size = CEIL_ROUND (size, alignment);
 #endif
              start_sequence ();
              loc = assign_stack_temp (BLKmode, size, 1);
@@ -1640,8 +1783,7 @@ copy_rtx_and_substitute (orig, map, for_lhs)
                = force_reg (Pmode, force_operand (loc, NULL_RTX));
 
 #ifdef STACK_BOUNDARY
-             mark_reg_pointer (map->reg_map[regno],
-                               STACK_BOUNDARY / BITS_PER_UNIT);
+             mark_reg_pointer (map->reg_map[regno], STACK_BOUNDARY);
 #endif
 
              SET_CONST_EQUIV_DATA (map, temp, loc, CONST_AGE_PARM);
@@ -1674,8 +1816,7 @@ copy_rtx_and_substitute (orig, map, for_lhs)
                = force_reg (Pmode, force_operand (loc, NULL_RTX));
 
 #ifdef STACK_BOUNDARY
-             mark_reg_pointer (map->reg_map[regno],
-                               STACK_BOUNDARY / BITS_PER_UNIT);
+             mark_reg_pointer (map->reg_map[regno], STACK_BOUNDARY);
 #endif
 
              SET_CONST_EQUIV_DATA (map, temp, loc, CONST_AGE_PARM);
@@ -1779,6 +1920,13 @@ copy_rtx_and_substitute (orig, map, for_lhs)
        = LABEL_PRESERVE_P (orig);
       return get_label_from_map (map, CODE_LABEL_NUMBER (orig));
 
+    /* We need to handle "deleted" labels that appear in the DECL_RTL
+       of a LABEL_DECL.  */
+    case NOTE:
+      if (NOTE_LINE_NUMBER (orig) == NOTE_INSN_DELETED_LABEL)
+       return map->insn_map[INSN_UID (orig)];
+      break;
+
     case LABEL_REF:
       copy
        = gen_rtx_LABEL_REF
@@ -1991,8 +2139,6 @@ copy_rtx_and_substitute (orig, map, for_lhs)
       PUT_MODE (copy, mode);
       XEXP (copy, 0) = copy_rtx_and_substitute (XEXP (orig, 0), map, 0);
       MEM_COPY_ATTRIBUTES (copy, orig);
-      MEM_ALIAS_SET (copy) = MEM_ALIAS_SET (orig);
-      RTX_UNCHANGING_P (copy) = RTX_UNCHANGING_P (orig);
       return copy;
       
     default:
@@ -2337,6 +2483,7 @@ subst_constants (loc, insn, map, memonly)
        case 'i':
        case 's':
        case 'w':
+       case 'n':
        case 't':
          break;
 
@@ -2384,9 +2531,16 @@ subst_constants (loc, insn, map, memonly)
                                               XEXP (x, 0), XEXP (x, 1));
 #ifdef FLOAT_STORE_FLAG_VALUE
          if (new != 0 && GET_MODE_CLASS (GET_MODE (x)) == MODE_FLOAT)
-         new = ((new == const0_rtx) ? CONST0_RTX (GET_MODE (x))
-                : CONST_DOUBLE_FROM_REAL_VALUE (FLOAT_STORE_FLAG_VALUE,
-                                                GET_MODE (x)));
+           {
+             enum machine_mode mode = GET_MODE (x);
+             if (new == const0_rtx)
+               new = CONST0_RTX (mode);
+             else
+               {
+                 REAL_VALUE_TYPE val = FLOAT_STORE_FLAG_VALUE (mode);
+                 new = CONST_DOUBLE_FROM_REAL_VALUE (val, mode);
+               }
+           }
 #endif
          break;
       }
@@ -2437,15 +2591,16 @@ mark_stores (dest, x, data)
 
   if (regno >= 0)
     {
-      int last_reg = (regno >= FIRST_PSEUDO_REGISTER ? regno
-                     : regno + HARD_REGNO_NREGS (regno, mode) - 1);
-      int i;
+      unsigned int uregno = regno;
+      unsigned int last_reg = (uregno >= FIRST_PSEUDO_REGISTER ? uregno
+                             : uregno + HARD_REGNO_NREGS (uregno, mode) - 1);
+      unsigned int i;
 
       /* Ignore virtual stack var or virtual arg register since those
         are handled separately.  */
-      if (regno != VIRTUAL_INCOMING_ARGS_REGNUM
-         && regno != VIRTUAL_STACK_VARS_REGNUM)
-       for (i = regno; i <= last_reg; i++)
+      if (uregno != VIRTUAL_INCOMING_ARGS_REGNUM
+         && uregno != VIRTUAL_STACK_VARS_REGNUM)
+       for (i = uregno; i <= last_reg; i++)
          if ((size_t) i < VARRAY_SIZE (global_const_equiv_varray))
            VARRAY_CONST_EQUIV (global_const_equiv_varray, i).rtx = 0;
     }
@@ -2500,7 +2655,7 @@ set_block_origin_self (stmt)
    set *their* DECL_ABSTRACT_ORIGIN or BLOCK_ABSTRACT_ORIGIN values to
    point to themselves.  */
 
-static void
+void
 set_decl_origin_self (decl)
      register tree decl;
 {
@@ -2591,27 +2746,16 @@ output_inline_function (fndecl)
 
   set_new_last_label_num (f->inl_max_label_num);
 
-  /* We must have already output DWARF debugging information for the
-     original (abstract) inline function declaration/definition, so
-     we want to make sure that the debugging information we generate
-     for this special instance of the inline function refers back to
-     the information we already generated.  To make sure that happens,
-     we simply have to set the DECL_ABSTRACT_ORIGIN for the function
-     node (and for all of the local ..._DECL nodes which are its children)
-     so that they all point to themselves.  */
-
-  set_decl_origin_self (fndecl);
-
   /* We're not deferring this any longer.  */
   DECL_DEFER_OUTPUT (fndecl) = 0;
 
+  /* Compile this function all the way down to assembly code.  */
+  rest_of_compilation (fndecl);
+
   /* We can't inline this anymore.  */
   f->inlinable = 0;
   DECL_INLINE (fndecl) = 0;
 
-  /* Compile this function all the way down to assembly code.  */
-  rest_of_compilation (fndecl);
-
   cfun = old_cfun;
   current_function_decl = old_cfun ? old_cfun->decl : 0;
 }