OSDN Git Service

Word wrap comment
[pf3gnuchains/gcc-fork.git] / gcc / emit-rtl.c
index 1918a43..e697d55 100644 (file)
@@ -1,5 +1,6 @@
 /* Emit RTL for the GNU C-Compiler expander.
-   Copyright (C) 1987, 88, 92-97, 1998, 1999 Free Software Foundation, Inc.
+   Copyright (C) 1987, 1988, 1992, 1993, 1994, 1995, 1996, 1997, 1998,
+   1999, 2000 Free Software Foundation, Inc.
 
 This file is part of GNU CC.
 
@@ -45,11 +46,13 @@ Boston, MA 02111-1307, USA.  */
 #include "expr.h"
 #include "regs.h"
 #include "hard-reg-set.h"
+#include "hashtab.h"
 #include "insn-config.h"
 #include "recog.h"
 #include "real.h"
 #include "obstack.h"
 #include "bitmap.h"
+#include "basic-block.h"
 #include "ggc.h"
 
 /* Commonly used modes.  */
@@ -135,6 +138,11 @@ rtx return_address_pointer_rtx;    /* (REG:Pmode RETURN_ADDRESS_POINTER_REGNUM) */
 
 rtx const_int_rtx[MAX_SAVED_CONST_INT * 2 + 1];
 
+/* A hash table storing CONST_INTs whose absolute value is greater
+   than MAX_SAVED_CONST_INT.  */
+
+static htab_t const_int_htab;
+
 /* start_sequence and gen_sequence can make a lot of rtx expressions which are
    shortly thrown away.  We use two mechanisms to prevent this waste:
 
@@ -155,30 +163,82 @@ static rtx sequence_result[SEQUENCE_RESULT_SIZE];
 /* During RTL generation, we also keep a list of free INSN rtl codes.  */
 static rtx free_insn;
 
-#define first_insn (current_function->emit->x_first_insn)
-#define last_insn (current_function->emit->x_last_insn)
-#define cur_insn_uid (current_function->emit->x_cur_insn_uid)
-#define last_linenum (current_function->emit->x_last_linenum)
-#define last_filename (current_function->emit->x_last_filename)
-#define first_label_num (current_function->emit->x_first_label_num)
+#define first_insn (cfun->emit->x_first_insn)
+#define last_insn (cfun->emit->x_last_insn)
+#define cur_insn_uid (cfun->emit->x_cur_insn_uid)
+#define last_linenum (cfun->emit->x_last_linenum)
+#define last_filename (cfun->emit->x_last_filename)
+#define first_label_num (cfun->emit->x_first_label_num)
 
 /* This is where the pointer to the obstack being used for RTL is stored.  */
 extern struct obstack *rtl_obstack;
 
-static rtx make_jump_insn_raw          PROTO((rtx));
-static rtx make_call_insn_raw          PROTO((rtx));
-static rtx find_line_note              PROTO((rtx));
-static void mark_sequence_stack         PROTO((struct sequence_stack *));
+static rtx make_jump_insn_raw          PARAMS ((rtx));
+static rtx make_call_insn_raw          PARAMS ((rtx));
+static rtx find_line_note              PARAMS ((rtx));
+static void mark_sequence_stack         PARAMS ((struct sequence_stack *));
+static void unshare_all_rtl_1          PARAMS ((rtx));
+static hashval_t const_int_htab_hash    PARAMS ((const void *));
+static int const_int_htab_eq            PARAMS ((const void *,
+                                                const void *));
+static int rtx_htab_mark_1              PARAMS ((void **, void *));
+static void rtx_htab_mark               PARAMS ((void *));
+
 \f
