OSDN Git Service

[pf3gnuchains/gcc-fork.git] / gcc / recog.c
index 261bb4d..19bc3b2 100644 (file)
@@ -31,6 +31,7 @@ Boston, MA 02111-1307, USA.  */
 #include "hard-reg-set.h"
 #include "flags.h"
 #include "real.h"
+#include "toplev.h"
 
 #ifndef STACK_PUSH_CODE
 #ifdef STACK_GROWS_DOWNWARD
@@ -40,9 +41,10 @@ Boston, MA 02111-1307, USA.  */
 #endif
 #endif
 
-static void validate_replace_rtx_1 PROTO((rtx *, rtx, rtx, rtx));
-static rtx *find_single_use_1 PROTO((rtx, rtx *));
-static rtx *find_constant_term_loc PROTO((rtx *));
+static void validate_replace_rtx_1     PROTO((rtx *, rtx, rtx, rtx));
+static rtx *find_single_use_1          PROTO((rtx, rtx *));
+static rtx *find_constant_term_loc     PROTO((rtx *));
+static int insn_invalid_p              PROTO((rtx));
 
 /* Nonzero means allow operands to be volatile.
    This should be 0 if you are generating rtl, such as if you are calling
@@ -54,7 +56,8 @@ static rtx *find_constant_term_loc PROTO((rtx *));
 
 int volatile_ok;
 
-/* The following vectors hold the results from insn_extract.  */
+/* The next variables are set up by extract_insn.  The first four of them
+   are also set up during insn_extract.  */
 
 /* Indexed by N, gives value of operand N.  */
 rtx recog_operand[MAX_RECOG_OPERANDS];
@@ -70,9 +73,6 @@ rtx *recog_dup_loc[MAX_RECOG_OPERANDS];
    Nth duplicate-appearance of an operand.  */
 char recog_dup_num[MAX_RECOG_OPERANDS];
 
-
-/* The next variables are set up by extract_insn.  */
-
 /* The number of operands of the insn.  */
 int recog_n_operands;
 
@@ -88,11 +88,18 @@ enum machine_mode recog_operand_mode[MAX_RECOG_OPERANDS];
 /* Indexed by N, gives the constraint string for operand N.  */
 char *recog_constraints[MAX_RECOG_OPERANDS];
 
+/* Indexed by N, gives the type (in, out, inout) for operand N.  */
+enum op_type recog_op_type[MAX_RECOG_OPERANDS];
+
 #ifndef REGISTER_CONSTRAINTS
 /* Indexed by N, nonzero if operand N should be an address.  */
 char recog_operand_address_p[MAX_RECOG_OPERANDS];
 #endif
 
+/* Contains a vector of operand_alternative structures for every operand.
+   Set up by preprocess_constraints.  */
+struct operand_alternative recog_op_alt[MAX_RECOG_OPERANDS][MAX_RECOG_ALTERNATIVES];
+
 /* On return from `constrain_operands', indicate which alternative
    was satisfied.  */
 
@@ -252,6 +259,33 @@ validate_change (object, loc, new, in_group)
     return apply_change_group ();
 }
 
+/* This subroutine of apply_change_group verifies whether the changes to INSN
+   were valid; i.e. whether INSN can still be recognized.  */
+
+static int
+insn_invalid_p (insn)
+     rtx insn;
+{
+  int icode = recog_memoized (insn);
+  int is_asm = icode < 0 && asm_noperands (PATTERN (insn)) >= 0;
+
+  if (is_asm && ! check_asm_operands (PATTERN (insn)))
+    return 1;
+  if (! is_asm && icode < 0)
+    return 1;
+
+  /* After reload, verify that all constraints are satisfied.  */
+  if (reload_completed)
+    {
+      extract_insn (insn);
+
+      if (! constrain_operands (1))
+       return 1;
+    }
+
+  return 0;
+}
+
 /* Apply a group of changes previously issued with `validate_change'.
    Return 1 if all changes are valid, zero otherwise.  */
 
@@ -267,8 +301,7 @@ apply_change_group ()
      given a MEM and it still is a valid address, or if this is in insn
      and it is recognized.  In the latter case, if reload has completed,
      we also require that the operands meet the constraints for
-     the insn.  We do not allow modifying an ASM_OPERANDS after reload
-     has completed because verifying the constraints is too difficult.  */
+     the insn.  */
 
   for (i = 0; i < num_changes; i++)
     {
@@ -282,13 +315,7 @@ apply_change_group ()
          if (! memory_address_p (GET_MODE (object), XEXP (object, 0)))
            break;
        }
