OSDN Git Service

* emit-rtl.c (dconstm2, dconsthalf): New real constants.
[pf3gnuchains/gcc-fork.git] / gcc / emit-rtl.c
index 0d9be17..4aab674 100644 (file)
@@ -1,6 +1,6 @@
 /* Emit RTL for the GNU C-Compiler expander.
    Copyright (C) 1987, 1988, 1992, 1993, 1994, 1995, 1996, 1997, 1998,
-   1999, 2000, 2001, 2002 Free Software Foundation, Inc.
+   1999, 2000, 2001, 2002, 2003 Free Software Foundation, Inc.
 
 This file is part of GCC.
 
@@ -37,6 +37,8 @@ Software Foundation, 59 Temple Place - Suite 330, Boston, MA
 
 #include "config.h"
 #include "system.h"
+#include "coretypes.h"
+#include "tm.h"
 #include "toplev.h"
 #include "rtl.h"
 #include "tree.h"
@@ -67,7 +69,7 @@ enum machine_mode ptr_mode;   /* Mode whose width is POINTER_SIZE.  */
 /* This is *not* reset after each function.  It gives each CODE_LABEL
    in the entire compilation a unique label number.  */
 
-static int label_num = 1;
+static GTY(()) int label_num = 1;
 
 /* Highest label number in current function.
    Zero means use the value of label_num instead.
@@ -109,6 +111,8 @@ REAL_VALUE_TYPE dconst0;
 REAL_VALUE_TYPE dconst1;
 REAL_VALUE_TYPE dconst2;
 REAL_VALUE_TYPE dconstm1;
+REAL_VALUE_TYPE dconstm2;
+REAL_VALUE_TYPE dconsthalf;
 
 /* All references to the following fixed hard registers go through
    these unique rtl objects.  On machines where the frame-pointer and
@@ -155,6 +159,10 @@ static GTY ((if_marked ("ggc_marked_p"), param_is (struct rtx_def)))
 static GTY ((if_marked ("ggc_marked_p"), param_is (struct mem_attrs)))
      htab_t mem_attrs_htab;
 
+/* A hash table storing register attribute structures.  */
+static GTY ((if_marked ("ggc_marked_p"), param_is (struct reg_attrs)))
+     htab_t reg_attrs_htab;
+
 /* A hash table storing all CONST_DOUBLEs.  */
 static GTY ((if_marked ("ggc_marked_p"), param_is (struct rtx_def)))
      htab_t const_double_htab;
@@ -188,6 +196,10 @@ static int mem_attrs_htab_eq            PARAMS ((const void *,
 static mem_attrs *get_mem_attrs                PARAMS ((HOST_WIDE_INT, tree, rtx,
                                                 rtx, unsigned int,
                                                 enum machine_mode));
+static hashval_t reg_attrs_htab_hash    PARAMS ((const void *));
+static int reg_attrs_htab_eq            PARAMS ((const void *,
+                                                const void *));
+static reg_attrs *get_reg_attrs                PARAMS ((tree, int));
 static tree component_ref_for_mem_expr PARAMS ((tree));
 static rtx gen_const_vector_0          PARAMS ((enum machine_mode));
 
@@ -227,7 +239,11 @@ const_double_htab_hash (x)
   if (GET_MODE (value) == VOIDmode)
     h = CONST_DOUBLE_LOW (value) ^ CONST_DOUBLE_HIGH (value);
   else
-    h = real_hash (CONST_DOUBLE_REAL_VALUE (value));
+    {
+      h = real_hash (CONST_DOUBLE_REAL_VALUE (value)); 
+      /* MODE is used in the comparison, so it should be in the hash.  */
+      h ^= GET_MODE (value);
+    }
   return h;
 }
 
@@ -321,6 +337,60 @@ get_mem_attrs (alias, expr, offset, size, align, mode)
   return *slot;
 }
 