+/* Returns a hash code for X (which is a really a CONST_INT).  */
+
+static hashval_t
+const_int_htab_hash (x)
+     const void *x;
+{
+  return (hashval_t) INTVAL ((const struct rtx_def *) x);
+}
+
+/* Returns non-zero if the value represented by X (which is really a
+   CONST_INT) is the same as that given by Y (which is really a
+   HOST_WIDE_INT *).  */
+
+static int
+const_int_htab_eq (x, y)
+     const void *x;
+     const void *y;
+{
+  return (INTVAL ((const struct rtx_def *) x) == *((const HOST_WIDE_INT *) y));
+}
+
+/* Mark the hash-table element X (which is really a pointer to an
+   rtx).  */
+
+static int
+rtx_htab_mark_1 (x, data)
+     void **x;
+     void *data ATTRIBUTE_UNUSED;
+{
+  ggc_mark_rtx (*x);
+  return 1;
+}
+
+/* Mark all the elements of HTAB (which is really an htab_t full of
+   rtxs).  */
+
+static void
+rtx_htab_mark (htab)
+     void *htab;
+{
+  htab_traverse (*((htab_t *) htab), rtx_htab_mark_1, NULL);
+}
+
 /* There are some RTL codes that require special attention; the generation
    functions do the raw handling.  If you add to this list, modify
    special_rtx in gengenrtl.c as well.  */
 
 rtx
 gen_rtx_CONST_INT (mode, arg)
-     enum machine_mode mode;
+     enum machine_mode mode ATTRIBUTE_UNUSED;
      HOST_WIDE_INT arg;
 {
+  void **slot;
+
   if (arg >= - MAX_SAVED_CONST_INT && arg <= MAX_SAVED_CONST_INT)
     return const_int_rtx[arg + MAX_SAVED_CONST_INT];
 
@@ -187,11 +247,27 @@ gen_rtx_CONST_INT (mode, arg)
     return const_true_rtx;
 #endif
 
-  return gen_rtx_raw_CONST_INT (mode, arg);
+  /* Look up the CONST_INT in the hash table.  */
+  slot = htab_find_slot_with_hash (const_int_htab, &arg, (hashval_t) arg, 1);
+  if (*slot == 0)
+    {
+      if (!ggc_p)
+       {
+         push_obstacks_nochange ();
+         end_temporary_allocation ();
+         *slot = gen_rtx_raw_CONST_INT (VOIDmode, arg);
+         pop_obstacks ();
+       }
+      else
+       *slot = gen_rtx_raw_CONST_INT (VOIDmode, arg);
+    }
+
+  return (rtx) *slot;
 }
 
-/* CONST_DOUBLEs needs special handling because its length is known
+/* CONST_DOUBLEs needs special handling because their length is known
    only at run-time.  */
+
 rtx
 gen_rtx_CONST_DOUBLE (mode, arg0, arg1, arg2)
      enum machine_mode mode;
@@ -297,7 +373,7 @@ gen_rtx_MEM (mode, addr)
 
 /*VARARGS2*/
 rtx