-      else if ((recog_memoized (object) < 0
-               && (asm_noperands (PATTERN (object)) < 0
-                   || ! check_asm_operands (PATTERN (object))
-                   || reload_completed))
-              || (reload_completed
-                  && (insn_extract (object),
-                      ! constrain_operands (INSN_CODE (object), 1))))
+      else if (insn_invalid_p (object))
        {
          rtx pat = PATTERN (object);
 
@@ -1728,7 +1755,6 @@ extract_insn (insn)
       recog_n_operands = noperands = asm_noperands (body);
       if (noperands >= 0)
        {
-         char *p;
          /* This insn is an `asm' with operands.  */
 
          /* expand_asm_operands makes sure there aren't too many operands.  */
@@ -1777,13 +1803,125 @@ extract_insn (insn)
          recog_operand_mode[i] = insn_operand_mode[icode][i];
        }
     }
+  for (i = 0; i < noperands; i++)
+    recog_op_type[i] = (recog_constraints[i][0] == '=' ? OP_OUT
+                       : recog_constraints[i][0] == '+' ? OP_INOUT
+                       : OP_IN);
+
+  if (recog_n_alternatives > MAX_RECOG_ALTERNATIVES)
+    abort ();
 }
 
+/* After calling extract_insn, you can use this function to extract some
+   information from the constraint strings into a more usable form.
+   The collected data is stored in recog_op_alt.  */
+void
+preprocess_constraints ()
+{
+  int i;
+
+  for (i = 0; i < recog_n_operands; i++)
+    {
+      int j;
+      struct operand_alternative *op_alt;
+      char *p = recog_constraints[i];
+
+      op_alt = recog_op_alt[i];
+
+      for (j = 0; j < recog_n_alternatives; j++)
+       {
+         op_alt[j].class = NO_REGS;
+         op_alt[j].constraint = p;
+         op_alt[j].matches = -1;
+         op_alt[j].matched = -1;
+
+         if (*p == '\0' || *p == ',')
+           {
+             op_alt[j].anything_ok = 1;
+             continue;
+           }
+
+         for (;;)
+           {
+             char c = *p++;
+             if (c == '#')
+               do
+                 c = *p++;
+               while (c != ',' && c != '\0');
+             if (c == ',' || c == '\0')
+               break;
+
+             switch (c)
+               {
+               case '=': case '+': case '*': case '%':
+               case 'E': case 'F': case 'G': case 'H':
+               case 's': case 'i': case 'n':
+               case 'I': case 'J': case 'K': case 'L':
+               case 'M': case 'N': case 'O': case 'P':
+#ifdef EXTRA_CONSTRAINT
+               case 'Q': case 'R': case 'S': case 'T': case 'U':
+#endif
+                 /* These don't say anything we care about.  */
+                 break;
+
+               case '?':
+                 op_alt[j].reject += 6;
+                 break;
+               case '!':
+                 op_alt[j].reject += 600;
+                 break;
+               case '&':
+                 op_alt[j].earlyclobber = 1;
+                 break;                  
+
+               case '0': case '1': case '2': case '3': case '4':
+               case '5': case '6': case '7': case '8': case '9':
+                 op_alt[j].matches = c - '0';
+                 op_alt[op_alt[j].matches].matched = i;
+                 break;
+
+               case 'm':
+                 op_alt[j].memory_ok = 1;
+                 break;
+               case '<':
+                 op_alt[j].decmem_ok = 1;
+                 break;
+               case '>':
+                 op_alt[j].incmem_ok = 1;
+                 break;
+               case 'V':
+                 op_alt[j].nonoffmem_ok = 1;
+                 break;
+               case 'o':
+                 op_alt[j].offmem_ok = 1;
+                 break;
+               case 'X':
+                 op_alt[j].anything_ok = 1;
+                 break;
+
+               case 'p':
+                 op_alt[j].class = reg_class_subunion[(int) op_alt[j].class][(int) BASE_REG_CLASS];
+                 break;
+
+               case 'g': case 'r':
+                 op_alt[j].class = reg_class_subunion[(int) op_alt[j].class][(int) GENERAL_REGS];
+                 break;
+
+               default:
+                 op_alt[j].class = reg_class_subunion[(int) op_alt[j].class][(int) REG_CLASS_FROM_LETTER (c)];
+                 break;
+               }
+           }
+       }
+    }
+}
 #ifdef REGISTER_CONSTRAINTS
 