+/* Returns a hash code for X (which is a really a reg_attrs *).  */
+
+static hashval_t
+reg_attrs_htab_hash (x)
+     const void *x;
+{
+  reg_attrs *p = (reg_attrs *) x;
+
+  return ((p->offset * 1000) ^ (long) p->decl);
+}
+
+/* Returns non-zero if the value represented by X (which is really a
+   reg_attrs *) is the same as that given by Y (which is also really a
+   reg_attrs *).  */
+
+static int
+reg_attrs_htab_eq (x, y)
+     const void *x;
+     const void *y;
+{
+  reg_attrs *p = (reg_attrs *) x;
+  reg_attrs *q = (reg_attrs *) y;
+
+  return (p->decl == q->decl && p->offset == q->offset);
+}
+/* Allocate a new reg_attrs structure and insert it into the hash table if
+   one identical to it is not already in the table.  We are doing this for
+   MEM of mode MODE.  */
+
+static reg_attrs *
+get_reg_attrs (decl, offset)
+     tree decl;
+     int offset;
+{
+  reg_attrs attrs;
+  void **slot;
+
+  /* If everything is the default, we can just return zero.  */
+  if (decl == 0 && offset == 0)
+    return 0;
+
+  attrs.decl = decl;
+  attrs.offset = offset;
+
+  slot = htab_find_slot (reg_attrs_htab, &attrs, INSERT);
+  if (*slot == 0)
+    {
+      *slot = ggc_alloc (sizeof (reg_attrs));
+      memcpy (*slot, &attrs, sizeof (reg_attrs));
+    }
+
+  return *slot;
+}
+
 /* Generate a new REG rtx.  Make sure ORIGINAL_REGNO is set properly, and
    don't attempt to share with the various global pieces of rtl (such as
    frame_pointer_rtx).  */
@@ -531,7 +601,7 @@ gen_rtx_REG (mode, regno)
       if (regno == RETURN_ADDRESS_POINTER_REGNUM)
        return return_address_pointer_rtx;
 #endif
-      if (regno == PIC_OFFSET_TABLE_REGNUM
+      if (regno == (unsigned) PIC_OFFSET_TABLE_REGNUM
          && fixed_regs[PIC_OFFSET_TABLE_REGNUM])
        return pic_offset_table_rtx;
       if (regno == STACK_POINTER_REGNUM)
@@ -809,7 +879,7 @@ gen_reg_rtx (mode)
       return gen_rtx_CONCAT (mode, realpart, imagpart);
     }
 
-  /* Make sure regno_pointer_align, regno_decl, and regno_reg_rtx are large
+  /* Make sure regno_pointer_align, and regno_reg_rtx are large
      enough to have an element for this pseudo reg number.  */
 
   if (reg_rtx_no == f->emit->regno_pointer_align_length)
@@ -817,7 +887,6 @@ gen_reg_rtx (mode)
       int old_size = f->emit->regno_pointer_align_length;
       char *new;
       rtx *new1;
-      tree *new2;
 
       new = ggc_realloc (f->emit->regno_pointer_align, old_size * 2);
       memset (new + old_size, 0, old_size);
@@ -828,11 +897,6 @@ gen_reg_rtx (mode)
       memset (new1 + old_size, 0, old_size * sizeof (rtx));
       regno_reg_rtx = new1;
 
-      new2 = (tree *) ggc_realloc (f->emit->regno_decl,
-                                  old_size * 2 * sizeof (tree));
-      memset (new2 + old_size, 0, old_size * sizeof (tree));
-      f->emit->regno_decl = new2;
-
       f->emit->regno_pointer_align_length = old_size * 2;
     }
 
@@ -841,6 +905,96 @@ gen_reg_rtx (mode)
   return val;
 }
 
