OSDN Git Service

Word wrap comment
[pf3gnuchains/gcc-fork.git] / gcc / emit-rtl.c
index 2c76306..e697d55 100644 (file)
@@ -1,5 +1,6 @@
 /* Emit RTL for the GNU C-Compiler expander.
-   Copyright (C) 1987, 88, 92-99, 2000 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,6 +46,7 @@ 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"
@@ -136,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:
 
@@ -170,16 +177,68 @@ 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];
 
@@ -188,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;
@@ -922,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,
@@ -1102,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;
 {
@@ -1179,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,
@@ -1218,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
@@ -1271,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)
@@ -1417,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);
@@ -1601,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.
@@ -1625,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.  */
 
@@ -2038,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;
@@ -2045,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;
     }
 
@@ -2068,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;
     }
 
@@ -2291,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;
 }
 
@@ -2607,9 +2741,8 @@ remove_unncessary_notes ()
   rtx insn;
   rtx next;
 
-  /* Remove NOTE_INSN_DELETED notes.  We must not remove the first
-     instruction in the function because the compiler depends on the
-     first instruction being a note.  */
+  /* 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.  */
@@ -2619,8 +2752,66 @@ remove_unncessary_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;
+           }
+       }
     }
 }
 
@@ -2899,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;
 {
@@ -2950,17 +3141,6 @@ emit_insn (pattern)
       add_insn (insn);
     }
 
-#ifdef ENABLE_RTL_CHECKING
-  if (insn
-      && (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;
 }
 
@@ -3109,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);
@@ -3129,7 +3309,7 @@ emit_line_note (file, line)
 
 rtx
 emit_note (file, line)
-     char *file;
+     const char *file;
      int line;
 {
   register rtx note;
@@ -3161,7 +3341,7 @@ emit_note (file, line)
 
 rtx
 emit_line_note_force (file, line)
-     char *file;
+     const char *file;
      int line;
 {
   last_linenum = -1;
@@ -3316,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.  */
 
@@ -3378,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
@@ -3704,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
@@ -3953,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