-/* Check the operands of an insn (found in recog_operands)
-   against the insn's operand constraints (found via INSN_CODE_NUM)
+/* Check the operands of an insn against the insn's operand constraints
    and return 1 if they are valid.
+   The information about the insn's operands, constraints, operand modes
+   etc. is obtained from the global variables set up by extract_insn.
 
    WHICH_ALTERNATIVE is set to a number which indicates which
    alternative of constraints was matched: 0 for the first alternative,
@@ -1813,40 +1951,35 @@ struct funny_match
 };
 
 int
-constrain_operands (insn_code_num, strict)
-     int insn_code_num;
+constrain_operands (strict)
      int strict;
 {
   char *constraints[MAX_RECOG_OPERANDS];
   int matching_operands[MAX_RECOG_OPERANDS];
-  enum op_type {OP_IN, OP_OUT, OP_INOUT} op_types[MAX_RECOG_OPERANDS];
   int earlyclobber[MAX_RECOG_OPERANDS];
   register int c;
-  int noperands = insn_n_operands[insn_code_num];
 
   struct funny_match funny_match[MAX_RECOG_OPERANDS];
   int funny_match_index;
-  int nalternatives = insn_n_alternatives[insn_code_num];
 
-  if (noperands == 0 || nalternatives == 0)
+  if (recog_n_operands == 0 || recog_n_alternatives == 0)
     return 1;
 
-  for (c = 0; c < noperands; c++)
+  for (c = 0; c < recog_n_operands; c++)
     {
-      constraints[c] = insn_operand_constraint[insn_code_num][c];
+      constraints[c] = recog_constraints[c];
       matching_operands[c] = -1;
-      op_types[c] = OP_IN;
     }
 
   which_alternative = 0;
 
-  while (which_alternative < nalternatives)
+  while (which_alternative < recog_n_alternatives)
     {
       register int opno;
       int lose = 0;
       funny_match_index = 0;
 
-      for (opno = 0; opno < noperands; opno++)
+      for (opno = 0; opno < recog_n_operands; opno++)
        {
          register rtx op = recog_operand[opno];
          enum machine_mode mode = GET_MODE (op);
@@ -1882,6 +2015,8 @@ constrain_operands (insn_code_num, strict)
              case '!':
              case '*':
              case '%':
+             case '=':
+             case '+':
                break;
 
              case '#':
@@ -1891,14 +2026,6 @@ constrain_operands (insn_code_num, strict)
                  p++;
                break;
 
-             case '=':
-               op_types[opno] = OP_OUT;
-               break;
-
-             case '+':
-               op_types[opno] = OP_INOUT;
-               break;
-
              case '&':
                earlyclobber[opno] = 1;
                break;
@@ -1943,8 +2070,8 @@ constrain_operands (insn_code_num, strict)
                   strictly valid, i.e., that all pseudos requiring hard regs
                   have gotten them.  */
                if (strict <= 0
-                   || (strict_memory_address_p
-                       (insn_operand_mode[insn_code_num][opno], op)))
+                   || (strict_memory_address_p (recog_operand_mode[opno],
+                                                op)))
                  win = 1;
                break;
 
@@ -2124,18 +2251,18 @@ constrain_operands (insn_code_num, strict)
             operand.  */
 
          if (strict > 0)
-           for (eopno = 0; eopno < noperands; eopno++)
+           for (eopno = 0; eopno < recog_n_operands; eopno++)
              /* Ignore earlyclobber operands now in memory,
                 because we would often report failure when we have
                 two memory operands, one of which was formerly a REG.  */
              if (earlyclobber[eopno]
                  && GET_CODE (recog_operand[eopno]) == REG)
-               for (opno = 0; opno < noperands; opno++)
+               for (opno = 0; opno < recog_n_operands; opno++)
                  if ((GET_CODE (recog_operand[opno]) == MEM
-                      || op_types[opno] != OP_OUT)
+                      || recog_op_type[opno] != OP_OUT)
                      && opno != eopno
                      /* Ignore things like match_operator operands.  */
-                     && *insn_operand_constraint[insn_code_num][opno] != 0
+                     && *recog_constraints[opno] != 0
                      && ! (matching_operands[opno] == eopno
                            && operands_match_p (recog_operand[opno],
                                                 recog_operand[eopno]))
@@ -2161,7 +2288,7 @@ constrain_operands (insn_code_num, strict)
   /* If we are about to reject this, but we are not to test strictly,
      try a very loose test.  Only return failure if it fails also.  */
   if (strict == 0)
-    return constrain_operands (insn_code_num, -1);
+    return constrain_operands (-1);
   else
     return 0;
 }