OSDN Git Service

* c-common.c: Include <stdlib.h> and <string.h>/<strings.h>.
[pf3gnuchains/gcc-fork.git] / gcc / integrate.c
index 4ecbfb2..1dd29bd 100644 (file)
@@ -1,5 +1,5 @@
 /* Procedure integration for GNU CC.
-   Copyright (C) 1988, 91, 93, 94, 95, 1996 Free Software Foundation, Inc.
+   Copyright (C) 1988, 91, 93, 94, 95, 96, 1997 Free Software Foundation, Inc.
    Contributed by Michael Tiemann (tiemann@cygnus.com)
 
 This file is part of GNU CC.
@@ -20,9 +20,13 @@ the Free Software Foundation, 59 Temple Place - Suite 330,
 Boston, MA 02111-1307, USA.  */
 
 
+#include "config.h"
 #include <stdio.h>
 
-#include "config.h"
+#ifdef HAVE_STDLIB_H
+#include <stdlib.h>
+#endif
+
 #include "rtl.h"
 #include "tree.h"
 #include "regs.h"
@@ -31,10 +35,11 @@ Boston, MA 02111-1307, USA.  */
 #include "insn-flags.h"
 #include "expr.h"
 #include "output.h"
+#include "recog.h"
 #include "integrate.h"
 #include "real.h"
+#include "except.h"
 #include "function.h"
-#include "bytecode.h"
 
 #include "obstack.h"
 #define        obstack_chunk_alloc     xmalloc
@@ -52,8 +57,12 @@ extern tree poplevel ();
 /* Default max number of insns a function can have and still be inline.
    This is overridden on RISC machines.  */
 #ifndef INTEGRATE_THRESHOLD
+/* Inlining small functions might save more space then not inlining at
+   all.  Assume 1 instruction for the call and 1.5 insns per argument.  */
 #define INTEGRATE_THRESHOLD(DECL) \
-  (8 * (8 + list_length (DECL_ARGUMENTS (DECL))))
+  (optimize_size \
+   ? (1 + (3 * list_length (DECL_ARGUMENTS (DECL)) / 2)) \
+   : (8 * (8 + list_length (DECL_ARGUMENTS (DECL)))))
 #endif
 \f
 static rtx initialize_for_inline PROTO((tree, int, int, int, int));
@@ -76,6 +85,25 @@ static void set_block_abstract_flags PROTO((tree, int));
 
 void set_decl_abstract_flags   PROTO((tree, int));
 \f
+/* Returns the Ith entry in the label_map contained in MAP.  If the
+   Ith entry has not yet been set, it is assumed to be a fresh label.
+   Essentially, we use this function to perform a lazy initialization
+   of label_map, thereby avoiding huge memory explosions when the
+   label_map gets very large.  */
+rtx
+get_label_from_map (map, i)
+     struct inline_remap* map;
+     int i;
+{
+  rtx x = map->label_map[i];
+
+  if (x == NULL_RTX)
+    x = map->label_map[i] = gen_label_rtx();
+
+  return x;
+}
+
+
 /* Zero if the current function (whose FUNCTION_DECL is FNDECL)
    is safe and reasonable to integrate into other functions.
    Nonzero means value is a warning message with a single %s
@@ -90,6 +118,7 @@ function_cannot_inline_p (fndecl)
   int max_insns = INTEGRATE_THRESHOLD (fndecl);
   register int ninsns = 0;
   register tree parms;
+  rtx result;
 
   /* No inlines with varargs.  `grokdeclarator' gives a warning
      message about that if `inline' is specified.  This code
@@ -170,6 +199,24 @@ function_cannot_inline_p (fndecl)
   if (current_function_has_nonlocal_goto)
     return "function with nonlocal goto cannot be inline";
 
+  /* This is a hack, until the inliner is taught about eh regions at
+     the start of the function.  */
+  for (insn = get_insns ();
+       insn
+        && ! (GET_CODE (insn) == NOTE
+              && NOTE_LINE_NUMBER (insn) == NOTE_INSN_FUNCTION_BEG);
+       insn = NEXT_INSN (insn))
+    {
+      if (insn && GET_CODE (insn) == NOTE
+         && NOTE_LINE_NUMBER (insn) == NOTE_INSN_EH_REGION_BEG)
+       return "function with complex parameters cannot be inline";
+    }
+
+  /* We can't inline functions that return a PARALLEL rtx.  */
+  result = DECL_RTL (DECL_RESULT (fndecl));
+  if (result && GET_CODE (result) == PARALLEL)
+    return "inline functions not supported for this return value type";
+
   return 0;
 }
 \f
@@ -198,7 +245,8 @@ static rtx *insn_map;
 static tree *parmdecl_map;
 
 /* Keep track of first pseudo-register beyond those that are parms.  */