+/* Generate an register with same attributes as REG,
+   but offsetted by OFFSET.  */
+
+rtx
+gen_rtx_REG_offset (reg, mode, regno, offset)
+     enum machine_mode mode;
+     unsigned int regno;
+     int offset;
+     rtx reg;
+{
+  rtx new = gen_rtx_REG (mode, regno);
+  REG_ATTRS (new) = get_reg_attrs (REG_EXPR (reg),
+                                  REG_OFFSET (reg) + offset);
+  return new;
+}
+
+/* Set the decl for MEM to DECL.  */
+
+void
+set_reg_attrs_from_mem (reg, mem)
+     rtx reg;
+     rtx mem;
+{
+  if (MEM_OFFSET (mem) && GET_CODE (MEM_OFFSET (mem)) == CONST_INT)
+    REG_ATTRS (reg)
+      = get_reg_attrs (MEM_EXPR (mem), INTVAL (MEM_OFFSET (mem)));
+}
+
+/* Set the register attributes for registers contained in PARM_RTX.
+   Use needed values from memory attributes of MEM.  */
+
+void
+set_reg_attrs_for_parm (parm_rtx, mem)
+     rtx parm_rtx;
+     rtx mem;
+{
+  if (GET_CODE (parm_rtx) == REG)
+    set_reg_attrs_from_mem (parm_rtx, mem);
+  else if (GET_CODE (parm_rtx) == PARALLEL)
+    {
+      /* Check for a NULL entry in the first slot, used to indicate that the
+        parameter goes both on the stack and in registers.  */
+      int i = XEXP (XVECEXP (parm_rtx, 0, 0), 0) ? 0 : 1;
+      for (; i < XVECLEN (parm_rtx, 0); i++)
+       {
+         rtx x = XVECEXP (parm_rtx, 0, i);
+         if (GET_CODE (XEXP (x, 0)) == REG)
+           REG_ATTRS (XEXP (x, 0))
+             = get_reg_attrs (MEM_EXPR (mem),
+                              INTVAL (XEXP (x, 1)));
+       }
+    }
+}
+
+/* Assign the RTX X to declaration T.  */
+void
+set_decl_rtl (t, x)
+     tree t;
+     rtx x;
+{
+  DECL_CHECK (t)->decl.rtl = x;
+
+  if (!x)
+    return;
+  /* For register, we maitain the reverse information too.  */
+  if (GET_CODE (x) == REG)
+    REG_ATTRS (x) = get_reg_attrs (t, 0);
+  else if (GET_CODE (x) == SUBREG)
+    REG_ATTRS (SUBREG_REG (x))
+      = get_reg_attrs (t, -SUBREG_BYTE (x));
+  if (GET_CODE (x) == CONCAT)
+    {
+      if (REG_P (XEXP (x, 0)))
+        REG_ATTRS (XEXP (x, 0)) = get_reg_attrs (t, 0);
+      if (REG_P (XEXP (x, 1)))
+       REG_ATTRS (XEXP (x, 1))
+         = get_reg_attrs (t, GET_MODE_UNIT_SIZE (GET_MODE (XEXP (x, 0))));
+    }
+  if (GET_CODE (x) == PARALLEL)
+    {
+      int i;
+      for (i = 0; i < XVECLEN (x, 0); i++)
+       {
+         rtx y = XVECEXP (x, 0, i);
+         if (REG_P (XEXP (y, 0)))
+           REG_ATTRS (XEXP (y, 0)) = get_reg_attrs (t, INTVAL (XEXP (y, 1)));
+       }
+    }
+}
+
 /* Identify REG (which may be a CONCAT) as a user register.  */
 
 void
@@ -1219,6 +1373,13 @@ gen_lowpart (mode, x)
     {
       /* The only additional case we can do is MEM.  */
       int offset = 0;
+
+      /* The following exposes the use of "x" to CSE.  */
+      if (GET_MODE_SIZE (GET_MODE (x)) <= UNITS_PER_WORD
+         && SCALAR_INT_MODE_P (GET_MODE (x))
+         && ! no_new_pseudos)
+       return gen_lowpart (mode, force_reg (GET_MODE (x), x));
+
       if (WORDS_BIG_ENDIAN)
        offset = (MAX (GET_MODE_SIZE (GET_MODE (x)), UNITS_PER_WORD)
                  - MAX (GET_MODE_SIZE (mode), UNITS_PER_WORD));
@@ -1268,7 +1429,7 @@ gen_highpart (mode, x)
   return result;
 }
 