-gen_rtx VPROTO((enum rtx_code code, enum machine_mode mode, ...))
+gen_rtx VPARAMS ((enum rtx_code code, enum machine_mode mode, ...))
 {
 #ifndef ANSI_PROTOTYPES
   enum rtx_code code;
@@ -398,7 +474,7 @@ gen_rtx VPROTO((enum rtx_code code, enum machine_mode mode, ...))
 
 /*VARARGS1*/
 rtvec
-gen_rtvec VPROTO((int n, ...))
+gen_rtvec VPARAMS ((int n, ...))
 {
 #ifndef ANSI_PROTOTYPES
   int n;
@@ -452,7 +528,7 @@ rtx
 gen_reg_rtx (mode)
      enum machine_mode mode;
 {
-  struct function *f = current_function;
+  struct function *f = cfun;
   register rtx val;
 
   /* Don't let anything called after initial flow analysis create new
@@ -921,7 +997,8 @@ subreg_realpart_p (x)
   if (GET_CODE (x) != SUBREG)
     abort ();
 
-  return SUBREG_WORD (x) * UNITS_PER_WORD < GET_MODE_UNIT_SIZE (GET_MODE (SUBREG_REG (x)));
+  return ((unsigned int) SUBREG_WORD (x) * UNITS_PER_WORD
+         < GET_MODE_UNIT_SIZE (GET_MODE (SUBREG_REG (x))));
 }
 \f
 /* Assuming that X is an rtx (e.g., MEM, REG or SUBREG) for a value,
@@ -1101,7 +1178,7 @@ subreg_lowpart_p (x)
 rtx
 operand_subword (op, i, validate_address, mode)
      rtx op;
-     int i;
+     unsigned int i;
      int validate_address;
      enum machine_mode mode;
 {
@@ -1178,7 +1255,9 @@ operand_subword (op, i, validate_address, mode)
     return gen_rtx_SUBREG (word_mode, SUBREG_REG (op), i + SUBREG_WORD (op));
   else if (GET_CODE (op) == CONCAT)
     {
-      int partwords = GET_MODE_UNIT_SIZE (GET_MODE (op)) / UNITS_PER_WORD;
+      unsigned int partwords
+       = GET_MODE_UNIT_SIZE (GET_MODE (op)) / UNITS_PER_WORD;
+
       if (i < partwords)
        return operand_subword (XEXP (op, 0), i, validate_address, mode);
       return operand_subword (XEXP (op, 1), i - partwords,
@@ -1217,9 +1296,9 @@ operand_subword (op, i, validate_address, mode)
      are defined as returning one or two 32 bit values, respectively,
      and not values of BITS_PER_WORD bits.  */
 #ifdef REAL_ARITHMETIC
-/*  The output is some bits, the width of the target machine's word.
-    A wider-word host can surely hold them in a CONST_INT. A narrower-word
-    host can't.  */
+  /* The output is some bits, the width of the target machine's word.
+     A wider-word host can surely hold them in a CONST_INT. A narrower-word
+     host can't.  */
   if (HOST_BITS_PER_WIDE_INT >= BITS_PER_WORD
       && GET_MODE_CLASS (mode) == MODE_FLOAT
       && GET_MODE_BITSIZE (mode) == 64
@@ -1270,22 +1349,31 @@ operand_subword (op, i, validate_address, mode)
           && GET_MODE_CLASS (mode) == MODE_FLOAT
           && GET_MODE_BITSIZE (mode) > 64
           && GET_CODE (op) == CONST_DOUBLE)
-  {
-    long k[4];
-    REAL_VALUE_TYPE rv;
+    {
+      long k[4];
+      REAL_VALUE_TYPE rv;
 
-    REAL_VALUE_FROM_CONST_DOUBLE (rv, op);
-    REAL_VALUE_TO_TARGET_LONG_DOUBLE (rv, k);
+      REAL_VALUE_FROM_CONST_DOUBLE (rv, op);
+      REAL_VALUE_TO_TARGET_LONG_DOUBLE (rv, k);
 
-    if (BITS_PER_WORD == 32)
-      {
-       val = k[i];
-       val = ((val & 0xffffffff) ^ 0x80000000) - 0x80000000;
-       return GEN_INT (val);
-      }
-    else
-      abort ();
-  }
+      if (BITS_PER_WORD == 32)
+       {
+         val = k[i];
+         val = ((val & 0xffffffff) ^ 0x80000000) - 0x80000000;
+         return GEN_INT (val);
+       }
+#if HOST_BITS_PER_WIDE_INT >= 64
+      else if (BITS_PER_WORD >= 64 && i <= 1)
+       {
+         val = k[i*2 + ! WORDS_BIG_ENDIAN];
+         val = (((val & 0xffffffff) ^ 0x80000000) - 0x80000000) << 32;
+         val |= (HOST_WIDE_INT) k[i*2 + WORDS_BIG_ENDIAN] & 0xffffffff;
+         return GEN_INT (val);
+       }
+#endif
+      else
+       abort ();
+    }
 #else /* no REAL_ARITHMETIC */
   if (((HOST_FLOAT_FORMAT == TARGET_FLOAT_FORMAT
        && HOST_BITS_PER_WIDE_INT == BITS_PER_WORD)
@@ -1416,7 +1504,7 @@ operand_subword (op, i, validate_address, mode)
 rtx
 operand_subword_force (op, i, mode)
      rtx op;
-     int i;
+     unsigned int i;
      enum machine_mode mode;
 {
   rtx result = operand_subword (op, i, 1, mode);
@@ -1522,9 +1610,10 @@ gen_label_rtx ()
   register rtx label;
 
   label = gen_rtx_CODE_LABEL (VOIDmode, 0, NULL_RTX,
-                             NULL_RTX, label_num++, NULL_PTR);
+                             NULL_RTX, label_num++, NULL_PTR, NULL_PTR);
 
   LABEL_NUSES (label) = 0;
+  LABEL_ALTERNATE_NAME (label) = NULL;
   return label;
 }
 \f
@@ -1578,7 +1667,7 @@ set_new_last_label_num (last)
 
 void
 restore_emit_status (p)
-     struct function *p;
+     struct function *p ATTRIBUTE_UNUSED;
 {
   last_label_num = 0;
   clear_emit_caches ();
@@ -1599,23 +1688,23 @@ free_emit_status (f)
   f->emit = NULL;
 }
 \f
-/* Go through all the RTL insn bodies and copy any invalid shared structure.
-   It does not work to do this twice, because the mark bits set here
-   are not cleared afterwards.  */
+/* Go through all the RTL insn bodies and copy any invalid shared 
+   structure.  This routine should only be called once.  */
 
 void
-unshare_all_rtl (insn)
-     register rtx insn;
+unshare_all_rtl (fndecl, insn)
+     tree fndecl;
+     rtx insn;
 {
-  for (; insn; insn = NEXT_INSN (insn))
-    if (GET_CODE (insn) == INSN || GET_CODE (insn) == JUMP_INSN
-       || GET_CODE (insn) == CALL_INSN)
-      {
-       PATTERN (insn) = copy_rtx_if_shared (PATTERN (insn));
-       REG_NOTES (insn) = copy_rtx_if_shared (REG_NOTES (insn));
-       LOG_LINKS (insn) = copy_rtx_if_shared (LOG_LINKS (insn));
-      }
+  tree decl;
 
+  /* Make sure that virtual parameters are not shared.  */
+  for (decl = DECL_ARGUMENTS (fndecl); decl; decl = TREE_CHAIN (decl))
+    copy_rtx_if_shared (DECL_RTL (decl));
+
+  /* Unshare just about everything else.  */
+  unshare_all_rtl_1 (insn);
+  
   /* Make sure the addresses of stack slots found outside the insn chain
      (such as, in DECL_RTL of a variable) are not shared
      with the insn chain.
@@ -1623,10 +1712,44 @@ unshare_all_rtl (insn)
      This special care is necessary when the stack slot MEM does not
      actually appear in the insn chain.  If it does appear, its address
      is unshared from all else at that point.  */
-
   copy_rtx_if_shared (stack_slot_list);
 }
 
+/* Go through all the RTL insn bodies and copy any invalid shared 
+   structure, again.  This is a fairly expensive thing to do so it
+   should be done sparingly.  */
+
+void
+unshare_all_rtl_again (insn)
+     rtx insn;
+{
+  rtx p;
+  for (p = insn; p; p = NEXT_INSN (p))
+    if (GET_RTX_CLASS (GET_CODE (p)) == 'i')
+      {
+       reset_used_flags (PATTERN (p));
+       reset_used_flags (REG_NOTES (p));
+       reset_used_flags (LOG_LINKS (p));
+      }
+  unshare_all_rtl_1 (insn);
+}
+
+/* Go through all the RTL insn bodies and copy any invalid shared structure.
+   Assumes the mark bits are cleared at entry.  */
+
+static void
+unshare_all_rtl_1 (insn)
+     rtx insn;
+{
+  for (; insn; insn = NEXT_INSN (insn))
+    if (GET_RTX_CLASS (GET_CODE (insn)) == 'i')
+      {
+       PATTERN (insn) = copy_rtx_if_shared (PATTERN (insn));
+       REG_NOTES (insn) = copy_rtx_if_shared (REG_NOTES (insn));
+       LOG_LINKS (insn) = copy_rtx_if_shared (LOG_LINKS (insn));
+      }
+}
+
 /* Mark ORIG as in use, and return a copy of it if it was already in use.
    Recursively does the same for subexpressions.  */
 
@@ -1895,6 +2018,34 @@ get_max_uid ()
 {
   return cur_insn_uid;
 }
+
+/* Renumber instructions so that no instruction UIDs are wasted.  */
+
+void
+renumber_insns (stream)
+     FILE *stream;
+{
+  rtx insn;
+
+  /* If we're not supposed to renumber instructions, don't.  */
+  if (!flag_renumber_insns)
+    return;
+
+  /* If there aren't that many instructions, then it's not really
+     worth renumbering them.  */
+  if (flag_renumber_insns == 1 && get_max_uid () < 25000)
+    return;
+
+  cur_insn_uid = 1;
+
+  for (insn = get_insns (); insn; insn = NEXT_INSN (insn))
+    {
+      if (stream)
+       fprintf (stream, "Renumbering insn %d to %d\n", 
+                INSN_UID (insn), cur_insn_uid);
+      INSN_UID (insn) = cur_insn_uid++;
+    }
+}
 \f
 /* Return the next insn.  If it is a SEQUENCE, return the first insn
    of the sequence.  */
@@ -2008,6 +2159,17 @@ prev_real_insn (insn)
    does not look inside SEQUENCEs.  Until reload has completed, this is the
    same as next_real_insn.  */
 
+int
+active_insn_p (insn)
+     rtx insn;
+{
+  return (GET_CODE (insn) == CALL_INSN || GET_CODE (insn) == JUMP_INSN
+         || (GET_CODE (insn) == INSN
+             && (! reload_completed
+                 || (GET_CODE (PATTERN (insn)) != USE
+                     && GET_CODE (PATTERN (insn)) != CLOBBER))));
+}
+
 rtx
 next_active_insn (insn)
      rtx insn;
@@ -2015,12 +2177,7 @@ next_active_insn (insn)
   while (insn)
     {
       insn = NEXT_INSN (insn);
-      if (insn == 0
-         || GET_CODE (insn) == CALL_INSN || GET_CODE (insn) == JUMP_INSN
-         || (GET_CODE (insn) == INSN
-             && (! reload_completed
-                 || (GET_CODE (PATTERN (insn)) != USE
-                     && GET_CODE (PATTERN (insn)) != CLOBBER))))
+      if (insn == 0 || active_insn_p (insn))
        break;
     }
 
@@ -2038,12 +2195,7 @@ prev_active_insn (insn)
   while (insn)
     {
       insn = PREV_INSN (insn);
-      if (insn == 0
-         || GET_CODE (insn) == CALL_INSN || GET_CODE (insn) == JUMP_INSN
-         || (GET_CODE (insn) == INSN
-             && (! reload_completed
-                 || (GET_CODE (PATTERN (insn)) != USE
-                     && GET_CODE (PATTERN (insn)) != CLOBBER))))
+      if (insn == 0 || active_insn_p (insn))
        break;
     }
 
@@ -2228,7 +2380,9 @@ try_split (pat, trial, last)
 
       /* Return either the first or the last insn, depending on which was
         requested.  */
-      return last ? prev_active_insn (after) : next_active_insn (before);
+      return last 
+               ? (after ? prev_active_insn (after) : last_insn) 
+               : next_active_insn (before);
     }
 
   return trial;
@@ -2259,6 +2413,18 @@ make_insn_raw (pattern)
   LOG_LINKS (insn) = NULL;
   REG_NOTES (insn) = NULL;
 
+#ifdef ENABLE_RTL_CHECKING
+  if (insn
+      && GET_RTX_CLASS (GET_CODE (insn)) == 'i'
+      && (returnjump_p (insn)
+         || (GET_CODE (insn) == SET
+             && SET_DEST (insn) == pc_rtx)))
+    {
+      warning ("ICE: emit_insn used where emit_jump_insn needed:\n");
+      debug_rtx (insn);
+    }
+#endif
+  
   return insn;
 }
 
@@ -2566,6 +2732,89 @@ reorder_insns_with_line_notes (from, to, after)
                          NOTE_LINE_NUMBER (after_line),
                          to);
 }
