OSDN Git Service

* (REG_CLASS_FROM_CONSTRAINT): Only define if not already defined.
[pf3gnuchains/gcc-fork.git] / gcc / recog.c
index c56069a..8ea1e8d 100644 (file)
@@ -1,6 +1,6 @@
 /* Subroutines used by or related to instruction recognition.
    Copyright (C) 1987, 1988, 1991, 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.
 
@@ -22,6 +22,8 @@ Software Foundation, 59 Temple Place - Suite 330, Boston, MA
 
 #include "config.h"
 #include "system.h"
+#include "coretypes.h"
+#include "tm.h"
 #include "rtl.h"
 #include "tm_p.h"
 #include "insn-config.h"
@@ -191,7 +193,7 @@ static int num_changes = 0;
    an INSN, CALL_INSN, or JUMP_INSN, the insn will be re-recognized with
    the change in place.
 
-   IN_GROUP is non-zero if this is part of a group of changes that must be
+   IN_GROUP is nonzero if this is part of a group of changes that must be
    performed as a group.  In that case, the changes will be stored.  The
    function `apply_change_group' will validate and apply the changes.
 
@@ -522,10 +524,10 @@ validate_replace_rtx_1 (loc, from, to, object)
     {
     case PLUS:
       /* If we have a PLUS whose second operand is now a CONST_INT, use
-         plus_constant to try to simplify it.
+         simplify_gen_binary to try to simplify it.
          ??? We may want later to remove this, once simplification is
          separated from this function.  */
-      if (GET_CODE (XEXP (x, 1)) == CONST_INT)
+      if (GET_CODE (XEXP (x, 1)) == CONST_INT && XEXP (x, 1) == to)
        validate_change (object, loc,
                         simplify_gen_binary
                         (PLUS, GET_MODE (x), XEXP (x, 0), XEXP (x, 1)), 1);
@@ -692,7 +694,7 @@ validate_replace_src_group (from, to, insn)
   note_uses (&PATTERN (insn), validate_replace_src_1, &d);
 }
 
-/* Same as validate_repalace_src_group, but validate by seeing if
+/* Same as validate_replace_src_group, but validate by seeing if
    INSN is still valid.  */
 int
 validate_replace_src (from, to, insn)
@@ -856,7 +858,7 @@ find_single_use_1 (dest, loc)
    sequel.  If so, return a pointer to the innermost rtx expression in which
    it is used.
 
-   If PLOC is non-zero, *PLOC is set to the insn containing the single use.
+   If PLOC is nonzero, *PLOC is set to the insn containing the single use.
 
    This routine will return usually zero either before flow is called (because
    there will be no LOG_LINKS notes) or after reload (because the REG_DEAD
@@ -954,6 +956,7 @@ general_operand (op, mode)
     return 0;
 
   if (GET_CODE (op) == CONST_INT
+      && mode != VOIDmode
       && trunc_int_for_mode (INTVAL (op), mode) != INTVAL (op))
     return 0;
 
@@ -1082,13 +1085,10 @@ register_operand (op, mode)
       if (! reload_completed && GET_CODE (sub) == MEM)
        return general_operand (op, mode);
 
-#ifdef CLASS_CANNOT_CHANGE_MODE
+#ifdef CANNOT_CHANGE_MODE_CLASS
       if (GET_CODE (sub) == REG
          && REGNO (sub) < FIRST_PSEUDO_REGISTER
-         && (TEST_HARD_REG_BIT
-             (reg_class_contents[(int) CLASS_CANNOT_CHANGE_MODE],
-              REGNO (sub)))
-         && CLASS_CANNOT_CHANGE_MODE_P (mode, GET_MODE (sub))
+         && REG_CANNOT_CHANGE_MODE_P (REGNO (sub), GET_MODE (sub), mode)
          && GET_MODE_CLASS (GET_MODE (sub)) != MODE_COMPLEX_INT
          && GET_MODE_CLASS (GET_MODE (sub)) != MODE_COMPLEX_FLOAT)
        return 0;
@@ -1159,6 +1159,7 @@ immediate_operand (op, mode)
     return 0;
 
   if (GET_CODE (op) == CONST_INT
+      && mode != VOIDmode
       && trunc_int_for_mode (INTVAL (op), mode) != INTVAL (op))
     return 0;
 
@@ -1241,6 +1242,7 @@ nonmemory_operand (op, mode)
        return 0;
 
       if (GET_CODE (op) == CONST_INT
+         && mode != VOIDmode
          && trunc_int_for_mode (INTVAL (op), mode) != INTVAL (op))
        return 0;
 
@@ -1314,7 +1316,7 @@ push_operand (op, mode)
 #ifdef STACK_GROWS_DOWNWARD
          || INTVAL (XEXP (XEXP (op, 1), 1)) != - (int) rounded_size
 #else
-         || INTVAL (XEXP (XEXP (op, 1), 1)) != rounded_size
+         || INTVAL (XEXP (XEXP (op, 1), 1)) != (int) rounded_size
 #endif
          )
        return 0;