-static int max_parm_reg;
+extern int max_parm_reg;
+extern rtx *parm_reg_stack_loc;
 
 /* When an insn is being copied by copy_for_inline,
    this is nonzero if we have copied an ASM_OPERANDS.
@@ -255,6 +303,13 @@ initialize_for_inline (fndecl, min_labelno, max_labelno, max_reg, copy)
     {
       rtx p = DECL_RTL (parms);
 
+      /* If we have (mem (addressof (mem ...))), use the inner MEM since
+        otherwise the copy_rtx call below will not unshare the MEM since
+        it shares ADDRESSOF.  */
+      if (GET_CODE (p) == MEM && GET_CODE (XEXP (p, 0)) == ADDRESSOF
+         && GET_CODE (XEXP (XEXP (p, 0), 0)) == MEM)
+       p = XEXP (XEXP (p, 0), 0);
+
       if (GET_CODE (p) == MEM && copy)
        {
          /* Copy the rtl so that modifications of the addresses
@@ -309,11 +364,12 @@ initialize_for_inline (fndecl, min_labelno, max_labelno, max_reg, copy)
      the size of the incoming stack area for parameters,
      the number of bytes popped on return,
      the stack slot list,
+     the labels that are forced to exist,
      some flags that are used to restore compiler globals,
      the value of current_function_outgoing_args_size,
      the original argument vector,
      the original DECL_INITIAL,
-     and pointers to the table of psuedo regs, pointer flags, and alignment. */
+     and pointers to the table of pseudo regs, pointer flags, and alignment. */
 
   return gen_inline_header_rtx (NULL_RTX, NULL_RTX, min_labelno, max_labelno,
                                max_parm_reg, max_reg,
@@ -323,7 +379,8 @@ initialize_for_inline (fndecl, min_labelno, max_labelno, max_reg, copy)
                                current_function_outgoing_args_size,
                                arg_vector, (rtx) DECL_INITIAL (fndecl),
                                (rtvec) regno_reg_rtx, regno_pointer_flag,
-                               regno_pointer_align);
+                               regno_pointer_align,
+                               (rtvec) parm_reg_stack_loc);
 }
 
 /* Subroutine for `save_for_inline{copying,nocopy}'.  Finishes up the
@@ -335,7 +392,7 @@ finish_inline (fndecl, head)
      tree fndecl;
      rtx head;
 {
-  NEXT_INSN (head) = get_first_nonparm_insn ();
+  FIRST_FUNCTION_INSN (head) = get_first_nonparm_insn ();
   FIRST_PARM_INSN (head) = get_insns ();
   DECL_SAVED_INSNS (fndecl) = head;
   DECL_FRAME_SIZE (fndecl) = get_frame_size ();
@@ -392,9 +449,11 @@ save_for_inline_copying (fndecl)
   int max_uid;
   rtx first_nonparm_insn;
   char *new, *new1;
+  rtx *new_parm_reg_stack_loc;
+  rtx *new2;
 
   /* Make and emit a return-label if we have not already done so. 
-     Do this before recording the bounds on label numbers. */
+     Do this before recording the bounds on label numbers.  */
 
   if (return_label == 0)
     {
@@ -414,7 +473,6 @@ save_for_inline_copying (fndecl)
      for the parms, prior to elimination of virtual registers.
      These values are needed for substituting parms properly.  */
 
-  max_parm_reg = max_parm_reg_num ();
   parmdecl_map = (tree *) alloca (max_parm_reg * sizeof (tree));
 
   head = initialize_for_inline (fndecl, min_labelno, max_labelno, max_reg, 1);
@@ -474,7 +532,7 @@ save_for_inline_copying (fndecl)
      Make these new rtx's now, and install them in regno_reg_rtx, so they
      will be the official pseudo-reg rtx's for the rest of compilation.  */
 
-  reg_map = (rtx *) savealloc ((max_reg + 1) * sizeof (rtx));
+  reg_map = (rtx *) savealloc (regno_pointer_flag_length * sizeof (rtx));
 
   len = sizeof (struct rtx_def) + (GET_RTX_LENGTH (REG) - 1) * sizeof (rtunion);
   for (i = max_reg - 1; i > LAST_VIRTUAL_REGISTER; i--)
@@ -491,12 +549,21 @@ save_for_inline_copying (fndecl)
 
   /* Likewise each label rtx must have a unique rtx as its copy.  */
 
-  label_map = (rtx *)alloca ((max_labelno - min_labelno) * sizeof (rtx));
-  label_map -= min_labelno;
+  /* We used to use alloca here, but the size of what it would try to
+     allocate would occasionally cause it to exceed the stack limit and
+     cause unpredictable core dumps.  Some examples were > 2Mb in size.  */
+  label_map = (rtx *) xmalloc ((max_labelno) * sizeof (rtx));
 
   for (i = min_labelno; i < max_labelno; i++)
     label_map[i] = gen_label_rtx ();
 
+  /* Likewise for parm_reg_stack_slot.  */
+  new_parm_reg_stack_loc = (rtx *) savealloc (max_parm_reg * sizeof (rtx));
+  for (i = 0; i < max_parm_reg; i++)
+    new_parm_reg_stack_loc[i] = copy_for_inline (parm_reg_stack_loc[i]);
+
+  parm_reg_stack_loc = new_parm_reg_stack_loc;
+
   /* Record the mapping of old insns to copied insns.  */
 
   insn_map = (rtx *) alloca (max_uid * sizeof (rtx));
@@ -515,6 +582,16 @@ save_for_inline_copying (fndecl)
       XEXP (regno_reg_rtx[i], 0)
        = copy_for_inline (XEXP (regno_reg_rtx[i], 0));
 
+  /* Copy the parm_reg_stack_loc array, and substitute for all of the rtx
+     contained in it.  */
+  new2 = (rtx *) savealloc (max_parm_reg * sizeof (rtx));
+  bcopy ((char *) parm_reg_stack_loc, (char *) new2,
+        max_parm_reg * sizeof (rtx));
+  parm_reg_stack_loc = new2;
+  for (i = LAST_VIRTUAL_REGISTER + 1; i < max_parm_reg; ++i)
+    if (parm_reg_stack_loc[i])
+      parm_reg_stack_loc[i] = copy_for_inline (parm_reg_stack_loc[i]);
+
   /* Copy the tree of subblocks of the function, and the decls in them.
      We will use the copy for compiling this function, then restore the original
      subblocks and decls for use when inlining this function.
@@ -565,6 +642,15 @@ save_for_inline_copying (fndecl)
              NOTE_SOURCE_FILE (insn) = (char *) copy;
              NOTE_SOURCE_FILE (copy) = 0;
            }
+         if (NOTE_LINE_NUMBER (copy) == NOTE_INSN_EH_REGION_BEG
+             || NOTE_LINE_NUMBER (copy) == NOTE_INSN_EH_REGION_END)
+           {
+             /* We have to forward these both to match the new exception
+                region.  */
+             NOTE_BLOCK_NUMBER (copy)
+               = CODE_LABEL_NUMBER (label_map[NOTE_BLOCK_NUMBER (copy)]);
+             
+           }
          RTX_INTEGRATED_P (copy) = RTX_INTEGRATED_P (insn);
          break;
 
