OSDN Git Service

Add new test - do not warn about (non-)redundant friend declaration.
[pf3gnuchains/gcc-fork.git] / gcc / genrecog.c
index 8146b71..ba40437 100644 (file)
@@ -87,7 +87,7 @@ struct decision_test
   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_veclen_ge, DT_dup, DT_pred, DT_c_test, 
     DT_accept_op, DT_accept_insn
   } type;
 
@@ -766,7 +766,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;
 
@@ -796,16 +796,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;
@@ -1018,6 +1027,8 @@ add_to_sequence (pattern, last, position, insn_type, top)
   if (this->tests == NULL)
     abort ();
 
+ ret:
+  free (subpos);
   return sub;
 }
 \f
@@ -1122,6 +1133,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;
 }
 
@@ -1252,6 +1269,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:
@@ -1297,7 +1315,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))
@@ -1414,7 +1434,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;
        }
 
@@ -1743,7 +1763,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
@@ -1839,6 +1860,10 @@ write_switch (start, depth)
           || type == DT_elt_one_int
           || type == DT_elt_zero_wide)
     {
+      /* The argument is casted to int.  In case HOST_WIDE_INT is more exact,
+         we can't safely construct switch statement over it.  */
+      if (type == DT_elt_zero_wide && HOST_BITS_PER_WIDE_INT > sizeof (int) * CHAR_BIT)
+         return p;
       printf ("  switch (");
       switch (type)
        {
@@ -1866,6 +1891,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;
 
@@ -1892,7 +1925,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;
@@ -1940,6 +1974,10 @@ write_cond (p, depth, subroutine_type)
       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;
@@ -2334,6 +2372,7 @@ write_header ()
 #include \"flags.h\"\n\
 #include \"hard-reg-set.h\"\n\
 #include \"resource.h\"\n\
+#include \"toplev.h\"\n\
 \n");
 
   puts ("\n\
@@ -2703,6 +2742,9 @@ debug_decision_2 (test)
       fprintf (stderr, "elt0_w=");
       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;