@@ -1679,18 +1681,21 @@ asm_operand_ok (op, constraint)
 
   while (*constraint)
     {
-      char c = *constraint++;
+      char c = *constraint;
+      int len;
       switch (c)
        {
+       case ',':
+         constraint++;
+         continue;
        case '=':
        case '+':
        case '*':
        case '%':
-       case '?':
        case '!':
        case '#':
        case '&':
-       case ',':
+       case '?':
          break;
 
        case '0': case '1': case '2': case '3': case '4':
@@ -1699,25 +1704,27 @@ asm_operand_ok (op, constraint)
             proper matching constraint, but we can't actually fail
             the check if they didn't.  Indicate that results are
             inconclusive.  */
-         while (ISDIGIT (*constraint))
+         do
            constraint++;
-         result = -1;
-         break;
+         while (ISDIGIT (*constraint));
+         if (! result)
+           result = -1;
+         continue;
 
        case 'p':
          if (address_operand (op, VOIDmode))
-           return 1;
+           result = 1;
          break;
 
        case 'm':
        case 'V': /* non-offsettable */
          if (memory_operand (op, VOIDmode))
-           return 1;
+           result = 1;
          break;
 
        case 'o': /* offsettable */
          if (offsettable_nonstrict_memref_p (op))
-           return 1;
+           result = 1;
          break;
 
        case '<':
@@ -1732,7 +1739,7 @@ asm_operand_ok (op, constraint)
              && (1
                  || GET_CODE (XEXP (op, 0)) == PRE_DEC
                  || GET_CODE (XEXP (op, 0)) == POST_DEC))
-           return 1;
+           result = 1;
          break;
 
        case '>':
@@ -1740,7 +1747,7 @@ asm_operand_ok (op, constraint)
              && (1
                  || GET_CODE (XEXP (op, 0)) == PRE_INC
                  || GET_CODE (XEXP (op, 0)) == POST_INC))
-           return 1;
+           result = 1;
          break;
 
        case 'E':
@@ -1748,18 +1755,18 @@ asm_operand_ok (op, constraint)
          if (GET_CODE (op) == CONST_DOUBLE
              || (GET_CODE (op) == CONST_VECTOR
                  && GET_MODE_CLASS (GET_MODE (op)) == MODE_VECTOR_FLOAT))
-           return 1;
+           result = 1;
          break;
 
        case 'G':
          if (GET_CODE (op) == CONST_DOUBLE
-             && CONST_DOUBLE_OK_FOR_LETTER_P (op, 'G'))
-           return 1;
+             && CONST_DOUBLE_OK_FOR_CONSTRAINT_P (op, 'G', constraint))
+           result = 1;
          break;
        case 'H':
          if (GET_CODE (op) == CONST_DOUBLE
-             && CONST_DOUBLE_OK_FOR_LETTER_P (op, 'H'))
-           return 1;
+             && CONST_DOUBLE_OK_FOR_CONSTRAINT_P (op, 'H', constraint))
+           result = 1;
          break;
 
        case 's':
@@ -1775,82 +1782,100 @@ asm_operand_ok (op, constraint)
              && (! flag_pic || LEGITIMATE_PIC_OPERAND_P (op))
 #endif
              )
-           return 1;
+           result = 1;
          break;
 
        case 'n':
          if (GET_CODE (op) == CONST_INT
              || (GET_CODE (op) == CONST_DOUBLE
                  && GET_MODE (op) == VOIDmode))