+
+/* Remove unncessary notes from the instruction stream.  */
+
+void
+remove_unncessary_notes ()
+{
+  rtx insn;
+  rtx next;
+
+  /* We must not remove the first instruction in the function because
+     the compiler depends on the first instruction being a note.  */
+  for (insn = NEXT_INSN (get_insns ()); insn; insn = next)
+    {
+      /* Remember what's next.  */
+      next = NEXT_INSN (insn);
+
+      /* We're only interested in notes.  */
+      if (GET_CODE (insn) != NOTE)
+       continue;
+
+      /* By now, all notes indicating lexical blocks should have
+        NOTE_BLOCK filled in.  */
+      if ((NOTE_LINE_NUMBER (insn) == NOTE_INSN_BLOCK_BEG
+          || NOTE_LINE_NUMBER (insn) == NOTE_INSN_BLOCK_END)
+         && NOTE_BLOCK (insn) == NULL_TREE)
+       abort ();
+
+      /* Remove NOTE_INSN_DELETED notes.  */
+      if (NOTE_LINE_NUMBER (insn) == NOTE_INSN_DELETED)
+       remove_insn (insn);
+      else if (NOTE_LINE_NUMBER (insn) == NOTE_INSN_BLOCK_END)
+       {
+         /* Scan back to see if there are any non-note instructions
+            between INSN and the beginning of this block.  If not,
+            then there is no PC range in the generated code that will
+            actually be in this block, so there's no point in
+            remembering the existence of the block.  */
+         rtx prev;
+
+         for (prev = PREV_INSN (insn); prev; prev = PREV_INSN (prev))
+           {
+             /* This block contains a real instruction.  Note that we
+                don't include labels; if the only thing in the block
+                is a label, then there are still no PC values that
+                lie within the block.  */
+             if (GET_RTX_CLASS (GET_CODE (prev)) == 'i')
+               break;
+
+             /* We're only interested in NOTEs.  */
+             if (GET_CODE (prev) != NOTE)
+               continue;
+
+             if (NOTE_LINE_NUMBER (prev) == NOTE_INSN_BLOCK_BEG)
+               {
+                 /* If the BLOCKs referred to by these notes don't
+                    match, then something is wrong with our BLOCK
+                    nesting structure.  */
+                 if (NOTE_BLOCK (prev) != NOTE_BLOCK (insn))
+                   abort ();
+
+                 /* Never delete the BLOCK for the outermost scope
+                    of the function; we can refer to names from
+                    that scope even if the block notes are messed up.  */
+                 if (! is_body_block (NOTE_BLOCK (insn)))
+                   {
+                     debug_ignore_block (NOTE_BLOCK (insn));
+
+                     remove_insn (prev);
+                     remove_insn (insn);
+                   }
+                 break;
+               }
+             else if (NOTE_LINE_NUMBER (prev) == NOTE_INSN_BLOCK_END)
+               /* There's a nested block.  We need to leave the
+                  current block in place since otherwise the debugger
+                  wouldn't be able to show symbols from our block in
+                  the nested block.  */
+               break;
+           }
+       }
+    }
+}
+
 \f
 /* Emit an insn of given code and pattern
    at a specified place within the doubly-linked list.  */
