OSDN Git Service

* expr.c (expand_expr): Use gen_int_mode for the argument
[pf3gnuchains/gcc-fork.git] / gcc / reload1.c
index a163b8a..441a447 100644 (file)
@@ -1,6 +1,6 @@
 /* Reload pseudo regs into hard regs for insns that require hard regs.
    Copyright (C) 1987, 1988, 1989, 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.
 
@@ -21,6 +21,8 @@ Software Foundation, 59 Temple Place - Suite 330, Boston, MA
 
 #include "config.h"
 #include "system.h"
+#include "coretypes.h"
+#include "tm.h"
 
 #include "machmode.h"
 #include "hard-reg-set.h"
@@ -139,7 +141,7 @@ static int reg_reloaded_contents[FIRST_PSEUDO_REGISTER];
    when reg_reloaded_valid is set for this register.  */
 static rtx reg_reloaded_insn[FIRST_PSEUDO_REGISTER];
 
-/* Indicate if reg_reloaded_insn / reg_reloaded_contents is valid */
+/* Indicate if reg_reloaded_insn / reg_reloaded_contents is valid */
 static HARD_REG_SET reg_reloaded_valid;
 /* Indicate if the register was dead at the end of the reload.
    This is only valid if reg_reloaded_contents is set and valid.  */
@@ -303,7 +305,7 @@ struct elim_table
   int from;                    /* Register number to be eliminated.  */
   int to;                      /* Register number used as replacement.  */
   int initial_offset;          /* Initial difference between values.  */
-  int can_eliminate;           /* Non-zero if this elimination can be done.  */
+  int can_eliminate;           /* Nonzero if this elimination can be done.  */
   int can_eliminate_previous;  /* Value of CAN_ELIMINATE in previous scan over
                                   insns made by reload.  */
   int offset;                  /* Current offset between the two regs.  */
@@ -352,11 +354,14 @@ static int num_eliminable_invariants;
 
 /* For each label, we record the offset of each elimination.  If we reach
    a label by more than one path and an offset differs, we cannot do the
-   elimination.  This information is indexed by the number of the label.
-   The first table is an array of flags that records whether we have yet
-   encountered a label and the second table is an array of arrays, one
-   entry in the latter array for each elimination.  */
-
+   elimination.  This information is indexed by the difference of the
+   number of the label and the first label number.  We can't offset the
+   pointer itself as this can cause problems on machines with segmented
+   memory.  The first table is an array of flags that records whether we
+   have yet encountered a label and the second table is an array of arrays,
+   one entry in the latter array for each elimination.  */
+
+static int first_label_num;
 static char *offsets_known_at;
 static int (*offsets_at)[NUM_ELIMINABLE_REGS];
 
@@ -673,11 +678,6 @@ reload (first, global)
   struct elim_table *ep;
   basic_block bb;
 
-  /* The two pointers used to track the true location of the memory used
-     for label offsets.  */
-  char *real_known_ptr = NULL;
-  int (*real_at_ptr)[NUM_ELIMINABLE_REGS];
-
   /* Make sure even insns with volatile mem refs are recognizable.  */
   init_recog ();
 
@@ -817,8 +817,12 @@ reload (first, global)
                      else if (LEGITIMATE_CONSTANT_P (x))
                        reg_equiv_constant[i] = x;
                      else
-                       reg_equiv_memory_loc[i]
-                         = force_const_mem (GET_MODE (SET_DEST (set)), x);
+                       {
+                         reg_equiv_memory_loc[i]
+                           = force_const_mem (GET_MODE (SET_DEST (set)), x);
+                         if (!reg_equiv_memory_loc[i])
+                           continue;
+                       }
                    }
                  else
                    continue;
@@ -852,21 +856,18 @@ reload (first, global)
 
   init_elim_table ();
 
-  num_labels = max_label_num () - get_first_label_num ();
+  first_label_num = get_first_label_num ();
+  num_labels = max_label_num () - first_label_num;
 
   /* Allocate the tables used to store offset information at labels.  */
   /* 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 a core dump.  */
-  real_known_ptr = xmalloc (num_labels);
-  real_at_ptr
+  offsets_known_at = xmalloc (num_labels);
+  offsets_at
     = (int (*)[NUM_ELIMINABLE_REGS])
     xmalloc (num_labels * NUM_ELIMINABLE_REGS * sizeof (int));
 
-  offsets_known_at = real_known_ptr - get_first_label_num ();
-  offsets_at
-    = (int (*)[NUM_ELIMINABLE_REGS]) (real_at_ptr - get_first_label_num ());
-
   /* Alter each pseudo-reg rtx to contain its hard reg number.
      Assign stack slots to the pseudos that lack hard regs or equivalents.
      Do not touch virtual registers.  */
@@ -1023,7 +1024,7 @@ reload (first, global)
              did_spill = 1;
 
              /* Regardless of the state of spills, if we previously had
-                a register that we thought we could eliminate, but no can
+                a register that we thought we could eliminate, but now can
                 not eliminate, we must run another pass.
 
                 Consider pseudos which have an entry in reg_equiv_* which
@@ -1265,10 +1266,10 @@ reload (first, global)
     free (reg_equiv_memory_loc);
   reg_equiv_memory_loc = 0;
 
-  if (real_known_ptr)
-    free (real_known_ptr);
-  if (real_at_ptr)
-    free (real_at_ptr);
+  if (offsets_known_at)
+    free (offsets_known_at);
+  if (offsets_at)
+    free (offsets_at);
 
   free (reg_equiv_mem);
   free (reg_equiv_init);
@@ -1349,7 +1350,7 @@ maybe_fix_stack_asms ()
 
          for (;;)
            {
-             char c = *p++;
+             char c = *p;
 
              if (c == '\0' || c == ',' || c == '#')
                {
@@ -1357,6 +1358,7 @@ maybe_fix_stack_asms ()
                     class, and reset the class.  */
                  IOR_HARD_REG_SET (allowed, reg_class_contents[cls]);
                  cls = NO_REGS;
+                 p++;
                  if (c == '#')
                    do {
                      c = *p++;
@@ -1387,13 +1389,14 @@ maybe_fix_stack_asms ()
                  break;
 
                default:
-                 if (EXTRA_ADDRESS_CONSTRAINT (c))
+                 if (EXTRA_ADDRESS_CONSTRAINT (c, p))
                    cls = (int) reg_class_subunion[cls]
                      [(int) MODE_BASE_REG_CLASS (VOIDmode)];
                  else
                    cls = (int) reg_class_subunion[cls]
-                     [(int) REG_CLASS_FROM_LETTER (c)];
+                     [(int) REG_CLASS_FROM_CONSTRAINT (c, p)];
                }
+             p += CONSTRAINT_LEN (c, p);
            }
        }
       /* Those of the registers which are clobbered, but allowed by the
@@ -1497,7 +1500,7 @@ calculate_needs_all_insns (global)
                  && REGNO (SET_SRC (set)) >= FIRST_PSEUDO_REGISTER)
                {
                  delete_insn (insn);
-                 /* Delete it from the reload chain */
+                 /* Delete it from the reload chain */
                  if (chain->prev)
                    chain->prev->next = next;
                  else
@@ -2073,9 +2076,10 @@ alter_reg (i, from_reg)
 
       /* If we have a decl for the original register, set it for the
         memory.  If this is a shared MEM, make a copy.  */