-           return 1;
+           result = 1;
          break;
 
        case 'I':
          if (GET_CODE (op) == CONST_INT
-             && CONST_OK_FOR_LETTER_P (INTVAL (op), 'I'))
-           return 1;
+             && CONST_OK_FOR_CONSTRAINT_P (INTVAL (op), 'I', constraint))
+           result = 1;
          break;
        case 'J':
          if (GET_CODE (op) == CONST_INT
-             && CONST_OK_FOR_LETTER_P (INTVAL (op), 'J'))
-           return 1;
+             && CONST_OK_FOR_CONSTRAINT_P (INTVAL (op), 'J', constraint))
+           result = 1;
          break;
        case 'K':
          if (GET_CODE (op) == CONST_INT
-             && CONST_OK_FOR_LETTER_P (INTVAL (op), 'K'))
-           return 1;
+             && CONST_OK_FOR_CONSTRAINT_P (INTVAL (op), 'K', constraint))
+           result = 1;
          break;
        case 'L':
          if (GET_CODE (op) == CONST_INT
-             && CONST_OK_FOR_LETTER_P (INTVAL (op), 'L'))
-           return 1;
+             && CONST_OK_FOR_CONSTRAINT_P (INTVAL (op), 'L', constraint))
+           result = 1;
          break;
        case 'M':
          if (GET_CODE (op) == CONST_INT
-             && CONST_OK_FOR_LETTER_P (INTVAL (op), 'M'))
-           return 1;
+             && CONST_OK_FOR_CONSTRAINT_P (INTVAL (op), 'M', constraint))
+           result = 1;
          break;
        case 'N':
          if (GET_CODE (op) == CONST_INT
-             && CONST_OK_FOR_LETTER_P (INTVAL (op), 'N'))
-           return 1;
+             && CONST_OK_FOR_CONSTRAINT_P (INTVAL (op), 'N', constraint))
+           result = 1;
          break;
        case 'O':
          if (GET_CODE (op) == CONST_INT
-             && CONST_OK_FOR_LETTER_P (INTVAL (op), 'O'))
-           return 1;
+             && CONST_OK_FOR_CONSTRAINT_P (INTVAL (op), 'O', constraint))
+           result = 1;
          break;
        case 'P':
          if (GET_CODE (op) == CONST_INT
-             && CONST_OK_FOR_LETTER_P (INTVAL (op), 'P'))
-           return 1;
+             && CONST_OK_FOR_CONSTRAINT_P (INTVAL (op), 'P', constraint))
+           result = 1;
          break;
 
        case 'X':
-         return 1;
+         result = 1;
 
        case 'g':
          if (general_operand (op, VOIDmode))
-           return 1;
+           result = 1;
          break;
 
        default:
          /* For all other letters, we first check for a register class,
             otherwise it is an EXTRA_CONSTRAINT.  */
-         if (REG_CLASS_FROM_LETTER (c) != NO_REGS)
+         if (REG_CLASS_FROM_CONSTRAINT (c, constraint) != NO_REGS)
            {
            case 'r':
              if (GET_MODE (op) == BLKmode)
                break;
              if (register_operand (op, VOIDmode))
-               return 1;
+               result = 1;
+           }
+#ifdef EXTRA_CONSTRAINT_STR
+         if (EXTRA_CONSTRAINT_STR (op, c, constraint))
+           result = 1;
+         if (EXTRA_MEMORY_CONSTRAINT (c, constraint))
+           {
+             /* Every memory operand can be reloaded to fit.  */
+             if (memory_operand (op, VOIDmode))
+               result = 1;
+           }
+         if (EXTRA_ADDRESS_CONSTRAINT (c, constraint))
+           {
+             /* Every address operand can be reloaded to fit.  */
+             if (address_operand (op, VOIDmode))
+               result = 1;
            }
-#ifdef EXTRA_CONSTRAINT
-         if (EXTRA_CONSTRAINT (op, c))
-           return 1;
 #endif
          break;
        }
+      len = CONSTRAINT_LEN (c, constraint);
+      do
+       constraint++;
+      while (--len && *constraint);
+      if (len)
+       return 0;
     }
 
   return result;