@@ -574,8 +660,8 @@ save_for_inline_copying (fndecl)
          copy = rtx_alloc (GET_CODE (insn));
 
          if (GET_CODE (insn) == CALL_INSN)
-           CALL_INSN_FUNCTION_USAGE (copy) =
-                  copy_for_inline (CALL_INSN_FUNCTION_USAGE (insn));
+           CALL_INSN_FUNCTION_USAGE (copy)
+             = copy_for_inline (CALL_INSN_FUNCTION_USAGE (insn));
 
          PATTERN (copy) = copy_for_inline (PATTERN (insn));
          INSN_CODE (copy) = -1;
@@ -625,6 +711,9 @@ save_for_inline_copying (fndecl)
   regno_pointer_align = new1;
 
   set_new_first_and_last_insn (first_insn, last_insn);
+
+  if (label_map)
+    free (label_map);
 }
 
 /* Return a copy of a chain of nodes, chained through the TREE_CHAIN field.
@@ -741,7 +830,6 @@ save_for_inline_nocopy (fndecl)
      for the parms, prior to elimination of virtual registers.
      These values are needed for substituting parms properly.  */
 
-  max_parm_reg = max_parm_reg_num ();
   parmdecl_map = (tree *) alloca (max_parm_reg * sizeof (tree));
 
   /* Make and emit a return-label if we have not already done so.  */
@@ -812,8 +900,8 @@ save_for_inline_nocopy (fndecl)
    pool.  Replace each with a CONST that has the mode of the original
    constant, contains the constant, and has RTX_INTEGRATED_P set.
    Similarly, constant pool addresses not enclosed in a MEM are replaced
-   with an ADDRESS rtx which also gives the constant, mode, and has
-   RTX_INTEGRATED_P set.  */
+   with an ADDRESS and CONST rtx which also gives the constant, its
+   mode, the mode of the address, and has RTX_INTEGRATED_P set.  */
 
 static void
 save_constants (px)
@@ -833,7 +921,7 @@ save_constants (px)
           && CONSTANT_POOL_ADDRESS_P (XEXP (x,0)))
     {
       enum machine_mode const_mode = get_pool_mode (XEXP (x, 0));
-      rtx new = gen_rtx (CONST, const_mode, get_pool_constant (XEXP (x, 0)));
+      rtx new = gen_rtx_CONST (const_mode, get_pool_constant (XEXP (x, 0)));
       RTX_INTEGRATED_P (new) = 1;
 
       /* If the MEM was in a different mode than the constant (perhaps we
@@ -842,7 +930,7 @@ save_constants (px)
 
       if (GET_MODE (x) != const_mode)
        {
-         new = gen_rtx (SUBREG, GET_MODE (x), new, 0);
+         new = gen_rtx_SUBREG (GET_MODE (x), new, 0);
          RTX_INTEGRATED_P (new) = 1;
        }
 
@@ -852,7 +940,9 @@ save_constants (px)
   else if (GET_CODE (x) == SYMBOL_REF
           && CONSTANT_POOL_ADDRESS_P (x))
     {
-      *px = gen_rtx (ADDRESS, get_pool_mode (x), get_pool_constant (x));
+      *px = gen_rtx_ADDRESS (GET_MODE (x),
+                            gen_rtx_CONST (get_pool_mode (x),
+                                           get_pool_constant (x)));
       save_constants (&XEXP (*px, 0));
       RTX_INTEGRATED_P (*px) = 1;
     }
@@ -919,6 +1009,7 @@ copy_for_inline (orig)
      rtx orig;
 {
   register rtx x = orig;
+  register rtx new;
   register int i;
   register enum rtx_code code;
   register char *format_ptr;
@@ -964,9 +1055,8 @@ copy_for_inline (orig)
       /* Get constant pool entry, but access in different mode.  */
       if (RTX_INTEGRATED_P (x))
        {
-         rtx new
-           = force_const_mem (GET_MODE (SUBREG_REG (x)),
-                              copy_for_inline (XEXP (SUBREG_REG (x), 0)));
+         new = force_const_mem (GET_MODE (SUBREG_REG (x)),
+                                copy_for_inline (XEXP (SUBREG_REG (x), 0)));
 
          PUT_MODE (new, GET_MODE (x));
          return validize_mem (new);
@@ -979,8 +1069,16 @@ copy_for_inline (orig)
       if (! RTX_INTEGRATED_P (x))
        abort ();
 
-      return XEXP (force_const_mem (GET_MODE (x),
-                                   copy_for_inline (XEXP (x, 0))), 0);
+      new = force_const_mem (GET_MODE (XEXP (x, 0)),
+                            copy_for_inline (XEXP (XEXP (x, 0), 0)));
+      new = XEXP (new, 0);
+
+#ifdef POINTERS_EXTEND_UNSIGNED
+      if (GET_MODE (new) != GET_MODE (x))
+       new = convert_memory_address (GET_MODE (x), new);
+#endif
+
+      return new;
 
     case ASM_OPERANDS:
       /* If a single asm insn contains multiple output operands
@@ -1038,9 +1136,9 @@ copy_for_inline (orig)
     case LABEL_REF:
       /* If this is a non-local label, just make a new LABEL_REF.
         Otherwise, use the new label as well.  */
-      x = gen_rtx (LABEL_REF, GET_MODE (orig),
-                  LABEL_REF_NONLOCAL_P (orig) ? XEXP (orig, 0)
-                  : label_map[CODE_LABEL_NUMBER (XEXP (orig, 0))]);
+      x = gen_rtx_LABEL_REF (GET_MODE (orig),
+                            LABEL_REF_NONLOCAL_P (orig) ? XEXP (orig, 0)
+                            : label_map[CODE_LABEL_NUMBER (XEXP (orig, 0))]);
       LABEL_REF_NONLOCAL_P (x) = LABEL_REF_NONLOCAL_P (orig);
       LABEL_OUTSIDE_LOOP_P (x) = LABEL_OUTSIDE_LOOP_P (orig);
       return x;
@@ -1089,6 +1187,8 @@ copy_for_inline (orig)
        }
       break;
 #endif
+    default:
+      break;
     }
 
   /* Replace this rtx with a copy of itself.  */