@@ -2600,6 +2849,20 @@ emit_insn_before (pattern, before)
   return insn;
 }
 
+/* Similar to emit_insn_before, but update basic block boundaries as well.  */
+
+rtx
+emit_block_insn_before (pattern, before, block)
+     rtx pattern, before;
+     basic_block block;
+{
+  rtx prev = PREV_INSN (before);
+  rtx r = emit_insn_before (pattern, before);
+  if (block && block->head == before)
+    block->head = NEXT_INSN (prev);
+  return r;
+}
+
 /* Make an instruction with body PATTERN and code JUMP_INSN
    and output it before the instruction BEFORE.  */
 
@@ -2742,6 +3005,19 @@ emit_insn_after_with_line_notes (pattern, after, from)
                          insn);
 }
 
+/* Similar to emit_insn_after, but update basic block boundaries as well.  */
+
+rtx
+emit_block_insn_after (pattern, after, block)
+     rtx pattern, after;
+     basic_block block;
+{
+  rtx r = emit_insn_after (pattern, after);
+  if (block && block->end == after)
+    block->end = r;
+  return r;
+}
+
 /* Make an insn of code JUMP_INSN with body PATTERN
    and output it after the insn AFTER.  */
 
@@ -2814,7 +3090,7 @@ emit_note_after (subtype, after)
 
 rtx
 emit_line_note_after (file, line, after)