-/* Like gen_highpart_mode, but accept mode of EXP operand in case EXP can
+/* Like gen_highpart, but accept mode of EXP operand in case EXP can
    be VOIDmode constant.  */
 rtx
 gen_highpart_mode (outermode, innermode, exp)
@@ -1847,7 +2008,7 @@ set_mem_attributes_minus_bitpos (ref, t, objectp, bitpos)
                  HOST_WIDE_INT ioff = tree_low_cst (off_tree, 1);
                  HOST_WIDE_INT aoff = (ioff & -ioff) * BITS_PER_UNIT;
                  align = DECL_ALIGN (t);
-                 if (aoff && aoff < align)
+                 if (aoff && (unsigned HOST_WIDE_INT) aoff < align)
                    align = aoff;
                  offset = GEN_INT (ioff);
                  apply_bitpos = bitpos;
@@ -1919,6 +2080,19 @@ set_mem_attributes (ref, t, objectp)
   set_mem_attributes_minus_bitpos (ref, t, objectp, 0);
 }
 
+/* Set the decl for MEM to DECL.  */
+
+void
+set_mem_attrs_from_reg (mem, reg)
+     rtx mem;
+     rtx reg;
+{
+  MEM_ATTRS (mem)
+    = get_mem_attrs (MEM_ALIAS_SET (mem), REG_EXPR (reg),
+                    GEN_INT (REG_OFFSET (reg)),
+                    MEM_SIZE (mem), MEM_ALIGN (mem), GET_MODE (mem));
+}
+
 /* Set the alias set of MEM to SET.  */
 
 void
@@ -3203,6 +3377,8 @@ try_split (pat, trial, last)
   rtx tem;
   rtx note, seq;
   int probability;
+  rtx insn_last, insn;
+  int njumps = 0;
 
   if (any_condjump_p (trial)
       && (note = find_reg_note (trial, REG_BR_PROB, 0)))
@@ -3221,172 +3397,147 @@ try_split (pat, trial, last)
       after = NEXT_INSN (after);
     }
 