@@ -2219,13 +2244,16 @@ preprocess_constraints ()
 
          for (;;)
            {
-             char c = *p++;
+             char c = *p;
              if (c == '#')
                do
-                 c = *p++;
+                 c = *++p;
                while (c != ',' && c != '\0');
              if (c == ',' || c == '\0')
-               break;
+               {
+                 p++;
+                 break;
+               }
 
              switch (c)
                {
@@ -2251,11 +2279,11 @@ preprocess_constraints ()
                case '5': case '6': case '7': case '8': case '9':
                  {
                    char *end;
-                   op_alt[j].matches = strtoul (p - 1, &end, 10);
+                   op_alt[j].matches = strtoul (p, &end, 10);
                    recog_op_alt[op_alt[j].matches][j].matched = i;
                    p = end;
                  }
-                 break;
+                 continue;
 
                case 'm':
                  op_alt[j].memory_ok = 1;
@@ -2287,9 +2315,28 @@ preprocess_constraints ()
                  break;
 
                default:
-                 op_alt[j].class = reg_class_subunion[(int) op_alt[j].class][(int) REG_CLASS_FROM_LETTER ((unsigned char) c)];
+                 if (EXTRA_MEMORY_CONSTRAINT (c, p))
+                   {
+                     op_alt[j].memory_ok = 1;
+                     break;
+                   }
+                 if (EXTRA_ADDRESS_CONSTRAINT (c, p))
+                   {
+                     op_alt[j].is_address = 1;
+                     op_alt[j].class
+                       = (reg_class_subunion
+                          [(int) op_alt[j].class]
+                          [(int) MODE_BASE_REG_CLASS (VOIDmode)]);
+                     break;
+                   }
+
+                 op_alt[j].class
+                   = (reg_class_subunion
+                      [(int) op_alt[j].class]
+                      [(int) REG_CLASS_FROM_CONSTRAINT ((unsigned char) c, p)]);
                  break;
                }
+             p += CONSTRAINT_LEN (c, p);
            }
        }
     }
@@ -2304,7 +2351,7 @@ preprocess_constraints ()
    alternative of constraints was matched: 0 for the first alternative,
    1 for the next, etc.
 
-   In addition, when two operands are match
+   In addition, when two operands are required to match
    and it happens that the output operand is (reg) while the
    input operand is --(reg) or ++(reg) (a pre-inc or pre-dec),
    make the output operand look like the input.
@@ -2313,7 +2360,7 @@ preprocess_constraints ()
    This is used in final, just before printing the assembler code and by
    the routines that determine an insn's attribute.
 
-   If STRICT is a positive non-zero value, it means that we have been
+   If STRICT is a positive nonzero value, it means that we have been
    called after reload has been completed.  In that case, we must
    do all checks strictly.  If it is zero, it means that we have been called
    before reload has completed.  In that case, we first try to see if we can
@@ -2363,6 +2410,7 @@ constrain_operands (strict)
          int offset = 0;
          int win = 0;
          int val;
+         int len;
 
          earlyclobber[opno] = 0;
 
@@ -2387,9 +2435,16 @@ constrain_operands (strict)
          if (*p == 0 || *p == ',')
            win = 1;
 
-         while (*p && (c = *p++) != ',')
-           switch (c)
+         do
+           switch (c = *p, len = CONSTRAINT_LEN (c, p), c)
              {
+             case '\0':
+               len = 0;
+               break;
+             case ',':
+               c = '\0';
+               break;
+
              case '?':  case '!': case '*':  case '%':
              case '=':  case '+':
                break;
@@ -2397,8 +2452,10 @@ constrain_operands (strict)
              case '#':
                /* Ignore rest of this alternative as far as
                   constraint checking is concerned.  */
-               while (*p && *p != ',')
+               do
                  p++;
+               while (*p && *p != ',');
+               len = 0;
                break;
 
              case '&':
@@ -2420,7 +2477,7 @@ constrain_operands (strict)
                  char *end;
                  int match;
 
-                 match = strtoul (p - 1, &end, 10);
+                 match = strtoul (p, &end, 10);
                  p = end;
 
                  if (strict < 0)
@@ -2455,6 +2512,7 @@ constrain_operands (strict)
                      funny_match[funny_match_index++].other = match;
                    }
                }
+               len = 0;
                break;
 
              case 'p':
@@ -2524,7 +2582,7 @@ constrain_operands (strict)
              case 'G':
              case 'H':
                if (GET_CODE (op) == CONST_DOUBLE
-                   && CONST_DOUBLE_OK_FOR_LETTER_P (op, c))
+                   && CONST_DOUBLE_OK_FOR_CONSTRAINT_P (op, c, p))
                  win = 1;
                break;
 
@@ -2554,7 +2612,7 @@ constrain_operands (strict)
              case 'O':
              case 'P':
                if (GET_CODE (op) == CONST_INT
-                   && CONST_OK_FOR_LETTER_P (INTVAL (op), c))
+                   && CONST_OK_FOR_CONSTRAINT_P (INTVAL (op), c, p))
                  win = 1;
                break;
 