@@ -1124,7 +1224,7 @@ copy_for_inline (orig)
            {
              register int j;
 
-             XVEC (x, i) = gen_rtvec_v (XVECLEN (x, i), &XVECEXP (x, i, 0));
+             XVEC (x, i) = gen_rtvec_vv (XVECLEN (x, i), XVEC (x, i)->elem);
              for (j = 0; j < XVECLEN (x, i); j++)
                XVECEXP (x, i, j)
                  = copy_for_inline (XVECEXP (x, i, j));
@@ -1199,6 +1299,10 @@ expand_inline_function (fndecl, parms, target, ignore, type,
   rtvec arg_vector = ORIGINAL_ARG_VECTOR (header);
   rtx static_chain_value = 0;
 
+  /* The pointer used to track the true location of the memory used
+     for MAP->LABEL_MAP.  */
+  rtx *real_label_map = 0;
+
   /* Allow for equivalences of the pseudos we make for virtual fp and ap.  */
   max_regno = MAX_REGNUM (header) + 3;
   if (max_regno < FIRST_PSEUDO_REGISTER)
@@ -1227,7 +1331,9 @@ expand_inline_function (fndecl, parms, target, ignore, type,
          /* If they are block mode, the types should match exactly.
             They don't match exactly if TREE_TYPE (FORMAL) == ERROR_MARK_NODE,
             which could happen if the parameter has incomplete type.  */
-         || (mode == BLKmode && TREE_TYPE (arg) != TREE_TYPE (formal)))
+         || (mode == BLKmode
+             && (TYPE_MAIN_VARIANT (TREE_TYPE (arg))
+                 != TYPE_MAIN_VARIANT (TREE_TYPE (formal)))))
        return (rtx) (HOST_WIDE_INT) -1;
     }
 
