OSDN Git Service

* regclass.c (record_reg_classes): Correctly handle 'p' constraint.
[pf3gnuchains/gcc-fork.git] / gcc / regclass.c
index 75d7302..9faf8ab 100644 (file)
@@ -1,5 +1,5 @@
 /* Compute register class preferences for pseudo-registers.
-   Copyright (C) 1987, 88, 91-97, 1998 Free Software Foundation, Inc.
+   Copyright (C) 1987, 88, 91-98, 1999 Free Software Foundation, Inc.
 
 This file is part of GNU CC.
 
@@ -41,6 +41,9 @@ Boston, MA 02111-1307, USA.  */
 #define REGISTER_MOVE_COST(x, y) 2
 #endif
 
+static void init_reg_sets_1    PROTO((void));
+static void init_reg_modes     PROTO((void));
+
 /* If we have auto-increment or auto-decrement and we can have secondary
    reloads, we are not allowed to use classes requiring secondary
    reloads for pseudos auto-incremented since reload can't handle it.  */
@@ -233,6 +236,25 @@ init_reg_sets ()
   bcopy (initial_call_used_regs, call_used_regs, sizeof call_used_regs);
   bzero (global_regs, sizeof global_regs);
 
+  /* Do any additional initialization regsets may need */
+  INIT_ONCE_REG_SET ();
+}
+
+/* After switches have been processed, which perhaps alter
+   `fixed_regs' and `call_used_regs', convert them to HARD_REG_SETs.  */
+
+static void
+init_reg_sets_1 ()
+{
+  register unsigned int i, j;
+
+  /* This macro allows the fixed or call-used registers
+     and the register classes to depend on target flags.  */
+
+#ifdef CONDITIONAL_REGISTER_USAGE
+  CONDITIONAL_REGISTER_USAGE;
+#endif
+
   /* Compute number of hard regs in each class.  */
 
   bzero ((char *) reg_class_size, sizeof reg_class_size);
@@ -336,25 +358,6 @@ init_reg_sets ()
        }
     }
 
-  /* Do any additional initialization regsets may need */
-  INIT_ONCE_REG_SET ();
-}
-
-/* After switches have been processed, which perhaps alter
-   `fixed_regs' and `call_used_regs', convert them to HARD_REG_SETs.  */
-
-static void
-init_reg_sets_1 ()
-{
-  register unsigned int i, j;
-
-  /* This macro allows the fixed or call-used registers
-     to depend on target flags.  */
-
-#ifdef CONDITIONAL_REGISTER_USAGE
-  CONDITIONAL_REGISTER_USAGE;
-#endif
-
   /* Initialize "constant" tables.  */
 
   CLEAR_HARD_REG_SET (fixed_reg_set);
@@ -584,8 +587,8 @@ fix_register (name, fixed, call_used)
          && (fixed == 0 || call_used == 0))
        {
          static char* what_option[2][2] = {
-           "call-saved", "call-used", 
-           "no-such-option", "fixed" };
+           { "call-saved", "call-used" },
+           { "no-such-option", "fixed" }};
          
          error ("can't use '%s' as a %s register", name, 
                 what_option[fixed][call_used]);
@@ -688,10 +691,9 @@ static int loop_depth;
 
 static int loop_cost;
 
-static int n_occurrences       PROTO((int, char *));
 static rtx scan_one_insn       PROTO((rtx, int));
 static void record_reg_classes PROTO((int, int, rtx *, enum machine_mode *,
-                                      char **, rtx));
+                                      const char **, rtx));
 static int copy_cost           PROTO((rtx, enum machine_mode, 
                                       enum reg_class, int));
 static void record_address_regs        PROTO((rtx, enum reg_class, int));
@@ -739,18 +741,6 @@ regclass_init ()
   prefclass = 0;
 }
 \f