-      if (REGNO_DECL (i))
+      if (REG_EXPR (regno_reg_rtx[i])
+         && TREE_CODE_CLASS (TREE_CODE (REG_EXPR (regno_reg_rtx[i]))) == 'd')
        {
-         rtx decl = DECL_RTL_IF_SET (REGNO_DECL (i));
+         rtx decl = DECL_RTL_IF_SET (REG_EXPR (regno_reg_rtx[i]));
 
          /* We can do this only for the DECLs home pseudo, not for
             any copies of it, since otherwise when the stack slot
@@ -2086,7 +2090,7 @@ alter_reg (i, from_reg)
              if (from_reg != -1 && spill_stack_slot[from_reg] == x)
                x = copy_rtx (x);
 
-             set_mem_expr (x, REGNO_DECL (i));
+             set_mem_attrs_from_reg (x, regno_reg_rtx[i]);
            }
        }
 
@@ -2151,13 +2155,13 @@ set_label_offsets (x, insn, initial_p)
         we guessed wrong, we will suppress an elimination that might have
         been possible had we been able to guess correctly.  */
 
-      if (! offsets_known_at[CODE_LABEL_NUMBER (x)])
+      if (! offsets_known_at[CODE_LABEL_NUMBER (x) - first_label_num])
        {
          for (i = 0; i < NUM_ELIMINABLE_REGS; i++)
-           offsets_at[CODE_LABEL_NUMBER (x)][i]
+           offsets_at[CODE_LABEL_NUMBER (x) - first_label_num][i]
              = (initial_p ? reg_eliminate[i].initial_offset
                 : reg_eliminate[i].offset);
-         offsets_known_at[CODE_LABEL_NUMBER (x)] = 1;
+         offsets_known_at[CODE_LABEL_NUMBER (x) - first_label_num] = 1;
        }
 
       /* Otherwise, if this is the definition of a label and it is
@@ -2174,7 +2178,7 @@ set_label_offsets (x, insn, initial_p)
           where the offsets disagree.  */
 
        for (i = 0; i < NUM_ELIMINABLE_REGS; i++)
-         if (offsets_at[CODE_LABEL_NUMBER (x)][i]
+         if (offsets_at[CODE_LABEL_NUMBER (x) - first_label_num][i]
              != (initial_p ? reg_eliminate[i].initial_offset
                  : reg_eliminate[i].offset))
            reg_eliminate[i].can_eliminate = 0;
@@ -2536,6 +2540,10 @@ eliminate_regs (x, mem_mode, insn)
     case ABS:
     case SQRT:
     case FFS:
+    case CLZ:
+    case CTZ:
+    case POPCOUNT:
+    case PARITY:
       new = eliminate_regs (XEXP (x, 0), mem_mode, insn);
       if (new != XEXP (x, 0))
        return gen_rtx_fmt_e (code, GET_MODE (x), new);
@@ -2767,6 +2775,10 @@ elimination_effects (x, mem_mode)
     case ABS:
     case SQRT:
     case FFS:
+    case CLZ:
+    case CTZ:
+    case POPCOUNT:
+    case PARITY:
       elimination_effects (XEXP (x, 0), mem_mode);
       return;
 
@@ -2929,7 +2941,7 @@ eliminate_regs_in_insn (insn, replace)
   rtx old_set = single_set (insn);
   rtx new_body;
   int val = 0;
-  int i, any_changes;
+  int i;
   rtx substed_operand[MAX_RECOG_OPERANDS];
   rtx orig_operand[MAX_RECOG_OPERANDS];
   struct elim_table *ep;
@@ -3104,7 +3116,6 @@ eliminate_regs_in_insn (insn, replace)
   /* Eliminate all eliminable registers occurring in operands that
      can be handled by reload.  */
   extract_insn (insn);
-  any_changes = 0;
   for (i = 0; i < recog_data.n_operands; i++)
     {
       orig_operand[i] = recog_data.operand[i];
@@ -3130,7 +3141,7 @@ eliminate_regs_in_insn (insn, replace)
          substed_operand[i] = eliminate_regs (recog_data.operand[i], 0,
                                               replace ? insn : NULL_RTX);
          if (substed_operand[i] != orig_operand[i])
-           val = any_changes = 1;
+           val = 1;
          /* Terminate the search in check_eliminable_occurrences at
             this point.  */
          *recog_data.operand_loc[i] = 0;
@@ -3229,7 +3240,7 @@ eliminate_regs_in_insn (insn, replace)
      insn.  The changes we make were determined by the earlier call to
      elimination_effects.
 
-     We also detect cases where register elimination cannot be done,
+     We also detect cases where register elimination cannot be done,
      namely, if a register would be both changed and referenced outside a MEM
      in the resulting insn since such an insn is often undefined and, even if
      not, we cannot know what meaning will be given to it.  Note that it is
@@ -3383,7 +3394,7 @@ static void
 set_initial_label_offsets ()
 {
   rtx x;
-  memset ((char *) &offsets_known_at[get_first_label_num ()], 0, num_labels);
+  memset (offsets_known_at, 0, num_labels);
 
   for (x = forced_labels; x; x = XEXP (x, 1))
     if (XEXP (x, 0))
@@ -3404,7 +3415,8 @@ set_offsets_for_label (insn)
   num_not_at_initial_offset = 0;
   for (i = 0, ep = reg_eliminate; i < NUM_ELIMINABLE_REGS; ep++, i++)
     {
-      ep->offset = ep->previous_offset = offsets_at[label_nr][i];
+      ep->offset = ep->previous_offset
+                = offsets_at[label_nr - first_label_num][i];
       if (ep->can_eliminate && ep->offset != ep->initial_offset)
        num_not_at_initial_offset++;
     }
@@ -3420,9 +3432,7 @@ static void
 update_eliminables (pset)
      HARD_REG_SET *pset;
 {
-#if HARD_FRAME_POINTER_REGNUM != FRAME_POINTER_REGNUM
   int previous_frame_pointer_needed = frame_pointer_needed;
-#endif
   struct elim_table *ep;
 
   for (ep = reg_eliminate; ep < &reg_eliminate[NUM_ELIMINABLE_REGS]; ep++)
@@ -3487,12 +3497,10 @@ update_eliminables (pset)
        }
     }
 
-#if HARD_FRAME_POINTER_REGNUM != FRAME_POINTER_REGNUM
   /* If we didn't need a frame pointer last time, but we do now, spill
      the hard frame pointer.  */
   if (frame_pointer_needed && ! previous_frame_pointer_needed)
     SET_HARD_REG_BIT (*pset, HARD_FRAME_POINTER_REGNUM);
-#endif
 }
 
 /* Initialize the table of registers to eliminate.  */
@@ -3839,7 +3847,7 @@ reload_as_needed (live_known)
 
   for (chain = reload_insn_chain; chain; chain = chain->next)
     {
-      rtx prev;
+      rtx prev = 0;
       rtx insn = chain->insn;
       rtx old_next = NEXT_INSN (insn);
 
@@ -3981,7 +3989,7 @@ reload_as_needed (live_known)
                                            REGNO (rld[i].reg_rtx))
                      /* Make sure it is the inc/dec pseudo, and not
                         some other (e.g. output operand) pseudo.  */
-                     && (reg_reloaded_contents[REGNO (rld[i].reg_rtx)]
+                     && ((unsigned) reg_reloaded_contents[REGNO (rld[i].reg_rtx)]
                          == REGNO (XEXP (in_reg, 0))))
 
                    {
@@ -4048,7 +4056,7 @@ reload_as_needed (live_known)
                                                 REGNO (rld[i].reg_rtx))
                           /* Make sure it is the inc/dec pseudo, and not
                              some other (e.g. output operand) pseudo.  */
-                          && (reg_reloaded_contents[REGNO (rld[i].reg_rtx)]
+                          && ((unsigned) reg_reloaded_contents[REGNO (rld[i].reg_rtx)]
                               == REGNO (XEXP (in_reg, 0))))
                    {
                      SET_HARD_REG_BIT (reg_is_output_reload,
@@ -5494,16 +5502,15 @@ choose_reload_regs (chain)
                                                GET_MODE_CLASS (mode));
 
                  if (
-#ifdef CLASS_CANNOT_CHANGE_MODE
-                     (TEST_HARD_REG_BIT
-                      (reg_class_contents[(int) CLASS_CANNOT_CHANGE_MODE], i)
-                      ? ! CLASS_CANNOT_CHANGE_MODE_P (GET_MODE (last_reg),
-                                                      need_mode)
-                      : (GET_MODE_SIZE (GET_MODE (last_reg))
-                         >= GET_MODE_SIZE (need_mode)))
-#else
+#ifdef CANNOT_CHANGE_MODE_CLASS
+                     (!REG_CANNOT_CHANGE_MODE_P (i, GET_MODE (last_reg),
+                                                 need_mode)
+                      ||
+#endif
                      (GET_MODE_SIZE (GET_MODE (last_reg))
                       >= GET_MODE_SIZE (need_mode))
+#ifdef CANNOT_CHANGE_MODE_CLASS
+                     )
 #endif
                      && reg_reloaded_contents[i] == regno
                      && TEST_HARD_REG_BIT (reg_reloaded_valid, i)
@@ -5935,7 +5942,7 @@ choose_reload_regs (chain)
     if (reload_override_in[j])
       rld[j].in = reload_override_in[j];
 
-  /* If this reload won't be done because it has been cancelled or is
+  /* If this reload won't be done because it has been canceled or is
      optional and not inherited, clear reload_reg_rtx so other
      routines (such as subst_reloads) don't get confused.  */
   for (j = 0; j < n_reloads; j++)
@@ -6258,7 +6265,7 @@ emit_input_reload_insns (chain, rl, old, j)
         or memory.  */
 
       if (oldequiv != 0
-         && ((REGNO_REG_CLASS (regno) != rl->class
+         && (((enum reg_class) REGNO_REG_CLASS (regno) != rl->class
               && (REGISTER_MOVE_COST (mode, REGNO_REG_CLASS (regno),
                                       rl->class)
                   >= MEMORY_MOVE_COST (mode, rl->class, 1)))
@@ -6872,7 +6879,6 @@ do_input_reload (chain, rl, j)
      struct reload *rl;
      int j;
 {
-  int expect_occurrences = 1;
   rtx insn = chain->insn;
   rtx old = (rl->in && GET_CODE (rl->in) == MEM
             ? rl->in_reg : rl->in);
@@ -6893,11 +6899,7 @@ do_input_reload (chain, rl, j)
       && GET_CODE (rl->in_reg) == MEM
       && reload_spill_index[j] >= 0
       && TEST_HARD_REG_BIT (reg_reloaded_valid, reload_spill_index[j]))
-    {
-      expect_occurrences
-       = count_occurrences (PATTERN (insn), rl->in, 0) == 1 ? 0 : -1;
-      rl->in = regno_reg_rtx[reg_reloaded_contents[reload_spill_index[j]]];
-    }
+    rl->in = regno_reg_rtx[reg_reloaded_contents[reload_spill_index[j]]];
 
   /* If we are reloading a register that was recently stored in with an
      output-reload, see if we can prove there was
@@ -7613,6 +7615,11 @@ delete_output_reload (insn, j, last_reload_reg)
   rtx i1;
   rtx substed;
 
+  /* It is possible that this reload has been only used to set another reload
+     we eliminated earlier and thus deleted this instruction too.  */
+  if (INSN_DELETED_P (output_reload_insn))
+    return;
+
   /* Get the raw pseudo-register referred to.  */
 
   while (GET_CODE (reg) == SUBREG)
@@ -7694,7 +7701,7 @@ delete_output_reload (insn, j, last_reload_reg)
 
   /* The caller has already checked that REG dies or is set in INSN.
      It has also checked that we are optimizing, and thus some
-     inaccurancies in the debugging information are acceptable.
+     inaccuracies in the debugging information are acceptable.
      So we could just delete output_reload_insn.  But in some cases
      we can improve the debugging information without sacrificing
      optimization - maybe even improving the code: See if the pseudo
@@ -7896,7 +7903,7 @@ delete_address_reloads_1 (dead_insn, x, current_insn)
                  return;
              /* ??? We can't finish the loop here, because dst might be
                 allocated to a pseudo in this block if no reload in this
-                block needs any of the clsses containing DST - see
+                block needs any of the classes containing DST - see
                 spill_hard_reg.  There is no easy way to tell this, so we
                 have to scan till the end of the basic block.  */
            }
@@ -8275,7 +8282,13 @@ reload_cse_simplify_set (set, insn)
        {
 #ifdef LOAD_EXTEND_OP
          if (GET_MODE_BITSIZE (GET_MODE (SET_DEST (set))) < BITS_PER_WORD
-             && extend_op != NIL)
+             && extend_op != NIL
+#ifdef CANNOT_CHANGE_MODE_CLASS
+             && !CANNOT_CHANGE_MODE_CLASS (GET_MODE (SET_DEST (set)),
+                                           word_mode,
+                                           REGNO_REG_CLASS (REGNO (SET_DEST (set))))
+#endif
+             )
            {
              rtx wide_dest = gen_rtx_REG (word_mode, REGNO (SET_DEST (set)));
              ORIGINAL_REGNO (wide_dest) = ORIGINAL_REGNO (SET_DEST (set));
@@ -8418,7 +8431,7 @@ reload_cse_simplify_operands (insn, testreg)
          p = constraints[i];
          for (;;)
            {
-             char c = *p++;
+             char c = *p;
 
              switch (c)
                {
@@ -8442,7 +8455,9 @@ reload_cse_simplify_operands (insn, testreg)
 
                default:
                  class
-                   = reg_class_subunion[(int) class][(int) REG_CLASS_FROM_LETTER ((unsigned char) c)];
+                   = (reg_class_subunion
+                      [(int) class]
+                      [(int) REG_CLASS_FROM_CONSTRAINT ((unsigned char) c, p)]);
                  break;
 
                case ',': case '\0':
@@ -8462,6 +8477,7 @@ reload_cse_simplify_operands (insn, testreg)
                  j++;
                  break;
                }
+             p += CONSTRAINT_LEN (c, p);
 
              if (c == '\0')
                break;
@@ -8535,7 +8551,7 @@ reload_cse_simplify_operands (insn, testreg)
 \f
 /* If reload couldn't use reg+reg+offset addressing, try to use reg+reg
    addressing now.
-   This code might also be useful when reload gave up on reg+reg addresssing
+   This code might also be useful when reload gave up on reg+reg addressing
    because of clashes between the return register and INDEX_REG_CLASS.  */
 
 /* The maximum number of uses of a register we can keep track of to
@@ -8556,7 +8572,7 @@ struct reg_use { rtx insn, *usep; };
    last, of these uses.
    STORE_RUID is always meaningful if we only want to use a value in a
    register in a different place: it denotes the next insn in the insn
-   stream (i.e. the last ecountered) that sets or clobbers the register.  */
+   stream (i.e. the last encountered) that sets or clobbers the register.  */
 static struct
   {
     struct reg_use reg_use[RELOAD_COMBINE_MAX_USES];
@@ -9059,7 +9075,7 @@ static HOST_WIDE_INT reg_offset[FIRST_PSEUDO_REGISTER];
 static int reg_base_reg[FIRST_PSEUDO_REGISTER];
 static enum machine_mode reg_mode[FIRST_PSEUDO_REGISTER];
 
-/* move2add_luid is linearily increased while scanning the instructions
+/* move2add_luid is linearly increased while scanning the instructions
    from first to last.  It is used to set reg_set_luid in
    reload_cse_move2add and move2add_note_store.  */
 static int move2add_luid;
@@ -9155,7 +9171,7 @@ reload_cse_move2add (first)
                     use (set (reg) (reg)) instead.
                     We don't delete this insn, nor do we convert it into a
                     note, to avoid losing register notes or the return
-                    value flag.  jump2 already knowns how to get rid of
+                    value flag.  jump2 already knows how to get rid of
                     no-op moves.  */
                  if (new_src == const0_rtx)
                    success = validate_change (insn, &SET_SRC (pat), reg, 0);
@@ -9465,7 +9481,7 @@ fixup_abnormal_edges ()
     {
       edge e;
 
-      /* Look for cases we are interested in - an calls or instructions causing
+      /* Look for cases we are interested in - calls or instructions causing
          exceptions.  */
       for (e = bb->succ; e; e = e->succ_next)
        {
@@ -9504,7 +9520,7 @@ fixup_abnormal_edges ()
                     If it's placed after a trapping call (i.e. that
                     call is the last insn anyway), we have no fallthru
                     edge.  Simply delete this use and don't try to insert
-                    on the non-existant edge.  */
+                    on the non-existent edge.  */
                  if (GET_CODE (PATTERN (insn)) != USE)
                    {
                      /* We're not deleting it, we're moving it.  */
@@ -9519,6 +9535,14 @@ fixup_abnormal_edges ()
            }
        }
     }
+  /* We've possibly turned single trapping insn into multiple ones.  */
+  if (flag_non_call_exceptions)
+    {
+      sbitmap blocks;
+      blocks = sbitmap_alloc (last_basic_block);
+      sbitmap_ones (blocks);
+      find_many_sub_basic_blocks (blocks);
+    }
   if (inserted)
     commit_edge_insertions ();
 }