-  if (seq)
+  if (!seq)
+    return trial;
+
+  /* Avoid infinite loop if any insn of the result matches
+     the original pattern.  */
+  insn_last = seq;
+  while (1)
     {
-      /* Sometimes there will be only one insn in that list, this case will
-        normally arise only when we want it in turn to be split (SFmode on
-        the 29k is an example).  */
-      if (NEXT_INSN (seq) != NULL_RTX)
-       {
-         rtx insn_last, insn;
-         int njumps = 0;
+      if (INSN_P (insn_last)
+         && rtx_equal_p (PATTERN (insn_last), pat))
+       return trial;
+      if (!NEXT_INSN (insn_last))
+       break;
+      insn_last = NEXT_INSN (insn_last);
+    }
 
-         /* Avoid infinite loop if any insn of the result matches
-            the original pattern.  */
-         insn_last = seq;
-         while (1)
+  /* Mark labels.  */
+  for (insn = insn_last; insn ; insn = PREV_INSN (insn))
+    {
+      if (GET_CODE (insn) == JUMP_INSN)
+       {
+         mark_jump_label (PATTERN (insn), insn, 0);
+         njumps++;
+         if (probability != -1
+             && any_condjump_p (insn)
+             && !find_reg_note (insn, REG_BR_PROB, 0))
            {
-             if (INSN_P (insn_last)
-                 && rtx_equal_p (PATTERN (insn_last), pat))
-               return trial;
-             if (NEXT_INSN (insn_last) == NULL_RTX)
-               break;
-             insn_last = NEXT_INSN (insn_last);
+             /* We can preserve the REG_BR_PROB notes only if exactly
+                one jump is created, otherwise the machine description
+                is responsible for this step using
+                split_branch_probability variable.  */
+             if (njumps != 1)
+               abort ();
+             REG_NOTES (insn)
+               = gen_rtx_EXPR_LIST (REG_BR_PROB,
+                                    GEN_INT (probability),
+                                    REG_NOTES (insn));
            }
+       }
+    }
 
-         /* Mark labels.  */
+  /* If we are splitting a CALL_INSN, look for the CALL_INSN
+     in SEQ and copy our CALL_INSN_FUNCTION_USAGE to it.  */
+  if (GET_CODE (trial) == CALL_INSN)
+    {
+      for (insn = insn_last; insn ; insn = PREV_INSN (insn))
+       if (GET_CODE (insn) == CALL_INSN)
+         {
+           CALL_INSN_FUNCTION_USAGE (insn)
+             = CALL_INSN_FUNCTION_USAGE (trial);
+           SIBLING_CALL_P (insn) = SIBLING_CALL_P (trial);
+         }
+    }
+
+  /* Copy notes, particularly those related to the CFG.  */
+  for (note = REG_NOTES (trial); note; note = XEXP (note, 1))
+    {
+      switch (REG_NOTE_KIND (note))
+       {
+       case REG_EH_REGION:
          insn = insn_last;
          while (insn != NULL_RTX)
            {
-             if (GET_CODE (insn) == JUMP_INSN)
-               {
-                 mark_jump_label (PATTERN (insn), insn, 0);
-                 njumps++;
-                 if (probability != -1
-                     && any_condjump_p (insn)
-                     && !find_reg_note (insn, REG_BR_PROB, 0))
-                   {
-                     /* We can preserve the REG_BR_PROB notes only if exactly
-                        one jump is created, otherwise the machine description
-                        is responsible for this step using
-                        split_branch_probability variable.  */
-                     if (njumps != 1)
-                       abort ();
-                     REG_NOTES (insn)
-                       = gen_rtx_EXPR_LIST (REG_BR_PROB,
-                                            GEN_INT (probability),
-                                            REG_NOTES (insn));
-                   }
-               }
-
+             if (GET_CODE (insn) == CALL_INSN
+                 || (flag_non_call_exceptions
+                     && may_trap_p (PATTERN (insn))))
+               REG_NOTES (insn)
+                 = gen_rtx_EXPR_LIST (REG_EH_REGION,
+                                      XEXP (note, 0),
+                                      REG_NOTES (insn));
              insn = PREV_INSN (insn);
            }
+         break;
 
-         /* If we are splitting a CALL_INSN, look for the CALL_INSN
-            in SEQ and copy our CALL_INSN_FUNCTION_USAGE to it.  */
-         if (GET_CODE (trial) == CALL_INSN)
+       case REG_NORETURN:
+       case REG_SETJMP:
+       case REG_ALWAYS_RETURN:
+         insn = insn_last;
+         while (insn != NULL_RTX)
            {
-             insn = insn_last;
-             while (insn != NULL_RTX)
-               {
-                 if (GET_CODE (insn) == CALL_INSN)
-                   CALL_INSN_FUNCTION_USAGE (insn)
-                     = CALL_INSN_FUNCTION_USAGE (trial);
-
-                 insn = PREV_INSN (insn);
-               }
+             if (GET_CODE (insn) == CALL_INSN)
+               REG_NOTES (insn)
+                 = gen_rtx_EXPR_LIST (REG_NOTE_KIND (note),
+                                      XEXP (note, 0),
+                                      REG_NOTES (insn));
+             insn = PREV_INSN (insn);
            }
+         break;
 
-         /* Copy notes, particularly those related to the CFG.  */
-         for (note = REG_NOTES (trial); note; note = XEXP (note, 1))
+       case REG_NON_LOCAL_GOTO:
+         insn = insn_last;
+         while (insn != NULL_RTX)
            {
-             switch (REG_NOTE_KIND (note))
-               {
-               case REG_EH_REGION:
-                 insn = insn_last;
-                 while (insn != NULL_RTX)
-                   {
-                     if (GET_CODE (insn) == CALL_INSN
-                         || (flag_non_call_exceptions
-                             && may_trap_p (PATTERN (insn))))
-                       REG_NOTES (insn)
-                         = gen_rtx_EXPR_LIST (REG_EH_REGION,
-                                              XEXP (note, 0),
-                                              REG_NOTES (insn));
-                     insn = PREV_INSN (insn);
-                   }
-                 break;
-
-               case REG_NORETURN:
-               case REG_SETJMP:
-               case REG_ALWAYS_RETURN:
-                 insn = insn_last;
-                 while (insn != NULL_RTX)
-                   {
-                     if (GET_CODE (insn) == CALL_INSN)
-                       REG_NOTES (insn)
-                         = gen_rtx_EXPR_LIST (REG_NOTE_KIND (note),
-                                              XEXP (note, 0),
-                                              REG_NOTES (insn));
-                     insn = PREV_INSN (insn);
-                   }
-                 break;
-
-               case REG_NON_LOCAL_GOTO:
-                 insn = insn_last;
-                 while (insn != NULL_RTX)
-                   {
-                     if (GET_CODE (insn) == JUMP_INSN)
-                       REG_NOTES (insn)
-                         = gen_rtx_EXPR_LIST (REG_NOTE_KIND (note),
-                                              XEXP (note, 0),
-                                              REG_NOTES (insn));
-                     insn = PREV_INSN (insn);
-                   }
-                 break;
-
-               default:
-                 break;
-               }
+             if (GET_CODE (insn) == JUMP_INSN)
+               REG_NOTES (insn)
+                 = gen_rtx_EXPR_LIST (REG_NOTE_KIND (note),
+                                      XEXP (note, 0),
+                                      REG_NOTES (insn));
+             insn = PREV_INSN (insn);
            }
+         break;
 
-         /* If there are LABELS inside the split insns increment the
-            usage count so we don't delete the label.  */
-         if (GET_CODE (trial) == INSN)
-           {
-             insn = insn_last;
-             while (insn != NULL_RTX)
-               {
-                 if (GET_CODE (insn) == INSN)
-                   mark_label_nuses (PATTERN (insn));
+       default:
+         break;
+       }
+    }
 
-                 insn = PREV_INSN (insn);
-               }
-           }
+  /* If there are LABELS inside the split insns increment the
+     usage count so we don't delete the label.  */
+  if (GET_CODE (trial) == INSN)
+    {
+      insn = insn_last;
+      while (insn != NULL_RTX)
+       {
+         if (GET_CODE (insn) == INSN)
+           mark_label_nuses (PATTERN (insn));
 
-         tem = emit_insn_after_scope (seq, trial, INSN_SCOPE (trial));
+         insn = PREV_INSN (insn);
+       }
+    }
 
-         delete_insn (trial);
-         if (has_barrier)
-           emit_barrier_after (tem);
+  tem = emit_insn_after_scope (seq, trial, INSN_SCOPE (trial));
 
-         /* Recursively call try_split for each new insn created; by the
-            time control returns here that insn will be fully split, so
-            set LAST and continue from the insn after the one returned.
-            We can't use next_active_insn here since AFTER may be a note.
-            Ignore deleted insns, which can be occur if not optimizing.  */
-         for (tem = NEXT_INSN (before); tem != after; tem = NEXT_INSN (tem))
-           if (! INSN_DELETED_P (tem) && INSN_P (tem))
-             tem = try_split (PATTERN (tem), tem, 1);
-       }
-      /* Avoid infinite loop if the result matches the original pattern.  */
-      else if (rtx_equal_p (PATTERN (seq), pat))
-       return trial;
-      else
-       {
-         PATTERN (trial) = PATTERN (seq);
-         INSN_CODE (trial) = -1;
-         try_split (PATTERN (trial), trial, last);
-       }
+  delete_insn (trial);
+  if (has_barrier)
+    emit_barrier_after (tem);
 