-/* Return the number of times character C occurs in string S.  */
-static int
-n_occurrences (c, s)
-     int c;
-     char *s;
-{
-  int n = 0;
-  while (*s)
-    n += (*s++ == c);
-  return n;
-}
-
 /* Subroutine of regclass, processes one insn INSN.  Scan it and record each
    time it would save code to put a certain register in a certain class.
    PASS, when nonzero, inhibits some optimizations which need only be done
@@ -765,12 +755,9 @@ scan_one_insn (insn, pass)
 {
   enum rtx_code code = GET_CODE (insn);
   enum rtx_code pat_code;
-
-  char *constraints[MAX_RECOG_OPERANDS];
+  const char *constraints[MAX_RECOG_OPERANDS];
   enum machine_mode modes[MAX_RECOG_OPERANDS];
-  int nalternatives;
-  int noperands;
-  rtx set;
+  rtx set, note;
   int i, j;
 
   /* Show that an insn inside a loop is likely to be executed three
@@ -799,106 +786,88 @@ scan_one_insn (insn, pass)
       || pat_code == ADDR_DIFF_VEC)
     return insn;
 
-  if (code == INSN
-      && (noperands = asm_noperands (PATTERN (insn))) >= 0)
+  set = single_set (insn);
+  extract_insn (insn);
+
+  for (i = 0; i < recog_n_operands; i++)
     {
-      decode_asm_operands (PATTERN (insn), recog_operand, NULL_PTR,
-                          constraints, modes);
-      nalternatives = (noperands == 0 ? 0
-                      : n_occurrences (',', constraints[0]) + 1);
+      constraints[i] = recog_constraints[i];
+      modes[i] = recog_operand_mode[i];
     }
-  else
-    {
-      int insn_code_number = recog_memoized (insn);
-      rtx note;
 
-      set = single_set (insn);
-      insn_extract (insn);
+  /* If this insn loads a parameter from its stack slot, then
+     it represents a savings, rather than a cost, if the
+     parameter is stored in memory.  Record this fact.  */
 
-      nalternatives = insn_n_alternatives[insn_code_number];
-      noperands = insn_n_operands[insn_code_number];
+  if (set != 0 && GET_CODE (SET_DEST (set)) == REG
+      && GET_CODE (SET_SRC (set)) == MEM
+      && (note = find_reg_note (insn, REG_EQUIV,
+                               NULL_RTX)) != 0
+      && GET_CODE (XEXP (note, 0)) == MEM)
+    {
+      costs[REGNO (SET_DEST (set))].mem_cost
+       -= (MEMORY_MOVE_COST (GET_MODE (SET_DEST (set)),
+                             GENERAL_REGS, 1)
+           * loop_cost);
+      record_address_regs (XEXP (SET_SRC (set), 0),
+                          BASE_REG_CLASS, loop_cost * 2);
+      return insn;
+    }
 
