OSDN Git Service

PR c++/15815
[pf3gnuchains/gcc-fork.git] / gcc / genrecog.c
index dcfa6d8..2694e83 100644 (file)
@@ -1,6 +1,6 @@
 /* Generate code from machine description to recognize rtl as insns.
    Copyright (C) 1987, 1988, 1992, 1993, 1994, 1995, 1997, 1998,
-   1999, 2000, 2001, 2002, 2003 Free Software Foundation, Inc.
+   1999, 2000, 2001, 2002, 2003, 2004 Free Software Foundation, Inc.
 
    This file is part of GCC.
 
@@ -90,6 +90,7 @@ struct decision_test
     {
       DT_mode, DT_code, DT_veclen,
       DT_elt_zero_int, DT_elt_one_int, DT_elt_zero_wide, DT_elt_zero_wide_safe,
+      DT_const_int,
       DT_veclen_ge, DT_dup, DT_pred, DT_c_test,
       DT_accept_op, DT_accept_insn
     } type;
@@ -189,23 +190,23 @@ static const struct pred_table
   const RTX_CODE codes[NUM_RTX_CODE];
 } preds[] = {
   {"general_operand", {CONST_INT, CONST_DOUBLE, CONST, SYMBOL_REF,
-                      LABEL_REF, SUBREG, REG, MEM, ADDRESSOF}},
+                      LABEL_REF, SUBREG, REG, MEM }},
 #ifdef PREDICATE_CODES
   PREDICATE_CODES
 #endif
   {"address_operand", {CONST_INT, CONST_DOUBLE, CONST, SYMBOL_REF,
-                      LABEL_REF, SUBREG, REG, MEM, ADDRESSOF,
+                      LABEL_REF, SUBREG, REG, MEM,
                       PLUS, MINUS, MULT}},
-  {"register_operand", {SUBREG, REG, ADDRESSOF}},
-  {"pmode_register_operand", {SUBREG, REG, ADDRESSOF}},
+  {"register_operand", {SUBREG, REG}},
+  {"pmode_register_operand", {SUBREG, REG}},
   {"scratch_operand", {SCRATCH, REG}},
   {"immediate_operand", {CONST_INT, CONST_DOUBLE, CONST, SYMBOL_REF,
                         LABEL_REF}},
   {"const_int_operand", {CONST_INT}},
   {"const_double_operand", {CONST_INT, CONST_DOUBLE}},
-  {"nonimmediate_operand", {SUBREG, REG, MEM, ADDRESSOF}},
+  {"nonimmediate_operand", {SUBREG, REG, MEM}},
   {"nonmemory_operand", {CONST_INT, CONST_DOUBLE, CONST, SYMBOL_REF,
-                        LABEL_REF, SUBREG, REG, ADDRESSOF}},
+                        LABEL_REF, SUBREG, REG}},
   {"push_operand", {MEM}},
   {"pop_operand", {MEM}},
   {"memory_operand", {SUBREG, MEM}},
@@ -231,7 +232,7 @@ static struct decision *new_decision
 static struct decision_test *new_decision_test
   (enum decision_type, struct decision_test ***);
 static rtx find_operand
-  (rtx, int);
+  (rtx, int, rtx);
 static rtx find_matching_operand
   (rtx, int);
 static void validate_pattern
@@ -316,10 +317,8 @@ extern void debug_decision_list
 static struct decision *
 new_decision (const char *position, struct decision_head *last)
 {
-  struct decision *new
-    = (struct decision *) xmalloc (sizeof (struct decision));
+  struct decision *new = xcalloc (1, sizeof (struct decision));
 
-  memset (new, 0, sizeof (*new));
   new->success = *last;
   new->position = xstrdup (position);
   new->number = next_number++;
@@ -336,7 +335,7 @@ new_decision_test (enum decision_type type, struct decision_test ***pplace)
   struct decision_test **place = *pplace;
   struct decision_test *test;
 
-  test = (struct decision_test *) xmalloc (sizeof (*test));
+  test = xmalloc (sizeof (*test));
   test->next = *place;
   test->type = type;
   *place = test;
@@ -347,19 +346,21 @@ new_decision_test (enum decision_type type, struct decision_test ***pplace)
   return test;
 }
 
-/* Search for and return operand N.  */
+/* Search for and return operand N, stop when reaching node STOP.  */
 
 static rtx