-      /* Return either the first or the last insn, depending on which was
-        requested.  */
-      return last
-               ? (after ? PREV_INSN (after) : last_insn)
-               : NEXT_INSN (before);
-    }
+  /* Recursively call try_split for each new insn created; by the
+     time control returns here that insn will be fully split, so
+     set LAST and continue from the insn after the one returned.
+     We can't use next_active_insn here since AFTER may be a note.
+     Ignore deleted insns, which can be occur if not optimizing.  */
+  for (tem = NEXT_INSN (before); tem != after; tem = NEXT_INSN (tem))
+    if (! INSN_DELETED_P (tem) && INSN_P (tem))
+      tem = try_split (PATTERN (tem), tem, 1);
 
-  return trial;
+  /* Return either the first or the last insn, depending on which was
+     requested.  */
+  return last
+    ? (after ? PREV_INSN (after) : last_insn)
+    : NEXT_INSN (before);
 }
 \f
 /* Make and return an INSN rtx, initializing all its slots.
@@ -5211,12 +5362,7 @@ init_emit ()
                                           * sizeof (unsigned char));
 
   regno_reg_rtx
-    = (rtx *) ggc_alloc_cleared (f->emit->regno_pointer_align_length
-                                * sizeof (rtx));
-
-  f->emit->regno_decl
-    = (tree *) ggc_alloc_cleared (f->emit->regno_pointer_align_length
-                                 * sizeof (tree));
+    = (rtx *) ggc_alloc (f->emit->regno_pointer_align_length * sizeof (rtx));
 
   /* Put copies of all the hard registers into regno_reg_rtx.  */
   memcpy (regno_reg_rtx,
@@ -5313,14 +5459,16 @@ init_emit_once (line_numbers)
 
   /* Initialize the CONST_INT, CONST_DOUBLE, and memory attribute hash
      tables.  */
-  const_int_htab = htab_create (37, const_int_htab_hash,
-                               const_int_htab_eq, NULL);
+  const_int_htab = htab_create_ggc (37, const_int_htab_hash,
+                                   const_int_htab_eq, NULL);
 
-  const_double_htab = htab_create (37, const_double_htab_hash,
-                                  const_double_htab_eq, NULL);
+  const_double_htab = htab_create_ggc (37, const_double_htab_hash,
+                                      const_double_htab_eq, NULL);
 
-  mem_attrs_htab = htab_create (37, mem_attrs_htab_hash,
-                               mem_attrs_htab_eq, NULL);
+  mem_attrs_htab = htab_create_ggc (37, mem_attrs_htab_hash,
+                                   mem_attrs_htab_eq, NULL);
+  reg_attrs_htab = htab_create_ggc (37, reg_attrs_htab_hash,
+                                   reg_attrs_htab_eq, NULL);
 
   no_line_numbers = ! line_numbers;
 
@@ -5406,6 +5554,10 @@ init_emit_once (line_numbers)
   REAL_VALUE_FROM_INT (dconst1,   1,  0, double_mode);
   REAL_VALUE_FROM_INT (dconst2,   2,  0, double_mode);
   REAL_VALUE_FROM_INT (dconstm1, -1, -1, double_mode);
+  REAL_VALUE_FROM_INT (dconstm2, -2, -1, double_mode);
+
+  dconsthalf = dconst1;
+  dconsthalf.exp--;
 
   for (i = 0; i <= 2; i++)
     {
@@ -5491,7 +5643,7 @@ init_emit_once (line_numbers)
 #endif
 #endif
 
-  if (PIC_OFFSET_TABLE_REGNUM != INVALID_REGNUM)
+  if ((unsigned) PIC_OFFSET_TABLE_REGNUM != INVALID_REGNUM)
     pic_offset_table_rtx = gen_raw_REG (Pmode, PIC_OFFSET_TABLE_REGNUM);
 }
 \f
@@ -5581,6 +5733,7 @@ emit_copy_of_insn_after (insn, after)
       XEXP (note1, 0) = p;
       XEXP (note2, 0) = new;
     }
+  INSN_CODE (new) = INSN_CODE (insn);
   return new;
 }