-      /* If this insn loads a parameter from its stack slot, then
-        it represents a savings, rather than a cost, if the
-        parameter is stored in memory.  Record this fact.  */
+  /* Improve handling of two-address insns such as
+     (set X (ashift CONST Y)) where CONST must be made to
+     match X. Change it into two insns: (set X CONST)
+     (set X (ashift X Y)).  If we left this for reloading, it
+     would probably get three insns because X and Y might go
+     in the same place. This prevents X and Y from receiving
+     the same hard reg.
+
+     We can only do this if the modes of operands 0 and 1
+     (which might not be the same) are tieable and we only need
+     do this during our first pass.  */
+
+  if (pass == 0 && optimize
+      && recog_n_operands >= 3
+      && recog_constraints[1][0] == '0'
+      && recog_constraints[1][1] == 0
+      && CONSTANT_P (recog_operand[1])
+      && ! rtx_equal_p (recog_operand[0], recog_operand[1])
+      && ! rtx_equal_p (recog_operand[0], recog_operand[2])
+      && GET_CODE (recog_operand[0]) == REG
+      && MODES_TIEABLE_P (GET_MODE (recog_operand[0]),
+                         recog_operand_mode[1]))
+    {
+      rtx previnsn = prev_real_insn (insn);
+      rtx dest
+       = gen_lowpart (recog_operand_mode[1],
+                      recog_operand[0]);
+      rtx newinsn
+       = emit_insn_before (gen_move_insn (dest,
+                                          recog_operand[1]),
+                           insn);
 
-      if (set != 0 && GET_CODE (SET_DEST (set)) == REG
-         && GET_CODE (SET_SRC (set)) == MEM
-         && (note = find_reg_note (insn, REG_EQUIV,
-                                   NULL_RTX)) != 0
-         && GET_CODE (XEXP (note, 0)) == MEM)
+      /* If this insn was the start of a basic block,
+        include the new insn in that block.
+        We need not check for code_label here;
+        while a basic block can start with a code_label,
+        INSN could not be at the beginning of that block.  */
+      if (previnsn == 0 || GET_CODE (previnsn) == JUMP_INSN)
        {
-         costs[REGNO (SET_DEST (set))].mem_cost
-           -= (MEMORY_MOVE_COST (GET_MODE (SET_DEST (set)),
-                                 GENERAL_REGS, 1)
-               * loop_cost);
-         record_address_regs (XEXP (SET_SRC (set), 0),
-                              BASE_REG_CLASS, loop_cost * 2);
-         return insn;
+         int b;
+         for (b = 0; b < n_basic_blocks; b++)
+           if (insn == BLOCK_HEAD (b))
+             BLOCK_HEAD (b) = newinsn;
        }
 
-      /* Improve handling of two-address insns such as
-        (set X (ashift CONST Y)) where CONST must be made to
-        match X. Change it into two insns: (set X CONST)
-        (set X (ashift X Y)).  If we left this for reloading, it
-        would probably get three insns because X and Y might go
-        in the same place. This prevents X and Y from receiving
-        the same hard reg.
-
-        We can only do this if the modes of operands 0 and 1
-        (which might not be the same) are tieable and we only need
-        do this during our first pass.  */
-
-      if (pass == 0 && optimize
-         && noperands >= 3
-         && insn_operand_constraint[insn_code_number][1][0] == '0'
-         && insn_operand_constraint[insn_code_number][1][1] == 0
-         && CONSTANT_P (recog_operand[1])
-         && ! rtx_equal_p (recog_operand[0], recog_operand[1])
-         && ! rtx_equal_p (recog_operand[0], recog_operand[2])
-         && GET_CODE (recog_operand[0]) == REG
-         && MODES_TIEABLE_P (GET_MODE (recog_operand[0]),
-                             insn_operand_mode[insn_code_number][1]))
-       {
-         rtx previnsn = prev_real_insn (insn);
-         rtx dest
-           = gen_lowpart (insn_operand_mode[insn_code_number][1],
-                          recog_operand[0]);
-         rtx newinsn
-           = emit_insn_before (gen_move_insn (dest,
-                                              recog_operand[1]),
-                               insn);
-
-         /* If this insn was the start of a basic block,
-            include the new insn in that block.
-            We need not check for code_label here;
-            while a basic block can start with a code_label,
-            INSN could not be at the beginning of that block.  */
-         if (previnsn == 0 || GET_CODE (previnsn) == JUMP_INSN)
-           {
-             int b;
-             for (b = 0; b < n_basic_blocks; b++)
-               if (insn == basic_block_head[b])
-                 basic_block_head[b] = newinsn;
-           }
-
-         /* This makes one more setting of new insns's dest.  */
-         REG_N_SETS (REGNO (recog_operand[0]))++;
+      /* This makes one more setting of new insns's dest.  */
+      REG_N_SETS (REGNO (recog_operand[0]))++;
 
-         *recog_operand_loc[1] = recog_operand[0];
-         for (i = insn_n_dups[insn_code_number] - 1; i >= 0; i--)
-           if (recog_dup_num[i] == 1)
-             *recog_dup_loc[i] = recog_operand[0];
-
-         return PREV_INSN (newinsn);
-       }
+      *recog_operand_loc[1] = recog_operand[0];
+      for (i = recog_n_dups - 1; i >= 0; i--)
+       if (recog_dup_num[i] == 1)
+         *recog_dup_loc[i] = recog_operand[0];
 
-      for (i = 0; i < noperands; i++)
-       {
-         constraints[i]
-           = insn_operand_constraint[insn_code_number][i];
-         modes[i] = insn_operand_mode[insn_code_number][i];
-       }
+      return PREV_INSN (newinsn);
     }
 
   /* If we get here, we are set up to record the costs of all the
@@ -907,7 +876,7 @@ scan_one_insn (insn, pass)
      classes for any pseudos, doing it twice if some pair of
      operands are commutative.  */
             