-find_operand (rtx pattern, int n)
+find_operand (rtx pattern, int n, rtx stop)
 {
   const char *fmt;
   RTX_CODE code;
   int i, j, len;
   rtx r;
 
+  if (pattern == stop)
+    return stop;
+
   code = GET_CODE (pattern);
   if ((code == MATCH_SCRATCH
-       || code == MATCH_INSN
        || code == MATCH_OPERAND
        || code == MATCH_OPERATOR
        || code == MATCH_PARALLEL)
@@ -373,18 +374,19 @@ find_operand (rtx pattern, int n)
       switch (fmt[i])
        {
        case 'e': case 'u':
-         if ((r = find_operand (XEXP (pattern, i), n)) != NULL_RTX)
+         if ((r = find_operand (XEXP (pattern, i), n, stop)) != NULL_RTX)
            return r;
          break;
 
        case 'V':
          if (! XVEC (pattern, i))
            break;
-         /* FALLTHRU */
+         /* Fall through.  */
 
        case 'E':
          for (j = 0; j < XVECLEN (pattern, i); j++)
-           if ((r = find_operand (XVECEXP (pattern, i, j), n)) != NULL_RTX)
+           if ((r = find_operand (XVECEXP (pattern, i, j), n, stop))
+               != NULL_RTX)
              return r;
          break;
 
@@ -431,7 +433,7 @@ find_matching_operand (rtx pattern, int n)
        case 'V':
          if (! XVEC (pattern, i))
            break;
-         /* FALLTHRU */
+         /* Fall through.  */
 
        case 'E':
          for (j = 0; j < XVECLEN (pattern, i); j++)
@@ -468,8 +470,17 @@ validate_pattern (rtx pattern, rtx insn, rtx set, int set_code)
     {
     case MATCH_SCRATCH:
       return;
-
-    case MATCH_INSN:
+    case MATCH_DUP:
+    case MATCH_OP_DUP:
+    case MATCH_PAR_DUP:
+      if (find_operand (insn, XINT (pattern, 0), pattern) == pattern)
+       {
+         message_with_line (pattern_lineno,
+                            "operand %i duplicated before defined",
+                            XINT (pattern, 0));
+          error_count++;
+       }
+      break;
     case MATCH_OPERAND:
     case MATCH_OPERATOR:
       {
@@ -502,14 +513,12 @@ validate_pattern (rtx pattern, rtx insn, rtx set, int set_code)
                        && c != CONST_INT
                        && c != CONST_DOUBLE
                        && c != CONST
-                       && c != HIGH
-                       && c != CONSTANT_P_RTX)
+                       && c != HIGH)
                      allows_non_const = 1;
 
                    if (c != REG
                        && c != SUBREG
                        && c != MEM
-                       && c != ADDRESSOF
                        && c != CONCAT
                        && c != PARALLEL
                        && c != STRICT_LOW_PART)
@@ -635,17 +644,17 @@ validate_pattern (rtx pattern, rtx insn, rtx set, int set_code)
        if (GET_CODE (dest) == STRICT_LOW_PART)
          dest = XEXP (dest, 0);
 
-       /* Find the referant for a DUP.  */
+       /* Find the referent for a DUP.  */
 
        if (GET_CODE (dest) == MATCH_DUP
            || GET_CODE (dest) == MATCH_OP_DUP
            || GET_CODE (dest) == MATCH_PAR_DUP)
-         dest = find_operand (insn, XINT (dest, 0));
+         dest = find_operand (insn, XINT (dest, 0), NULL);
 
        if (GET_CODE (src) == MATCH_DUP
            || GET_CODE (src) == MATCH_OP_DUP
            || GET_CODE (src) == MATCH_PAR_DUP)
-         src = find_operand (insn, XINT (src, 0));
+         src = find_operand (insn, XINT (src, 0), NULL);
 
        dmode = GET_MODE (dest);
        smode = GET_MODE (src);
@@ -770,7 +779,7 @@ add_to_sequence (rtx pattern, struct decision_head *last, const char *position,
   if (depth > max_depth)
     max_depth = depth;
 
-  subpos = (char *) xmalloc (depth + 2);
+  subpos = xmalloc (depth + 2);
   strcpy (subpos, position);
   subpos[depth + 1] = 0;
 
@@ -814,12 +823,11 @@ add_to_sequence (rtx pattern, struct decision_head *last, const char *position,
         beyond the end of the vector.  */
       test = new_decision_test (DT_veclen_ge, &place);
       test->u.veclen = XVECLEN (pattern, 2);
-      /* FALLTHRU */
+      /* Fall through.  */
 
     case MATCH_OPERAND:
     case MATCH_SCRATCH:
     case MATCH_OPERATOR:
-    case MATCH_INSN:
       {
        const char *pred_name;
        RTX_CODE was_code = code;
@@ -1736,6 +1744,20 @@ write_afterward (struct decision *start, struct decision *afterward,
     }
 }
 
+/* Emit a HOST_WIDE_INT as an integer constant expression.  We need to take
+   special care to avoid "decimal constant is so large that it is unsigned"
+   warnings in the resulting code.  */
+
+static void
+print_host_wide_int (HOST_WIDE_INT val)
+{
+  HOST_WIDE_INT min = (unsigned HOST_WIDE_INT)1 << (HOST_BITS_PER_WIDE_INT-1);
+  if (val == min)
+    printf ("(" HOST_WIDE_INT_PRINT_DEC_C "-1)", val + 1);
+  else
+    printf (HOST_WIDE_INT_PRINT_DEC_C, val);
+}
+
 /* Emit a switch statement, if possible, for an initial sequence of
    nodes at START.  Return the first node yet untested.  */
 
@@ -1909,7 +1931,7 @@ write_switch (struct decision *start, int depth)
            case DT_elt_one_int:
            case DT_elt_zero_wide:
            case DT_elt_zero_wide_safe:
-             printf (HOST_WIDE_INT_PRINT_DEC_C, p->tests->u.intval);
+             print_host_wide_int (p->tests->u.intval);
              break;
            default:
              abort ();
@@ -1966,7 +1988,12 @@ write_cond (struct decision_test *p, int depth,
     case DT_elt_zero_wide:
     case DT_elt_zero_wide_safe:
       printf ("XWINT (x%d, 0) == ", depth);
-      printf (HOST_WIDE_INT_PRINT_DEC_C, p->u.intval);
+      print_host_wide_int (p->u.intval);
+      break;
+
+    case DT_const_int:
+      printf ("x%d == const_int_rtx[MAX_SAVED_CONST_INT + (%d)]",
+             depth, (int) p->u.intval);
       break;
 
     case DT_veclen_ge:
@@ -2057,7 +2084,7 @@ write_action (struct decision *p, struct decision_test *test,
          break;
 
        case SPLIT:
-         printf ("%sreturn gen_split_%d (operands);\n",
+         printf ("%sreturn gen_split_%d (insn, operands);\n",
                  indent, test->u.insn.code_number);
          break;
 
@@ -2131,6 +2158,23 @@ write_node (struct decision *p, int depth,
   struct decision_test *test, *last_test;
   int uncond;
 
+  /* Scan the tests and simplify comparisons against small
+     constants.  */
+  for (test = p->tests; test; test = test->next)
+    {
+      if (test->type == DT_code
+         && test->u.code == CONST_INT
+         && test->next
+         && test->next->type == DT_elt_zero_wide_safe
+         && -MAX_SAVED_CONST_INT <= test->next->u.intval
+         && test->next->u.intval <= MAX_SAVED_CONST_INT)
+       {
+         test->type = DT_const_int;
+         test->u.intval = test->next->u.intval;
+         test->next = test->next->next;
+       }
+    }
+
   last_test = test = p->tests;
   uncond = is_unconditional (test, subroutine_type);
   if (uncond == 0)
@@ -2140,11 +2184,8 @@ write_node (struct decision *p, int depth,
 
       while ((test = test->next) != NULL)
        {
-         int uncond2;
-
          last_test = test;
-         uncond2 = is_unconditional (test, subroutine_type);
-         if (uncond2 != 0)
+         if (is_unconditional (test, subroutine_type))
            break;
 
          printf ("\n      && ");
@@ -2272,28 +2313,18 @@ write_subroutine (struct decision_head *head, enum routine_type type)
   switch (type)
     {
     case RECOG:
-      printf ("%sint recog%s (rtx, rtx, int *);\n", s_or_e, extension);
       printf ("%sint\n\
-recog%s (x0, insn, pnum_clobbers)\n\
-     rtx x0 ATTRIBUTE_UNUSED;\n\
-     rtx insn ATTRIBUTE_UNUSED;\n\
-     int *pnum_clobbers ATTRIBUTE_UNUSED;\n", s_or_e, extension);
+recog%s (rtx x0 ATTRIBUTE_UNUSED,\n\trtx insn ATTRIBUTE_UNUSED,\n\tint *pnum_clobbers ATTRIBUTE_UNUSED)\n", s_or_e, extension);
       break;
     case SPLIT:
-      printf ("%srtx split%s (rtx, rtx);\n", s_or_e, extension);
       printf ("%srtx\n\
-split%s (x0, insn)\n\
-     rtx x0 ATTRIBUTE_UNUSED;\n\
-     rtx insn ATTRIBUTE_UNUSED;\n", s_or_e, extension);
+split%s (rtx x0 ATTRIBUTE_UNUSED, rtx insn ATTRIBUTE_UNUSED)\n",
+             s_or_e, extension);
       break;
     case PEEPHOLE2:
-      printf ("%srtx peephole2%s (rtx, rtx, int *);\n",
-             s_or_e, extension);
       printf ("%srtx\n\
-peephole2%s (x0, insn, _pmatch_len)\n\
-     rtx x0 ATTRIBUTE_UNUSED;\n\
-     rtx insn ATTRIBUTE_UNUSED;\n\
-     int *_pmatch_len ATTRIBUTE_UNUSED;\n", s_or_e, extension);
+peephole2%s (rtx x0 ATTRIBUTE_UNUSED,\n\trtx insn ATTRIBUTE_UNUSED,\n\tint *_pmatch_len ATTRIBUTE_UNUSED)\n",
+             s_or_e, extension);
       break;
     }
 
@@ -2490,7 +2521,7 @@ make_insn_sequence (rtx insn, enum routine_type type)
            {
              rtx y = XVECEXP (x, 0, i - 1);
              if (GET_CODE (y) != CLOBBER
-                 || (GET_CODE (XEXP (y, 0)) != REG
+                 || (!REG_P (XEXP (y, 0))
                      && GET_CODE (XEXP (y, 0)) != MATCH_SCRATCH))
                break;
            }
@@ -2550,7 +2581,7 @@ make_insn_sequence (rtx insn, enum routine_type type)
 
     case SPLIT:
       /* Define the subroutine we will call below and emit in genemit.  */
-      printf ("extern rtx gen_split_%d (rtx *);\n", next_insn_code);
+      printf ("extern rtx gen_split_%d (rtx, rtx *);\n", next_insn_code);
       break;
 
     case PEEPHOLE2:
@@ -2677,8 +2708,7 @@ record_insn_name (int code, const char *name)
     {
       int new_size;
       new_size = (insn_name_ptr_size ? insn_name_ptr_size * 2 : 512);
-      insn_name_ptr =
-       (char **) xrealloc (insn_name_ptr, sizeof(char *) * new_size);
+      insn_name_ptr = xrealloc (insn_name_ptr, sizeof(char *) * new_size);
       memset (insn_name_ptr + insn_name_ptr_size, 0,
              sizeof(char *) * (new_size - insn_name_ptr_size));
       insn_name_ptr_size = new_size;