@@ -1242,10 +1348,6 @@ expand_inline_function (fndecl, parms, target, ignore, type,
      parameter declarations.  */
   pushlevel (0);
 
-  /* Make a fresh binding contour that we can easily remove.  */
-  pushlevel (0);
-  expand_start_bindings (0);
-
   /* Expand the function arguments.  Do this first so that any
      new registers get created before we allocate the maps.  */
 
@@ -1337,8 +1439,12 @@ expand_inline_function (fndecl, parms, target, ignore, type,
   map->reg_map = (rtx *) alloca (max_regno * sizeof (rtx));
   bzero ((char *) map->reg_map, max_regno * sizeof (rtx));
 
-  map->label_map = (rtx *)alloca ((max_labelno - min_labelno) * sizeof (rtx));
-  map->label_map -= min_labelno;
+  /* We used to use alloca here, but the size of what it would try to
+     allocate would occasionally cause it to exceed the stack limit and
+     cause unpredictable core dumps.  */
+  real_label_map
+    = (rtx *) xmalloc ((max_labelno) * sizeof (rtx));
+  map->label_map = real_label_map;
 
   map->insn_map = (rtx *) alloca (INSN_UID (header) * sizeof (rtx));
   bzero ((char *) map->insn_map, INSN_UID (header) * sizeof (rtx));
@@ -1374,8 +1480,11 @@ expand_inline_function (fndecl, parms, target, ignore, type,
   map->const_age = 0;
 
   /* Record the current insn in case we have to set up pointers to frame
-     and argument memory blocks.  */
+     and argument memory blocks.  If there are no insns yet, add a dummy
+     insn that can be used as an insertion point.  */
   map->insns_at_start = get_last_insn ();
+  if (map->insns_at_start == 0)
+    map->insns_at_start = emit_note (NULL_PTR, NOTE_INSN_DELETED);
 
   map->regno_pointer_flag = INLINE_REGNO_POINTER_FLAG (header);
   map->regno_pointer_align = INLINE_REGNO_POINTER_ALIGN (header);
@@ -1464,7 +1573,7 @@ expand_inline_function (fndecl, parms, target, ignore, type,
             that flag set if it is a register.
 
             Also, don't allow hard registers here; they might not be valid
-            when substituted into insns. */
+            when substituted into insns.  */
 
          if ((GET_CODE (copy) != REG && GET_CODE (copy) != SUBREG)
              || (GET_CODE (copy) == REG && REG_USERVAR_P (loc)
@@ -1495,7 +1604,7 @@ expand_inline_function (fndecl, parms, target, ignore, type,
             that flag set if it is a register.
 
             Also, don't allow hard registers here; they might not be valid
-            when substituted into insns. */
+            when substituted into insns.  */
          rtx locreal = gen_realpart (GET_MODE (XEXP (loc, 0)), loc);
          rtx locimag = gen_imagpart (GET_MODE (XEXP (loc, 0)), loc);
          rtx copyreal = gen_realpart (GET_MODE (locreal), copy);
@@ -1597,9 +1706,11 @@ expand_inline_function (fndecl, parms, target, ignore, type,
 
       if (GET_CODE (XEXP (loc, 0)) == REG)
        {
-         temp = force_reg (Pmode, structure_value_addr);
+         temp = force_reg (Pmode,
+                           force_operand (structure_value_addr, NULL_RTX));
          map->reg_map[REGNO (XEXP (loc, 0))] = temp;
          if ((CONSTANT_P (structure_value_addr)
+              || GET_CODE (structure_value_addr) == ADDRESSOF
               || (GET_CODE (structure_value_addr) == PLUS
                   && XEXP (structure_value_addr, 0) == virtual_stack_vars_rtx
                   && GET_CODE (XEXP (structure_value_addr, 1)) == CONST_INT))
@@ -1630,9 +1741,11 @@ expand_inline_function (fndecl, parms, target, ignore, type,
       /* Machine mode function was declared to return.   */
       enum machine_mode departing_mode = TYPE_MODE (type);
       /* (Possibly wider) machine mode it actually computes
-        (for the sake of callers that fail to declare it right).  */
+        (for the sake of callers that fail to declare it right).
+        We have to use the mode of the result's RTL, rather than
+        its type, since expand_function_start may have promoted it.  */
       enum machine_mode arriving_mode
-       = TYPE_MODE (TREE_TYPE (DECL_RESULT (fndecl)));
+       = GET_MODE (DECL_RTL (DECL_RESULT (fndecl)));
       rtx reg_to_map;
 
       /* Don't use MEMs as direct targets because on some machines
@@ -1646,7 +1759,21 @@ expand_inline_function (fndecl, parms, target, ignore, type,
         avoid machine mode mismatch when we substitute INLINE_TARGET.
         But TARGET is what we will return to the caller.  */
       if (arriving_mode != departing_mode)
-       reg_to_map = gen_rtx (SUBREG, arriving_mode, target, 0);
+       {
+         /* Avoid creating a paradoxical subreg wider than
+            BITS_PER_WORD, since that is illegal.  */
+         if (GET_MODE_BITSIZE (arriving_mode) > BITS_PER_WORD)
+           {
+             if (!TRULY_NOOP_TRUNCATION (GET_MODE_BITSIZE (departing_mode),
+                                         GET_MODE_BITSIZE (arriving_mode)))
+               /* Maybe could be handled by using convert_move () ?  */
+               abort ();
+             reg_to_map = gen_reg_rtx (arriving_mode);
+             target = gen_lowpart (departing_mode, reg_to_map);
+           }
+         else
+           reg_to_map = gen_rtx_SUBREG (arriving_mode, target, 0);
+       }
       else
        reg_to_map = target;
 
@@ -1657,10 +1784,17 @@ expand_inline_function (fndecl, parms, target, ignore, type,
       else
        map->reg_map[REGNO (loc)] = reg_to_map;
     }
+  else
+    abort ();
+
+  /* Make a fresh binding contour that we can easily remove.  Do this after
+     expanding our arguments so cleanups are properly scoped.  */
+  pushlevel (0);
+  expand_start_bindings (0);
 
   /* Make new label equivalences for the labels in the called function.  */
   for (i = min_labelno; i < max_labelno; i++)
-    map->label_map[i] = gen_label_rtx ();
+    map->label_map[i] = NULL_RTX;
 
   /* Perform postincrements before actually calling the function.  */
   emit_queue ();
@@ -1705,6 +1839,12 @@ expand_inline_function (fndecl, parms, target, ignore, type,
               inline_target.  */
            break;
 
+         /* If the inline fn needs eh context, make sure that
+            the current fn has one. */
+         if (GET_CODE (pattern) == USE
+             && find_reg_note (insn, REG_EH_CONTEXT, 0) != 0)
+           get_eh_context ();
+
          /* Ignore setting a function value that we don't want to use.  */
          if (map->inline_target == 0
              && set != 0
@@ -1788,7 +1928,9 @@ expand_inline_function (fndecl, parms, target, ignore, type,
          break;
 
        case JUMP_INSN:
-         if (GET_CODE (PATTERN (insn)) == RETURN)
+         if (GET_CODE (PATTERN (insn)) == RETURN
+             || (GET_CODE (PATTERN (insn)) == PARALLEL
+                 && GET_CODE (XVECEXP (PATTERN (insn), 0, 0)) == RETURN))
            {
              if (local_return_label == 0)
                local_return_label = gen_label_rtx ();
@@ -1835,8 +1977,8 @@ expand_inline_function (fndecl, parms, target, ignore, type,
 
          /* 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);
+         CALL_INSN_FUNCTION_USAGE (copy)
+           = copy_rtx_and_substitute (CALL_INSN_FUNCTION_USAGE (insn), map);
 
 #ifdef HAVE_cc0
          if (cc0_insn)
@@ -1851,7 +1993,9 @@ expand_inline_function (fndecl, parms, target, ignore, type,
          break;
 
        case CODE_LABEL:
-         copy = emit_label (map->label_map[CODE_LABEL_NUMBER (insn)]);
+         copy = 
+           emit_label (get_label_from_map(map,
+                                          CODE_LABEL_NUMBER (insn)));
          LABEL_NAME (copy) = LABEL_NAME (insn);
          map->const_age++;
          break;
@@ -1869,7 +2013,19 @@ expand_inline_function (fndecl, parms, target, ignore, type,
          if (NOTE_LINE_NUMBER (insn) != NOTE_INSN_FUNCTION_END
              && NOTE_LINE_NUMBER (insn) != NOTE_INSN_FUNCTION_BEG
              && NOTE_LINE_NUMBER (insn) != NOTE_INSN_DELETED)
-           copy = emit_note (NOTE_SOURCE_FILE (insn), NOTE_LINE_NUMBER (insn));
+           {
+             copy = emit_note (NOTE_SOURCE_FILE (insn), NOTE_LINE_NUMBER (insn));
+             if (copy && (NOTE_LINE_NUMBER (copy) == NOTE_INSN_EH_REGION_BEG
+                          || NOTE_LINE_NUMBER (copy) == NOTE_INSN_EH_REGION_END))
+               {
+                 rtx label =
+                   get_label_from_map (map, NOTE_BLOCK_NUMBER (copy));
+
+                 /* We have to forward these both to match the new exception
+                    region.  */
+                 NOTE_BLOCK_NUMBER (copy) = CODE_LABEL_NUMBER (label);
+               }
+           }
          else
            copy = 0;
          break;
@@ -1927,14 +2083,30 @@ expand_inline_function (fndecl, parms, target, ignore, type,
   BLOCK_ABSTRACT_ORIGIN (block) = (DECL_ABSTRACT_ORIGIN (fndecl) == NULL
                                   ? fndecl : DECL_ABSTRACT_ORIGIN (fndecl));
   poplevel (0, 0, 0);
+
+  /* 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 (structure_value_addr)
     {
-      target = gen_rtx (MEM, TYPE_MODE (type),
-                       memory_address (TYPE_MODE (type), structure_value_addr));
+      target = gen_rtx_MEM (TYPE_MODE (type),
+                           memory_address (TYPE_MODE (type),
+                                           structure_value_addr));
       MEM_IN_STRUCT_P (target) = 1;
     }
+
+  /* Make sure we free the things we explicitly allocated with xmalloc.  */
+  if (real_label_map)
+    free (real_label_map);
+
   return target;
 }
 \f
@@ -2114,18 +2286,22 @@ copy_rtx_and_substitute (orig, map)
            {
              rtx loc, seq;
              int size = DECL_FRAME_SIZE (map->fndecl);
-             int rounded;
 
+#ifdef FRAME_GROWS_DOWNWARD
+             /* 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);
+#endif
              start_sequence ();
              loc = assign_stack_temp (BLKmode, size, 1);
              loc = XEXP (loc, 0);
 #ifdef FRAME_GROWS_DOWNWARD
              /* In this case, virtual_stack_vars_rtx points to one byte
                 higher than the top of the frame area.  So compute the offset
-                to one byte higher than our substitute frame.
-                Keep the fake frame pointer aligned like a real one.  */
-             rounded = CEIL_ROUND (size, BIGGEST_ALIGNMENT / BITS_PER_UNIT);
-             loc = plus_constant (loc, rounded);
+                to one byte higher than our substitute frame.  */
+             loc = plus_constant (loc, size);
 #endif
              map->reg_map[regno] = temp
                = force_reg (Pmode, force_operand (loc, NULL_RTX));
@@ -2149,7 +2325,7 @@ copy_rtx_and_substitute (orig, map)
          else if (regno == VIRTUAL_INCOMING_ARGS_REGNUM)
            {
              /* Do the same for a block to contain any arguments referenced
-                in memory. */
+                in memory.  */
              rtx loc, seq;
              int size = FUNCTION_ARGS_SIZE (DECL_SAVED_INSNS (map->fndecl));
 
@@ -2158,7 +2334,7 @@ copy_rtx_and_substitute (orig, map)
              loc = XEXP (loc, 0);
              /* When arguments grow downward, the virtual incoming 
                 args pointer points to the top of the argument block,
-                so the remapped location better do the same. */
+                so the remapped location better do the same.  */
 #ifdef ARGS_GROW_DOWNWARD
              loc = plus_constant (loc, size);
 #endif
@@ -2215,13 +2391,37 @@ copy_rtx_and_substitute (orig, map)
       copy = copy_rtx_and_substitute (SUBREG_REG (orig), map);
       /* SUBREG is ordinary, but don't make nested SUBREGs.  */
       if (GET_CODE (copy) == SUBREG)
-       return gen_rtx (SUBREG, GET_MODE (orig), SUBREG_REG (copy),
-                       SUBREG_WORD (orig) + SUBREG_WORD (copy));
+       return gen_rtx_SUBREG (GET_MODE (orig), SUBREG_REG (copy),
+                              SUBREG_WORD (orig) + SUBREG_WORD (copy));
       else if (GET_CODE (copy) == CONCAT)
        return (subreg_realpart_p (orig) ? XEXP (copy, 0) : XEXP (copy, 1));
       else
-       return gen_rtx (SUBREG, GET_MODE (orig), copy,
-                       SUBREG_WORD (orig));
+       return gen_rtx_SUBREG (GET_MODE (orig), copy,
+                              SUBREG_WORD (orig));
+
+    case ADDRESSOF:
+      copy = gen_rtx_ADDRESSOF (mode,
+                       copy_rtx_and_substitute (XEXP (orig, 0), map), 0);
+      SET_ADDRESSOF_DECL (copy, ADDRESSOF_DECL (orig));
+      regno = ADDRESSOF_REGNO (orig);
+      if (map->reg_map[regno])
+       regno = REGNO (map->reg_map[regno]);
+      else if (regno > LAST_VIRTUAL_REGISTER)
+       {
+         temp = XEXP (orig, 0);
+         map->reg_map[regno] = gen_reg_rtx (GET_MODE (temp));
+         REG_USERVAR_P (map->reg_map[regno]) = REG_USERVAR_P (temp);
+         REG_LOOP_TEST_P (map->reg_map[regno]) = REG_LOOP_TEST_P (temp);
+         RTX_UNCHANGING_P (map->reg_map[regno]) = RTX_UNCHANGING_P (temp);
+         /* A reg with REG_FUNCTION_VALUE_P true will never reach here.  */
+
+         if (map->regno_pointer_flag[regno])
+           mark_reg_pointer (map->reg_map[regno],
+                             map->regno_pointer_align[regno]);
+         regno = REGNO (map->reg_map[regno]);
+       }
+      ADDRESSOF_REGNO (copy) = regno;
+      return copy;
 
     case USE:
     case CLOBBER:
@@ -2232,17 +2432,18 @@ copy_rtx_and_substitute (orig, map)
       copy = copy_rtx_and_substitute (XEXP (orig, 0), map);
       if (GET_CODE (copy) == SUBREG && GET_CODE (XEXP (orig, 0)) != SUBREG)
        copy = SUBREG_REG (copy);
-      return gen_rtx (code, VOIDmode, copy);
+      return gen_rtx_fmt_e (code, VOIDmode, copy);
 
     case CODE_LABEL:
-      LABEL_PRESERVE_P (map->label_map[CODE_LABEL_NUMBER (orig)])
+      LABEL_PRESERVE_P (get_label_from_map (map, CODE_LABEL_NUMBER (orig)))
        = LABEL_PRESERVE_P (orig);
-      return map->label_map[CODE_LABEL_NUMBER (orig)];
+      return get_label_from_map (map, CODE_LABEL_NUMBER (orig));
 
     case LABEL_REF:
-      copy = gen_rtx (LABEL_REF, mode,
-                     LABEL_REF_NONLOCAL_P (orig) ? XEXP (orig, 0)
-                     : map->label_map[CODE_LABEL_NUMBER (XEXP (orig, 0))]);
+      copy = gen_rtx_LABEL_REF (mode,
+                               LABEL_REF_NONLOCAL_P (orig) ? XEXP (orig, 0)
+                               : get_label_from_map (map, 
+                                                     CODE_LABEL_NUMBER (XEXP (orig, 0))));
       LABEL_OUTSIDE_LOOP_P (copy) = LABEL_OUTSIDE_LOOP_P (orig);
 
       /* The fact that this label was previously nonlocal does not mean
@@ -2275,7 +2476,7 @@ copy_rtx_and_substitute (orig, map)
        {
          rtx constant = get_pool_constant (orig);
          if (GET_CODE (constant) == LABEL_REF)
-           return XEXP (force_const_mem (Pmode, 
+           return XEXP (force_const_mem (GET_MODE (orig),
                                          copy_rtx_and_substitute (constant,
                                                                   map)),
                         0);
@@ -2322,8 +2523,10 @@ copy_rtx_and_substitute (orig, map)
       if (! RTX_INTEGRATED_P (orig))
        abort ();
 
-      temp = force_const_mem (GET_MODE (orig),
-                             copy_rtx_and_substitute (XEXP (orig, 0), map));
+      temp
+       = force_const_mem (GET_MODE (XEXP (orig, 0)),
+                          copy_rtx_and_substitute (XEXP (XEXP (orig, 0), 0),
+                                                   map));
 
 #if 0
       /* Legitimizing the address here is incorrect.
@@ -2342,13 +2545,20 @@ copy_rtx_and_substitute (orig, map)
         will not have valid reg_map entries.  This can cause try_constants()
         to fail because assumes that all registers in the rtx have valid
         reg_map entries, and it may end up replacing one of these new
-        registers with junk. */
+        registers with junk.  */
 
       if (! memory_address_p (GET_MODE (temp), XEXP (temp, 0)))
        temp = change_address (temp, GET_MODE (temp), XEXP (temp, 0));
 #endif
 
-      return XEXP (temp, 0);
+      temp = XEXP (temp, 0);
+
+#ifdef POINTERS_EXTEND_UNSIGNED
+      if (GET_MODE (temp) != GET_MODE (orig))
+       temp = convert_memory_address (GET_MODE (orig), temp);
+#endif
+
+      return temp;
 
     case ASM_OPERANDS:
       /* If a single asm insn contains multiple output operands
@@ -2377,9 +2587,9 @@ copy_rtx_and_substitute (orig, map)
 #ifndef NO_FUNCTION_CSE
       if (! (optimize && ! flag_no_function_cse))
 #endif
-       return gen_rtx (CALL, GET_MODE (orig),
-                       gen_rtx (MEM, GET_MODE (XEXP (orig, 0)),
-                                copy_rtx_and_substitute (XEXP (XEXP (orig, 0), 0), map)),
+       return gen_rtx_CALL (GET_MODE (orig),
+                            gen_rtx_MEM (GET_MODE (XEXP (orig, 0)),
+                                         copy_rtx_and_substitute (XEXP (XEXP (orig, 0), 0), map)),
                        copy_rtx_and_substitute (XEXP (orig, 1), map));
       break;
 
@@ -2391,13 +2601,26 @@ copy_rtx_and_substitute (orig, map)
 
     case SET:
       /* If this is setting fp or ap, it means that we have a nonlocal goto.
-        Don't alter that.
+        Adjust the setting by the offset of the area we made.
         If the nonlocal goto is into the current function,
         this will result in unnecessarily bad code, but should work.  */
       if (SET_DEST (orig) == virtual_stack_vars_rtx
          || SET_DEST (orig) == virtual_incoming_args_rtx)
-       return gen_rtx (SET, VOIDmode, SET_DEST (orig),
-                       copy_rtx_and_substitute (SET_SRC (orig), map));
+       {
+         /* In case a translation hasn't occurred already, make one now. */
+         rtx junk = copy_rtx_and_substitute (SET_DEST (orig), map);
+         rtx equiv_reg = map->reg_map[REGNO (SET_DEST (orig))];
+         rtx equiv_loc = map->const_equiv_map[REGNO (equiv_reg)];
+         HOST_WIDE_INT loc_offset
+           = GET_CODE (equiv_loc) == REG ? 0 : INTVAL (XEXP (equiv_loc, 1));
+             
+         return gen_rtx_SET (VOIDmode, SET_DEST (orig),
+                             force_operand
+                             (plus_constant
+                              (copy_rtx_and_substitute (SET_SRC (orig), map),
+                               - loc_offset),
+                              NULL_RTX));
+       }
       break;
 
     case MEM:
@@ -2416,6 +2639,9 @@ copy_rtx_and_substitute (orig, map)
        RTX_UNCHANGING_P (copy) = RTX_UNCHANGING_P (orig);
 
       return copy;
+      
+    default:
+      break;
     }
 
   copy = rtx_alloc (code);
@@ -2431,6 +2657,7 @@ copy_rtx_and_substitute (orig, map)
       switch (*format_ptr++)
        {
        case '0':
+         XEXP (copy, i) = XEXP (orig, i);
          break;
 
        case 'e':
@@ -2622,6 +2849,7 @@ subst_constants (loc, insn, map)
            new = operand_subword (inner, SUBREG_WORD (x), 0,
                                   GET_MODE (SUBREG_REG (x)));
 
+         cancel_changes (num_changes);
          if (new == 0 && subreg_lowpart_p (x))
            new = gen_lowpart_common (GET_MODE (x), inner);
 
@@ -2707,9 +2935,11 @@ subst_constants (loc, insn, map)
            map->equiv_sets[map->num_sets].equiv = copy_rtx (src);
            map->equiv_sets[map->num_sets++].dest = dest;
          }
-
-       return;
       }
+      return;
+
+    default:
+      break;
     }
 
   format_ptr = GET_RTX_FORMAT (code);
@@ -2829,9 +3059,13 @@ mark_stores (dest, x)
                      : regno + HARD_REGNO_NREGS (regno, mode) - 1);
       int i;
 
-      for (i = regno; i <= last_reg; i++)
-       if (i < global_const_equiv_map_size)
-         global_const_equiv_map[i] = 0;
+      /* 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 (i < global_const_equiv_map_size)
+           global_const_equiv_map[i] = 0;
     }
 }
 \f
@@ -2886,8 +3120,16 @@ restore_constants (px)
     }
   else if (RTX_INTEGRATED_P (x) && GET_CODE (x) == ADDRESS)
     {
-      restore_constants (&XEXP (x, 0));
-      *px = XEXP (force_const_mem (GET_MODE (x), XEXP (x, 0)), 0);
+      rtx new = XEXP (force_const_mem (GET_MODE (XEXP (x, 0)),
+                                      XEXP (XEXP (x, 0), 0)),
+                     0);
+
+#ifdef POINTERS_EXTEND_UNSIGNED
+      if (GET_MODE (new) != GET_MODE (x))
+       new = convert_memory_address (GET_MODE (x), new);
+#endif
+
+      *px = new;
     }
   else
     {
@@ -3038,13 +3280,6 @@ output_inline_function (fndecl)
 {
   rtx head;
   rtx last;
-  int save_flag_no_inline = flag_no_inline;
-
-  if (output_bytecode)
-    {
-      warning ("`inline' ignored for bytecode output");
-      return;
-    }
 
   /* Things we allocate from here on are part of this function, not
      permanent.  */
@@ -3069,6 +3304,8 @@ output_inline_function (fndecl)
   regno_reg_rtx = (rtx *) INLINE_REGNO_REG_RTX (head);
   regno_pointer_flag = INLINE_REGNO_POINTER_FLAG (head);
   regno_pointer_align = INLINE_REGNO_POINTER_ALIGN (head);
+  max_parm_reg = MAX_PARMREG (head);
+  parm_reg_stack_loc = (rtx *) PARMREG_STACK_LOC (head);
   
   stack_slot_list = STACK_SLOT_LIST (head);
   forced_labels = FORCED_LABELS (head);
@@ -3138,15 +3375,11 @@ output_inline_function (fndecl)
   /* We're not deferring this any longer.  */
   DECL_DEFER_OUTPUT (fndecl) = 0;
 
-  /* Integrating function calls isn't safe anymore, so turn on
-     flag_no_inline.  */
-  flag_no_inline = 1;
+  /* We can't inline this anymore.  */
+  DECL_INLINE (fndecl) = 0;
 
   /* Compile this function all the way down to assembly code.  */
   rest_of_compilation (fndecl);
 
-  /* Reset flag_no_inline to its original value.  */
-  flag_no_inline = save_flag_no_inline;
-
   current_function_decl = 0;
 }