-  for (i = 0; i < noperands; i++)
+  for (i = 0; i < recog_n_operands; i++)
     {
       op_costs[i] = init_cost;
 
@@ -926,32 +895,32 @@ scan_one_insn (insn, pass)
      have been initialized.  We must do this even if one operand
      is a constant--see addsi3 in m68k.md.  */
 
-  for (i = 0; i < noperands - 1; i++)
+  for (i = 0; i < recog_n_operands - 1; i++)
     if (constraints[i][0] == '%')
       {
-       char *xconstraints[MAX_RECOG_OPERANDS];
+       const char *xconstraints[MAX_RECOG_OPERANDS];
        int j;
 
        /* Handle commutative operands by swapping the constraints.
           We assume the modes are the same.  */
 
-       for (j = 0; j < noperands; j++)
+       for (j = 0; j < recog_n_operands; j++)
          xconstraints[j] = constraints[j];
 
        xconstraints[i] = constraints[i+1];
        xconstraints[i+1] = constraints[i];
-       record_reg_classes (nalternatives, noperands,
+       record_reg_classes (recog_n_alternatives, recog_n_operands,
                            recog_operand, modes, xconstraints,
                            insn);
       }
 
-  record_reg_classes (nalternatives, noperands, recog_operand,
+  record_reg_classes (recog_n_alternatives, recog_n_operands, recog_operand,
                      modes, constraints, insn);
 
   /* Now add the cost for each operand to the total costs for
      its register.  */
 
-  for (i = 0; i < noperands; i++)
+  for (i = 0; i < recog_n_operands; i++)
     if (GET_CODE (recog_operand[i]) == REG
        && REGNO (recog_operand[i]) >= FIRST_PSEUDO_REGISTER)
       {
@@ -998,6 +967,7 @@ regclass (f, nregs)
     {
       rtx r = gen_rtx_REG (VOIDmode, 0);
       enum machine_mode m;
+      register int j;
 
       for (j = 0; j < FIRST_PSEUDO_REGISTER; j++)
        if (TEST_HARD_REG_BIT (reg_class_contents[i], j))
@@ -1166,19 +1136,13 @@ record_reg_classes (n_alts, n_ops, ops, modes, constraints, insn)
      int n_ops;
      rtx *ops;
      enum machine_mode *modes;
-     char **constraints;
+     const char **constraints;
      rtx insn;
 {
   int alt;
-  enum op_type {OP_READ, OP_WRITE, OP_READ_WRITE} op_types[MAX_RECOG_OPERANDS];
   int i, j;
   rtx set;
 
-  /* By default, each operand is an input operand.  */
-
-  for (i = 0; i < n_ops; i++)
-    op_types[i] = OP_READ;
-
   /* Process each alternative, each time minimizing an operand's cost with
      the cost for each operand in that alternative.  */
 
@@ -1192,13 +1156,17 @@ record_reg_classes (n_alts, n_ops, ops, modes, constraints, insn)
 
       for (i = 0; i < n_ops; i++)
        {
-         char *p = constraints[i];
+         const char *p = constraints[i];
          rtx op = ops[i];
          enum machine_mode mode = modes[i];
+         int allows_addr = 0;
          int allows_mem = 0;
          int win = 0;
          unsigned char c;
 
+         /* Initially show we know nothing about the register class.  */
+         classes[i] = NO_REGS;
+
          /* If this operand has no constraints at all, we can conclude 
             nothing about it since anything is valid.  */
 
@@ -1210,12 +1178,13 @@ record_reg_classes (n_alts, n_ops, ops, modes, constraints, insn)
              continue;
            }
 
-         if (*p == '%')
-           p++;
-
          /* If this alternative is only relevant when this operand
             matches a previous operand, we do different things depending
-            on whether this operand is a pseudo-reg or not.  */
+            on whether this operand is a pseudo-reg or not.  We must process
+            any modifiers for the operand before we can make this test.  */
+
+         while (*p == '%' || *p == '=' || *p == '+' || *p == '&')
+           p++;
 
          if (p[0] >= '0' && p[0] <= '0' + i && (p[1] == ',' || p[1] == 0))
            {
@@ -1281,18 +1250,9 @@ record_reg_classes (n_alts, n_ops, ops, modes, constraints, insn)
             any of the constraints.  Collect the valid register classes
             and see if this operand accepts memory.  */
 
-         classes[i] = NO_REGS;
          while (*p && (c = *p++) != ',')
            switch (c)
              {
-             case '=':
-               op_types[i] = OP_WRITE;
-               break;
-
-             case '+':
-               op_types[i] = OP_READ_WRITE;
-               break;
-
              case '*':
                /* Ignore the next letter for this pass.  */
                p++;
@@ -1300,11 +1260,14 @@ record_reg_classes (n_alts, n_ops, ops, modes, constraints, insn)
 
              case '?':
                alt_cost += 2;
-             case '%':
-             case '!':  case '#':
-             case '&':
+             case '!':  case '#':  case '&':
              case '0':  case '1':  case '2':  case '3':  case '4':
+             case '5':  case '6':  case '7':  case '8':  case '9':
+               break;
+
              case 'p':
+               allows_addr = 1;
+               win = address_operand (op, GET_MODE (op));
                break;
 
              case 'm':  case 'o':  case 'V':
@@ -1435,7 +1398,10 @@ record_reg_classes (n_alts, n_ops, ops, modes, constraints, insn)
          if (GET_CODE (op) == REG && REGNO (op) >= FIRST_PSEUDO_REGISTER)
            {
              if (classes[i] == NO_REGS)
-               alt_fail = 1;
+               {
+                 if (! allows_addr)
+                   alt_fail = 1;
+               }
              else
                {
                  struct costs *pp = &this_op_costs[i];
@@ -1475,17 +1441,17 @@ record_reg_classes (n_alts, n_ops, ops, modes, constraints, insn)
 
          else if (classes[i] != NO_REGS)
            {
-             if (op_types[i] != OP_WRITE)
+             if (recog_op_type[i] != OP_OUT)
                alt_cost += copy_cost (op, mode, classes[i], 1);
 
-             if (op_types[i] != OP_READ)
+             if (recog_op_type[i] != OP_IN)
                alt_cost += copy_cost (op, mode, classes[i], 0);
            }
 
          /* The only other way this alternative can be used is if this is a
             constant that could be placed into memory.  */
 
-         else if (CONSTANT_P (op) && allows_mem)
+         else if (CONSTANT_P (op) && (allows_addr || allows_mem))
            alt_cost += MEMORY_MOVE_COST (mode, classes[i], 1);
          else
            alt_fail = 1;
@@ -1502,7 +1468,7 @@ record_reg_classes (n_alts, n_ops, ops, modes, constraints, insn)
            && REGNO (ops[i]) >= FIRST_PSEUDO_REGISTER)
          {
            struct costs *pp = &op_costs[i], *qq = &this_op_costs[i];
-           int scale = 1 + (op_types[i] == OP_READ_WRITE);
+           int scale = 1 + (recog_op_type[i] == OP_INOUT);
 
            pp->mem_cost = MIN (pp->mem_cost,
                                (qq->mem_cost + alt_cost) * scale);
@@ -1799,25 +1765,21 @@ auto_inc_dec_reg_p (reg, mode)
      rtx reg;
      enum machine_mode mode;
 {
-#ifdef HAVE_POST_INCREMENT
-  if (memory_address_p (mode, gen_rtx_POST_INC (Pmode, reg)))
+  if (HAVE_POST_INCREMENT
+      && memory_address_p (mode, gen_rtx_POST_INC (Pmode, reg)))
     return 1;
-#endif
 
-#ifdef HAVE_POST_DECREMENT
-  if (memory_address_p (mode, gen_rtx_POST_DEC (Pmode, reg)))
+  if (HAVE_POST_DECREMENT
+      && memory_address_p (mode, gen_rtx_POST_DEC (Pmode, reg)))
     return 1;
-#endif
 
-#ifdef HAVE_PRE_INCREMENT
-  if (memory_address_p (mode, gen_rtx_PRE_INC (Pmode, reg)))
+  if (HAVE_PRE_INCREMENT
+      && memory_address_p (mode, gen_rtx_PRE_INC (Pmode, reg)))
     return 1;
-#endif
 
-#ifdef HAVE_PRE_DECREMENT
-  if (memory_address_p (mode, gen_rtx_PRE_DEC (Pmode, reg)))
+  if (HAVE_PRE_DECREMENT
+      && memory_address_p (mode, gen_rtx_PRE_DEC (Pmode, reg)))
     return 1;
-#endif
 
   return 0;
 }
@@ -1825,6 +1787,9 @@ auto_inc_dec_reg_p (reg, mode)
 
 #endif /* REGISTER_CONSTRAINTS */
 \f
+static short *renumber = (short *)0;
+static size_t regno_allocated = 0;
+
 /* Allocate enough space to hold NUM_REGS registers for the tables used for
    reg_scan and flow_analysis that are indexed by the register number.  If
    NEW_P is non zero, initialize all of the registers, otherwise only
@@ -1838,39 +1803,12 @@ allocate_reg_info (num_regs, new_p, renumber_p)
      int new_p;
      int renumber_p;
 {
-  static size_t regno_allocated = 0;
-  static short *renumber = (short *)0;
-  int i;
   size_t size_info;
   size_t size_renumber;
   size_t min = (new_p) ? 0 : reg_n_max;
   struct reg_info_data *reg_data;
   struct reg_info_data *reg_next;
 
-  /* Free up all storage allocated */
-  if (num_regs < 0)
-    {
-      if (reg_n_info)
-       {
-         VARRAY_FREE (reg_n_info);
-         for (reg_data = reg_info_head; reg_data; reg_data = reg_next)
-           {
-             reg_next = reg_data->next;
-             free ((char *)reg_data);
-           }
-
-         free (prefclass_buffer);
-         free (altclass_buffer);
-         prefclass_buffer = (char *)0;
-         altclass_buffer = (char *)0;
-         reg_info_head = (struct reg_info_data *)0;
-         renumber = (short *)0;
-       }
-      regno_allocated = 0;
-      reg_n_max = 0;
-      return;
-    }
-
   if (num_regs > regno_allocated)
     {
       size_t old_allocated = regno_allocated;
@@ -1935,6 +1873,8 @@ allocate_reg_info (num_regs, new_p, renumber_p)
            {
              size_t max = max_index;
              size_t local_min = min - min_index;
+             size_t i;
+
              if (min < min_index)
                local_min = 0;
              if (!reg_data->used_p)    /* page just allocated with calloc */
@@ -1970,6 +1910,32 @@ allocate_reg_info (num_regs, new_p, renumber_p)
   MAX_REGNO_REG_SET (num_regs, new_p, renumber_p);
 }
 
+/* Free up the space allocated by allocate_reg_info.  */
+void
+free_reg_info ()
+{
+  if (reg_n_info)
+    {
+      struct reg_info_data *reg_data;
+      struct reg_info_data *reg_next;
+
+      VARRAY_FREE (reg_n_info);
+      for (reg_data = reg_info_head; reg_data; reg_data = reg_next)
+       {
+         reg_next = reg_data->next;
+         free ((char *)reg_data);
+       }
+
+      free (prefclass_buffer);
+      free (altclass_buffer);
+      prefclass_buffer = (char *)0;
+      altclass_buffer = (char *)0;
+      reg_info_head = (struct reg_info_data *)0;
+      renumber = (short *)0;
+    }
+  regno_allocated = 0;
+  reg_n_max = 0;
+}
 \f
 /* This is the `regscan' pass of the compiler, run just before cse
    and again just before loop.
@@ -2061,8 +2027,8 @@ reg_scan_mark_refs (x, insn, note_flag, min_regno)
   code = GET_CODE (x);
   switch (code)
     {
-    case CONST_INT:
     case CONST:
+    case CONST_INT:
     case CONST_DOUBLE:
     case CC0:
     case PC: