OSDN Git Service

* aclocal.m4: Fixed typo.
[pf3gnuchains/gcc-fork.git] / gcc / genrecog.c
index 1121d8f..00f425b 100644 (file)
@@ -84,12 +84,13 @@ struct decision_test
   struct decision_test *next;
 
   /* These types are roughly in the order in which we'd like to test them.  */
-  enum decision_type {
-    DT_mode, DT_code, DT_veclen,
-    DT_elt_zero_int, DT_elt_one_int, DT_elt_zero_wide,
-    DT_dup, DT_pred, DT_c_test, 
-    DT_accept_op, DT_accept_insn
-  } type;
+  enum decision_type
+    {
+      DT_mode, DT_code, DT_veclen,
+      DT_elt_zero_int, DT_elt_one_int, DT_elt_zero_wide, DT_elt_zero_wide_safe,
+      DT_veclen_ge, DT_dup, DT_pred, DT_c_test, 
+      DT_accept_op, DT_accept_insn
+    } type;
 
   union
   {
@@ -230,6 +231,8 @@ static struct decision_test *new_decision_test
   PARAMS ((enum decision_type, struct decision_test ***));
 static rtx find_operand
   PARAMS ((rtx, int));
+static rtx find_matching_operand
+  PARAMS ((rtx, int));
 static void validate_pattern
   PARAMS ((rtx, rtx, rtx, int));
 static struct decision *add_to_sequence
@@ -379,6 +382,11 @@ find_operand (pattern, n)
            return r;
          break;
 
+       case 'V':
+         if (! XVEC (pattern, i))
+           break;
+         /* FALLTHRU */
+
        case 'E':
          for (j = 0; j < XVECLEN (pattern, i); j++)
            if ((r = find_operand (XVECEXP (pattern, i, j), n)) != NULL_RTX)
@@ -396,6 +404,60 @@ find_operand (pattern, n)
   return NULL;
 }
 
+/* Search for and return operand M, such that it has a matching
+   constraint for operand N.  */
+
+static rtx
+find_matching_operand (pattern, n)
+     rtx pattern;
+     int n;
+{
+  const char *fmt;
+  RTX_CODE code;
+  int i, j, len;
+  rtx r;
+
+  code = GET_CODE (pattern);
+  if (code == MATCH_OPERAND
+      && (XSTR (pattern, 2)[0] == '0' + n
+         || (XSTR (pattern, 2)[0] == '%'
+             && XSTR (pattern, 2)[1] == '0' + n)))
+    return pattern;
+
+  fmt = GET_RTX_FORMAT (code);
+  len = GET_RTX_LENGTH (code);
+  for (i = 0; i < len; i++)
+    {
+      switch (fmt[i])
+       {
+       case 'e': case 'u':
+         if ((r = find_matching_operand (XEXP (pattern, i), n)))
+           return r;
+         break;
+
+       case 'V':
+         if (! XVEC (pattern, i))
+           break;
+         /* FALLTHRU */
+
+       case 'E':
+         for (j = 0; j < XVECLEN (pattern, i); j++)
+           if ((r = find_matching_operand (XVECEXP (pattern, i, j), n)))
+             return r;
+         break;
+
+       case 'i': case 'w': case '0': case 's':
+         break;
+
+       default:
+         abort ();
+       }
+    }
+
+  return NULL;
+}
+
+
 /* Check for various errors in patterns.  SET is nonnull for a destination,
    and is the complete set pattern.  SET_CODE is '=' for normal sets, and
    '+' within a context that requires in-out constraints.  */
@@ -484,19 +546,27 @@ validate_pattern (pattern, insn, set, set_code)
          }
 
        /* A MATCH_OPERAND that is a SET should have an output reload.  */
-       if (set && code == MATCH_OPERAND)
+       if (set && code == MATCH_OPERAND
+           && XSTR (pattern, 2)[0] != '\0')
          {
-           if (set_code == '+'
-               && XSTR (pattern, 2)[0] != '\0'
-               && XSTR (pattern, 2)[0] != '+')
+           if (set_code == '+')
              {
-               message_with_line (pattern_lineno,
-                                  "operand %d missing in-out reload",
-                                  XINT (pattern, 0));
-               error_count++;
+               if (XSTR (pattern, 2)[0] == '+')
+                 ;
+               /* If we've only got an output reload for this operand,
+                  we'd better have a matching input operand.  */
+               else if (XSTR (pattern, 2)[0] == '='
+                        && find_matching_operand (insn, XINT (pattern, 0)))
+                 ;
+               else
+                 {
+                   message_with_line (pattern_lineno,
+                                      "operand %d missing in-out reload",
+                                      XINT (pattern, 0));
+                   error_count++;
+                 }
              }
-           else if (XSTR (pattern, 2)[0] != '\0'
-                    && XSTR (pattern, 2)[0] != '='
+           else if (XSTR (pattern, 2)[0] != '='
                     && XSTR (pattern, 2)[0] != '+')
              {
                message_with_line (pattern_lineno,
@@ -623,7 +693,6 @@ validate_pattern (pattern, insn, set, set_code)
 
     case STRICT_LOW_PART:
       validate_pattern (XEXP (pattern, 0), insn, set, set ? '+' : 0);
-      validate_pattern (XEXP (pattern, 1), insn, NULL, 0);
       return;
 
     case LABEL_REF:
@@ -698,7 +767,7 @@ add_to_sequence (pattern, last, position, insn_type, top)
   if (depth > max_depth)
     max_depth = depth;
 
-  subpos = (char *) alloca (depth + 2);
+  subpos = (char *) xmalloc (depth + 2);
   strcpy (subpos, position);
   subpos[depth + 1] = 0;
 
@@ -728,16 +797,25 @@ add_to_sequence (pattern, last, position, insn_type, top)
                                     last, subpos, insn_type, 0);
              last = &sub->success;
            }
-         return sub;
+         goto ret;
        }
 
       /* Else nothing special.  */
       break;
 
+    case MATCH_PARALLEL:
+      /* The explicit patterns within a match_parallel enforce a minimum
+        length on the vector.  The match_parallel predicate may allow
+        for more elements.  We do need to check for this minimum here
+        or the code generated to match the internals may reference data
+        beyond the end of the vector.  */
+      test = new_decision_test (DT_veclen_ge, &place);
+      test->u.veclen = XVECLEN (pattern, 2);
+      /* FALLTHRU */
+
     case MATCH_OPERAND:
     case MATCH_SCRATCH:
     case MATCH_OPERATOR:
-    case MATCH_PARALLEL:
     case MATCH_INSN:
       {
        const char *pred_name;
@@ -758,30 +836,22 @@ add_to_sequence (pattern, last, position, insn_type, top)
              code = UNKNOWN;
          }
 
-       /* We know exactly what const_int_operand matches -- any CONST_INT.  */
-       if (strcmp ("const_int_operand", pred_name) == 0)
-         {
-           code = CONST_INT;
-           mode = VOIDmode;
-         }
-       else if (pred_name[0] != 0)
+       if (pred_name[0] != 0)
          {
            test = new_decision_test (DT_pred, &place);
            test->u.pred.name = pred_name;
            test->u.pred.mode = mode;
 
-           /* See if we know about this predicate and save its number.  If
-              we do, and it only accepts one code, note that fact.  The
-              predicate `const_int_operand' only tests for a CONST_INT, so
-              if we do so we can avoid calling it at all.
+           /* See if we know about this predicate and save its number.
+              If we do, and it only accepts one code, note that fact.
 
-              Finally, if we know that the predicate does not allow
-              CONST_INT, we know that the only way the predicate can match
-              is if the modes match (here we use the kludge of relying on
-              the fact that "address_operand" accepts CONST_INT; otherwise,
-              it would have to be a special case), so we can test the mode
-              (but we need not).  This fact should considerably simplify the
-              generated code.  */
+              If we know that the predicate does not allow CONST_INT,
+              we know that the only way the predicate can match is if
+              the modes match (here we use the kludge of relying on the
+              fact that "address_operand" accepts CONST_INT; otherwise,
+              it would have to be a special case), so we can test the
+              mode (but we need not).  This fact should considerably
+              simplify the generated code.  */
 
            for (i = 0; i < NUM_KNOWN_PREDS; i++)
              if (! strcmp (preds[i].name, pred_name))
@@ -885,10 +955,16 @@ add_to_sequence (pattern, last, position, insn_type, top)
        }
       else if (fmt[i] == 'w')
        {
+         /* If this value actually fits in an int, we can use a switch
+            statement here, so indicate that.  */
+         enum decision_type type
+           = ((int) XWINT (pattern, i) == XWINT (pattern, i))
+             ? DT_elt_zero_wide_safe : DT_elt_zero_wide;
+
          if (i != 0)
            abort ();
 
-         test = new_decision_test (DT_elt_zero_wide, &place);
+         test = new_decision_test (type, &place);
          test->u.intval = XWINT (pattern, i);
        }
       else if (fmt[i] == 'E')
@@ -956,6 +1032,8 @@ add_to_sequence (pattern, last, position, insn_type, top)
   if (this->tests == NULL)
     abort ();
 
+ ret:
+  free (subpos);
   return sub;
 }
 \f