@@ -2585,7 +2643,8 @@ constrain_operands (strict)
                {
                  enum reg_class class;
 
-                 class = (c == 'r' ? GENERAL_REGS : REG_CLASS_FROM_LETTER (c));
+                 class = (c == 'r'
+                          ? GENERAL_REGS : REG_CLASS_FROM_CONSTRAINT (c, p));
                  if (class != NO_REGS)
                    {
                      if (strict < 0
@@ -2597,13 +2656,36 @@ constrain_operands (strict)
                              && reg_fits_class_p (op, class, offset, mode)))
                        win = 1;
                    }
-#ifdef EXTRA_CONSTRAINT
-                 else if (EXTRA_CONSTRAINT (op, c))
+#ifdef EXTRA_CONSTRAINT_STR
+                 else if (EXTRA_CONSTRAINT_STR (op, c, p))
                    win = 1;
+
+                 if (EXTRA_MEMORY_CONSTRAINT (c, p))
+                   {
+                     /* Every memory operand can be reloaded to fit.  */
+                     if (strict < 0 && GET_CODE (op) == MEM)
+                       win = 1;
+       
+                     /* Before reload, accept what reload can turn into mem.  */
+                     if (strict < 0 && CONSTANT_P (op))
+                       win = 1;
+
+                     /* During reload, accept a pseudo  */
+                     if (reload_in_progress && GET_CODE (op) == REG
+                         && REGNO (op) >= FIRST_PSEUDO_REGISTER)
+                       win = 1;
+                   }
+                 if (EXTRA_ADDRESS_CONSTRAINT (c, p))
+                   {
+                     /* Every address operand can be reloaded to fit.  */
+                     if (strict < 0)
+                       win = 1;
+                   }
 #endif
                  break;
                }
              }
+         while (p += len, c);
 
          constraints[opno] = p;
          /* If this operand did not win somehow,
@@ -2758,12 +2840,12 @@ split_all_insns (upd_life)
      int upd_life;
 {
   sbitmap blocks;
-  int changed;
+  bool changed;
   basic_block bb;
 
   blocks = sbitmap_alloc (last_basic_block);
   sbitmap_zero (blocks);
-  changed = 0;
+  changed = false;
 
   FOR_EACH_BB_REVERSE (bb)
     {
@@ -2788,7 +2870,7 @@ split_all_insns (upd_life)
              while (GET_CODE (last) == BARRIER)
                last = PREV_INSN (last);
              SET_BIT (blocks, bb->index);
-             changed = 1;
+             changed = true;
              insn = last;
            }
        }
@@ -2796,14 +2878,18 @@ split_all_insns (upd_life)
 
   if (changed)
     {
+      int old_last_basic_block = last_basic_block;
+
       find_many_sub_basic_blocks (blocks);
+
+      if (old_last_basic_block != last_basic_block && upd_life)
+       blocks = sbitmap_resize (blocks, last_basic_block, 1);
     }
 
   if (changed && upd_life)
-    {
-      count_or_remove_death_notes (blocks, 1);
-      update_life_info (blocks, UPDATE_LIFE_LOCAL, PROP_DEATH_NOTES);
-    }
+    update_life_info (blocks, UPDATE_LIFE_GLOBAL_RM_NOTES,
+                     PROP_DEATH_NOTES | PROP_REG_INFO);
+
 #ifdef ENABLE_CHECKING
   verify_flow_info ();
 #endif
@@ -2812,7 +2898,7 @@ split_all_insns (upd_life)
 }
 
 /* Same as split_all_insns, but do not expect CFG to be available.
-   Used by machine depedent reorg passes.  */
+   Used by machine dependent reorg passes.  */
 
 void
 split_all_insns_noflow ()
@@ -2960,7 +3046,7 @@ peep2_find_free_register (from, to, class_str, mode, reg_set)
     }
 
   class = (class_str[0] == 'r' ? GENERAL_REGS
-          : REG_CLASS_FROM_LETTER (class_str[0]));
+          : REG_CLASS_FROM_CONSTRAINT (class_str[0], class_str));
 
   for (i = 0; i < FIRST_PSEUDO_REGISTER; i++)
     {
@@ -3163,8 +3249,8 @@ peephole2_optimize (dump_file)
                                        REG_EH_REGION, NULL_RTX);
 
                  /* Replace the old sequence with the new.  */
-                 try = emit_insn_after_scope (try, peep2_insn_data[i].insn,
-                                              INSN_SCOPE (peep2_insn_data[i].insn));
+                 try = emit_insn_after_setloc (try, peep2_insn_data[i].insn,
+                                               INSN_LOCATOR (peep2_insn_data[i].insn));
                  before_try = PREV_INSN (insn);
                  delete_insn_chain (insn, peep2_insn_data[i].insn);