-     char *file;
+     const char *file;
      int line;
      rtx after;
 {
@@ -3013,7 +3289,7 @@ emit_barrier ()
 
 rtx
 emit_line_note (file, line)
-     char *file;
+     const char *file;
      int line;
 {
   set_file_and_line_for_stmt (file, line);
@@ -3033,7 +3309,7 @@ emit_line_note (file, line)
 
 rtx
 emit_note (file, line)
-     char *file;
+     const char *file;
      int line;
 {
   register rtx note;
@@ -3065,7 +3341,7 @@ emit_note (file, line)
 
 rtx
 emit_line_note_force (file, line)
-     char *file;
+     const char *file;
      int line;
 {
   last_linenum = -1;
@@ -3220,6 +3496,20 @@ push_to_sequence (first)
   last_insn = last;
 }
 
+/* Set up the insn chain from a chain stort in FIRST to LAST.  */
+
+void
+push_to_full_sequence (first, last)
+     rtx first, last;
+{
+  start_sequence ();
+  first_insn = first;
+  last_insn = last;
+  /* We really should have the end of the insn chain here.  */
+  if (last && NEXT_INSN (last))
+    abort ();
+}
+
 /* Set up the outer-level insn chain
    as the current sequence, saving the previously current one.  */
 
@@ -3282,6 +3572,18 @@ end_sequence ()
   free (tem);
 }
 
+/* This works like end_sequence, but records the old sequence in FIRST
+   and LAST.  */
+
+void
+end_full_sequence (first, last)
+     rtx *first, *last;
+{
+  *first = first_insn;
+  *last = last_insn;
+  end_sequence();
+}
+
 /* Return 1 if currently emitting into a sequence.  */
 
 int
@@ -3309,16 +3611,16 @@ gen_sequence ()
   for (tem = first_insn; tem; tem = NEXT_INSN (tem))
     len++;
 
-  /* If only one insn, return its pattern rather than a SEQUENCE.
+  /* If only one insn, return it rather than a SEQUENCE.
      (Now that we cache SEQUENCE expressions, it isn't worth special-casing
-     the case of an empty list.)  */
+     the case of an empty list.)     
+     We only return the pattern of an insn if its code is INSN and it
+     has no notes.  This ensures that no information gets lost.  */
   if (len == 1
       && ! RTX_FRAME_RELATED_P (first_insn)
-      && (GET_CODE (first_insn) == INSN
-         || GET_CODE (first_insn) == JUMP_INSN
-         /* Don't discard the call usage field.  */
-         || (GET_CODE (first_insn) == CALL_INSN
-             && CALL_INSN_FUNCTION_USAGE (first_insn) == NULL_RTX)))
+      && GET_CODE (first_insn) == INSN
+      /* Don't throw away any reg notes. */
+      && REG_NOTES (first_insn) == 0)
     {
       if (!ggc_p)
        {
@@ -3560,7 +3862,7 @@ copy_insn (insn)
 void
 init_emit ()
 {
-  struct function *f = current_function;
+  struct function *f = cfun;
 
   f->emit = (struct emit_status *) xmalloc (sizeof (struct emit_status));
   first_insn = NULL;
@@ -3608,21 +3910,16 @@ init_emit ()
   REGNO_POINTER_FLAG (VIRTUAL_CFA_REGNUM) = 1;
 
 #ifdef STACK_BOUNDARY
-  REGNO_POINTER_ALIGN (STACK_POINTER_REGNUM) = STACK_BOUNDARY / BITS_PER_UNIT;
-  REGNO_POINTER_ALIGN (FRAME_POINTER_REGNUM) = STACK_BOUNDARY / BITS_PER_UNIT;
-  REGNO_POINTER_ALIGN (HARD_FRAME_POINTER_REGNUM)
-    = STACK_BOUNDARY / BITS_PER_UNIT;
-  REGNO_POINTER_ALIGN (ARG_POINTER_REGNUM) = STACK_BOUNDARY / BITS_PER_UNIT;
-
-  REGNO_POINTER_ALIGN (VIRTUAL_INCOMING_ARGS_REGNUM)
-    = STACK_BOUNDARY / BITS_PER_UNIT;
-  REGNO_POINTER_ALIGN (VIRTUAL_STACK_VARS_REGNUM)
-    = STACK_BOUNDARY / BITS_PER_UNIT;
-  REGNO_POINTER_ALIGN (VIRTUAL_STACK_DYNAMIC_REGNUM)
-    = STACK_BOUNDARY / BITS_PER_UNIT;
-  REGNO_POINTER_ALIGN (VIRTUAL_OUTGOING_ARGS_REGNUM)
-    = STACK_BOUNDARY / BITS_PER_UNIT;
-  REGNO_POINTER_ALIGN (VIRTUAL_CFA_REGNUM) = UNITS_PER_WORD;
+  REGNO_POINTER_ALIGN (STACK_POINTER_REGNUM) = STACK_BOUNDARY;
+  REGNO_POINTER_ALIGN (FRAME_POINTER_REGNUM) = STACK_BOUNDARY;
+  REGNO_POINTER_ALIGN (HARD_FRAME_POINTER_REGNUM) = STACK_BOUNDARY;
+  REGNO_POINTER_ALIGN (ARG_POINTER_REGNUM) = STACK_BOUNDARY;
+
+  REGNO_POINTER_ALIGN (VIRTUAL_INCOMING_ARGS_REGNUM) = STACK_BOUNDARY;
+  REGNO_POINTER_ALIGN (VIRTUAL_STACK_VARS_REGNUM) = STACK_BOUNDARY;
+  REGNO_POINTER_ALIGN (VIRTUAL_STACK_DYNAMIC_REGNUM) = STACK_BOUNDARY;
+  REGNO_POINTER_ALIGN (VIRTUAL_OUTGOING_ARGS_REGNUM) = STACK_BOUNDARY;
+  REGNO_POINTER_ALIGN (VIRTUAL_CFA_REGNUM) = BITS_PER_WORD;
 #endif
 
 #ifdef INIT_EXPANDERS
@@ -3857,6 +4154,12 @@ init_emit_once (line_numbers)
   ggc_add_rtx_root (&static_chain_rtx, 1);
   ggc_add_rtx_root (&static_chain_incoming_rtx, 1);
   ggc_add_rtx_root (&return_address_pointer_rtx, 1);
+
+  /* Initialize the CONST_INT hash table.  */
+  const_int_htab = htab_create (37, const_int_htab_hash, 
+                               const_int_htab_eq, NULL);
+  ggc_add_root (&const_int_htab, 1, sizeof (const_int_htab), 
+               rtx_htab_mark);
 }
 \f
 /* Query and clear/ restore no_line_numbers.  This is used by the