@@ -982,6 +1060,7 @@ maybe_both_true_2 (d1, d2)
        case DT_elt_zero_int:
        case DT_elt_one_int:
        case DT_elt_zero_wide:
+       case DT_elt_zero_wide_safe:
          return d1->u.intval == d2->u.intval;
 
        default:
@@ -1060,6 +1139,12 @@ maybe_both_true_2 (d1, d2)
        }
     }
 
+  /* Tests vs veclen may be known when strict equality is involved.  */
+  if (d1->type == DT_veclen && d2->type == DT_veclen_ge)
+    return d1->u.veclen >= d2->u.veclen;
+  if (d1->type == DT_veclen_ge && d2->type == DT_veclen)
+    return d2->u.veclen >= d1->u.veclen;
+
   return -1;
 }
 
@@ -1138,7 +1223,7 @@ maybe_both_true (d1, d2, toplevel)
        p1 = d1, d1 = d2, d2 = p1;
 
       if (d1->success.first == 0)
-       return 0;
+       return 1;
       for (p1 = d1->success.first; p1; p1 = p1->next)
        if (maybe_both_true (p1, d2, 0))
          return 1;
@@ -1190,6 +1275,7 @@ nodes_identical_1 (d1, d2)
       return strcmp (d1->u.c_test, d2->u.c_test) == 0;
 
     case DT_veclen:
+    case DT_veclen_ge:
       return d1->u.veclen == d2->u.veclen;
 
     case DT_dup:
@@ -1198,6 +1284,7 @@ nodes_identical_1 (d1, d2)
     case DT_elt_zero_int:
     case DT_elt_one_int:
     case DT_elt_zero_wide:
+    case DT_elt_zero_wide_safe:
       return d1->u.intval == d2->u.intval;
 
     case DT_accept_op:
@@ -1235,7 +1322,9 @@ nodes_identical (d1, d2)
     return 0;
 
   /* Check that their subnodes are at the same position, as any one set
-     of sibling decisions must be at the same position.  */
+     of sibling decisions must be at the same position.  Allowing this
+     requires complications to find_afterward and when change_state is
+     invoked.  */
   if (d1->success.first
       && d2->success.first
       && strcmp (d1->success.first->position, d2->success.first->position))
@@ -1352,7 +1441,7 @@ merge_trees (oldh, addh)
             how expensive/important the test is.  Given that the tests
             are also ordered within the list, examining the first is
             sufficient.  */
-         if (add->tests->type < old->tests->type)
+         if ((int) add->tests->type < (int) old->tests->type)
            insert_before = old;
        }
 
@@ -1406,7 +1495,7 @@ factor_tests (head)
          && type != DT_veclen
          && type != DT_elt_zero_int
          && type != DT_elt_one_int
-         && type != DT_elt_zero_wide)
+         && type != DT_elt_zero_wide_safe)
        continue;
 
       /* If we'd been performing more than one test, create a new node
@@ -1681,7 +1770,8 @@ write_switch (start, depth)
   if (!p->next
       || p->tests->next
       || p->next->tests->type != type
-      || p->next->tests->next)
+      || p->next->tests->next
+      || nodes_identical_1 (p->tests, p->next->tests))
     return p;
 
   /* DT_code is special in that we can do interesting things with
@@ -1775,7 +1865,7 @@ write_switch (start, depth)
           || type == DT_veclen
           || type == DT_elt_zero_int
           || type == DT_elt_one_int
-          || type == DT_elt_zero_wide)
+          || type == DT_elt_zero_wide_safe)
     {
       printf ("  switch (");
       switch (type)
@@ -1792,7 +1882,7 @@ write_switch (start, depth)
        case DT_elt_one_int:
          printf ("XINT (x%d, 1)", depth);
          break;
-       case DT_elt_zero_wide:
+       case DT_elt_zero_wide_safe:
          /* Convert result of XWINT to int for portability since some C
             compilers won't do it and some will.  */
          printf ("(int) XWINT (x%d, 0)", depth);
@@ -1804,6 +1894,14 @@ write_switch (start, depth)
 
       do
        {
+         /* Merge trees will not unify identical nodes if their
+            sub-nodes are at different levels.  Thus we must check
+            for duplicate cases.  */
+         struct decision *q;
+         for (q = start; q != p; q = q->next)
+           if (nodes_identical_1 (p->tests, q->tests))
+             goto case_done;
+
          if (p != start && p->need_label && needs_label == NULL)
            needs_label = p;
 
@@ -1819,6 +1917,7 @@ write_switch (start, depth)
            case DT_elt_zero_int:
            case DT_elt_one_int:
            case DT_elt_zero_wide:
+           case DT_elt_zero_wide_safe:
              printf (HOST_WIDE_INT_PRINT_DEC, p->tests->u.intval);
              break;
            default:
@@ -1830,7 +1929,8 @@ write_switch (start, depth)
          p = p->next;
        }
       while (p && p->tests->type == type && !p->tests->next);
-      
+
+    case_done:
       printf ("    default:\n      break;\n    }\n");
 
       return needs_label != NULL ? needs_label : p;
@@ -1874,10 +1974,15 @@ write_cond (p, depth, subroutine_type)
       break;
 
     case DT_elt_zero_wide:
+    case DT_elt_zero_wide_safe:
       printf ("XWINT (x%d, 0) == ", depth);
       printf (HOST_WIDE_INT_PRINT_DEC, p->u.intval);
       break;
 
+    case DT_veclen_ge:
+      printf ("XVECLEN (x%d, 0) >= %d", depth, p->u.veclen);
+      break;
+
     case DT_dup:
       printf ("rtx_equal_p (x%d, operands[%d])", depth, p->u.dup);
       break;
@@ -2272,6 +2377,7 @@ write_header ()
 #include \"flags.h\"\n\
 #include \"hard-reg-set.h\"\n\
 #include \"resource.h\"\n\
+#include \"toplev.h\"\n\
 \n");
 
   puts ("\n\
@@ -2641,6 +2747,13 @@ debug_decision_2 (test)
       fprintf (stderr, "elt0_w=");
       fprintf (stderr, HOST_WIDE_INT_PRINT_DEC, test->u.intval);
       break;
+    case DT_elt_zero_wide_safe:
+      fprintf (stderr, "elt0_ws=");
+      fprintf (stderr, HOST_WIDE_INT_PRINT_DEC, test->u.intval);
+      break;
+    case DT_veclen_ge:
+      fprintf (stderr, "veclen>=%d", test->u.veclen);
+      break;
     case DT_dup:
       fprintf (stderr, "dup=%d", test->u.dup);
       break;