OSDN Git Service

* config/alpha/alpha.c (alpha_sa_size): Force procedure type to
[pf3gnuchains/gcc-fork.git] / gcc / genoutput.c
index a62c677..e651cb4 100644 (file)
@@ -1,12 +1,12 @@
 /* Generate code from to output assembler insns as recognized from rtl.
    Copyright (C) 1987, 1988, 1992, 1994, 1995, 1997, 1998, 1999, 2000, 2002,
 /* Generate code from to output assembler insns as recognized from rtl.
    Copyright (C) 1987, 1988, 1992, 1994, 1995, 1997, 1998, 1999, 2000, 2002,
-   2003, 2004 Free Software Foundation, Inc.
+   2003, 2004, 2005, 2007, 2008 Free Software Foundation, Inc.
 
 This file is part of GCC.
 
 GCC is free software; you can redistribute it and/or modify it under
 the terms of the GNU General Public License as published by the Free
 
 This file is part of GCC.
 
 GCC is free software; you can redistribute it and/or modify it under
 the terms of the GNU General Public License as published by the Free
-Software Foundation; either version 2, or (at your option) any later
+Software Foundation; either version 3, or (at your option) any later
 version.
 
 GCC is distributed in the hope that it will be useful, but WITHOUT ANY
 version.
 
 GCC is distributed in the hope that it will be useful, but WITHOUT ANY
@@ -15,9 +15,8 @@ FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
 for more details.
 
 You should have received a copy of the GNU General Public License
 for more details.
 
 You should have received a copy of the GNU General Public License
-along with GCC; see the file COPYING.  If not, write to the Free
-Software Foundation, 59 Temple Place - Suite 330, Boston, MA
-02111-1307, USA.  */
+along with GCC; see the file COPYING3.  If not see
+<http://www.gnu.org/licenses/>.  */
 
 
 /* This program reads the machine description for the compiler target machine
 
 
 /* This program reads the machine description for the compiler target machine
@@ -54,12 +53,10 @@ Software Foundation, 59 Temple Place - Suite 330, Boston, MA
      a. `predicate', an int-valued function, is the match_operand predicate
      for this operand.
 
      a. `predicate', an int-valued function, is the match_operand predicate
      for this operand.
 
-     b. `constraint' is the constraint for this operand.  This exists
-     only if register constraints appear in match_operand rtx's.
+     b. `constraint' is the constraint for this operand.
 
      c. `address_p' indicates that the operand appears within ADDRESS
 
      c. `address_p' indicates that the operand appears within ADDRESS
-     rtx's.  This exists only if there are *no* register constraints
-     in the match_operand rtx's.
+     rtx's.
 
      d. `mode' is the machine mode that that operand is supposed to have.
 
 
      d. `mode' is the machine mode that that operand is supposed to have.
 
@@ -157,7 +154,7 @@ struct data
 {
   struct data *next;
   const char *name;
 {
   struct data *next;
   const char *name;
-  const char *template;
+  const char *template_code;
   int code_number;
   int index_number;
   const char *filename;
   int code_number;
   int index_number;
   const char *filename;
@@ -189,31 +186,36 @@ static void gen_insn (rtx, int);
 static void gen_peephole (rtx, int);
 static void gen_expand (rtx, int);
 static void gen_split (rtx, int);
 static void gen_peephole (rtx, int);
 static void gen_expand (rtx, int);
 static void gen_split (rtx, int);
-static void check_constraint_len (void);
-static int constraint_len (const char *, int);
-\f
-const char *
-get_insn_name (int index)
+
+#ifdef USE_MD_CONSTRAINTS
+
+struct constraint_data
 {
 {
-  static char buf[100];
+  struct constraint_data *next_this_letter;
+  int lineno;
+  unsigned int namelen;
+  const char name[1];
+};
 
 
-  struct data *i, *last_named = NULL;
-  for (i = idata; i ; i = i->next)
-    {
-      if (i->index_number == index)
-       return i->name;
-      if (i->name)
-       last_named = i;
-    }
+/* This is a complete list (unlike the one in genpreds.c) of constraint
+   letters and modifiers with machine-independent meaning.  The only
+   omission is digits, as these are handled specially.  */
+static const char indep_constraints[] = ",=+%*?!#&<>EFVXgimnoprs";
 
 
-  if (last_named)
-    sprintf(buf, "%s+%d", last_named->name, index - last_named->index_number);
-  else
-    sprintf(buf, "insn %d", index);
+static struct constraint_data *
+constraints_by_letter_table[1 << CHAR_BIT];
 
 
-  return buf;
-}
+static int mdep_constraint_len (const char *, int, int);
+static void note_constraint (rtx, int);
+
+#else  /* !USE_MD_CONSTRAINTS */
+
+static void check_constraint_len (void);
+static int constraint_len (const char *, int);
 
 
+#endif /* !USE_MD_CONSTRAINTS */
+
+\f
 static void
 output_prologue (void)
 {
 static void
 output_prologue (void)
 {
@@ -241,6 +243,7 @@ output_prologue (void)
   printf ("#include \"toplev.h\"\n");
   printf ("#include \"output.h\"\n");
   printf ("#include \"target.h\"\n");
   printf ("#include \"toplev.h\"\n");
   printf ("#include \"output.h\"\n");
   printf ("#include \"target.h\"\n");
+  printf ("#include \"tm-constrs.h\"\n");
 }
 
 static void
 }
 
 static void
@@ -333,7 +336,7 @@ output_insn_data (void)
          break;
        case INSN_OUTPUT_FORMAT_SINGLE:
          {
          break;
        case INSN_OUTPUT_FORMAT_SINGLE:
          {
-           const char *p = d->template;
+           const char *p = d->template_code;
            char prev = 0;
 
            printf ("#if HAVE_DESIGNATED_INITIALIZERS\n");
            char prev = 0;
 
            printf ("#if HAVE_DESIGNATED_INITIALIZERS\n");
@@ -653,36 +656,36 @@ place_operands (struct data *d)
    templates, or C code to generate the assembler code template.  */
 
 static void
    templates, or C code to generate the assembler code template.  */
 
 static void
-process_template (struct data *d, const char *template)
+process_template (struct data *d, const char *template_code)
 {
   const char *cp;
   int i;
 
   /* Templates starting with * contain straight code to be run.  */
 {
   const char *cp;
   int i;
 
   /* Templates starting with * contain straight code to be run.  */
-  if (template[0] == '*')
+  if (template_code[0] == '*')
     {
     {
-      d->template = 0;
+      d->template_code = 0;
       d->output_format = INSN_OUTPUT_FORMAT_FUNCTION;
 
       puts ("\nstatic const char *");
       printf ("output_%d (rtx *operands ATTRIBUTE_UNUSED, rtx insn ATTRIBUTE_UNUSED)\n",
              d->code_number);
       puts ("{");
       d->output_format = INSN_OUTPUT_FORMAT_FUNCTION;
 
       puts ("\nstatic const char *");
       printf ("output_%d (rtx *operands ATTRIBUTE_UNUSED, rtx insn ATTRIBUTE_UNUSED)\n",
              d->code_number);
       puts ("{");
-
-      puts (template + 1);
+      print_rtx_ptr_loc (template_code);
+      puts (template_code + 1);
       puts ("}");
     }
 
   /* If the assembler code template starts with a @ it is a newline-separated
      list of assembler code templates, one for each alternative.  */
       puts ("}");
     }
 
   /* If the assembler code template starts with a @ it is a newline-separated
      list of assembler code templates, one for each alternative.  */
-  else if (template[0] == '@')
+  else if (template_code[0] == '@')
     {
     {
-      d->template = 0;
+      d->template_code = 0;
       d->output_format = INSN_OUTPUT_FORMAT_MULTI;
 
       printf ("\nstatic const char * const output_%d[] = {\n", d->code_number);
 
       d->output_format = INSN_OUTPUT_FORMAT_MULTI;
 
       printf ("\nstatic const char * const output_%d[] = {\n", d->code_number);
 
-      for (i = 0, cp = &template[1]; *cp; )
+      for (i = 0, cp = &template_code[1]; *cp; )
        {
          const char *ep, *sp;
 
        {
          const char *ep, *sp;
 
@@ -722,7 +725,7 @@ process_template (struct data *d, const char *template)
     }
   else
     {
     }
   else
     {
-      d->template = template;
+      d->template_code = template_code;
       d->output_format = INSN_OUTPUT_FORMAT_SINGLE;
     }
 }
       d->output_format = INSN_OUTPUT_FORMAT_SINGLE;
     }
 }
@@ -747,6 +750,20 @@ validate_insn_alternatives (struct data *d)
 
        for (p = d->operand[start].constraint; (c = *p); p += len)
          {
 
        for (p = d->operand[start].constraint; (c = *p); p += len)
          {
+#ifdef USE_MD_CONSTRAINTS
+           if (ISSPACE (c) || strchr (indep_constraints, c))
+             len = 1;
+           else if (ISDIGIT (c))
+             {
+               const char *q = p;
+               do
+                 q++;
+               while (ISDIGIT (*q));
+               len = q - p;
+             }
+           else
+             len = mdep_constraint_len (p, d->lineno, start);
+#else
            len = CONSTRAINT_LEN (c, p);
 
            if (len < 1 || (len > 1 && strchr (",#*+=&%!0123456789", c)))
            len = CONSTRAINT_LEN (c, p);
 
            if (len < 1 || (len > 1 && strchr (",#*+=&%!0123456789", c)))
@@ -757,6 +774,7 @@ validate_insn_alternatives (struct data *d)
                len = 1;
                have_error = 1;
              }
                len = 1;
                have_error = 1;
              }
+#endif
 
            if (c == ',')
              {
 
            if (c == ',')
              {
@@ -812,6 +830,22 @@ validate_insn_operands (struct data *d)
        have_error = 1;
       }
 }
        have_error = 1;
       }
 }
+
+static void
+validate_optab_operands (struct data *d)
+{
+  if (!d->name || d->name[0] == '\0' || d->name[0] == '*')
+    return;
+
+  /* Miscellaneous tests.  */
+  if (strncmp (d->name, "cstore", 6) == 0
+      && d->name[strlen (d->name) - 1] == '4'
+      && d->operand[0].mode == VOIDmode)
+    {
+      message_with_line (d->lineno, "missing mode for operand 0 of cstore");
+      have_error = 1;
+    }
+}
 \f
 /* Look at a define_insn just read.  Assign its code number.  Record
    on idata the template and the number of arguments.  If the insn has
 \f
 /* Look at a define_insn just read.  Assign its code number.  Record
    on idata the template and the number of arguments.  If the insn has
@@ -820,7 +854,7 @@ validate_insn_operands (struct data *d)
 static void
 gen_insn (rtx insn, int lineno)
 {
 static void
 gen_insn (rtx insn, int lineno)
 {
-  struct data *d = xmalloc (sizeof (struct data));
+  struct data *d = XNEW (struct data);
   int i;
 
   d->code_number = next_code_number;
   int i;
 
   d->code_number = next_code_number;
@@ -848,9 +882,12 @@ gen_insn (rtx insn, int lineno)
   d->n_operands = max_opno + 1;
   d->n_dups = num_dups;
 
   d->n_operands = max_opno + 1;
   d->n_dups = num_dups;
 
+#ifndef USE_MD_CONSTRAINTS
   check_constraint_len ();
   check_constraint_len ();
+#endif
   validate_insn_operands (d);
   validate_insn_alternatives (d);
   validate_insn_operands (d);
   validate_insn_alternatives (d);
+  validate_optab_operands (d);
   place_operands (d);
   process_template (d, XTMPL (insn, 3));
 }
   place_operands (d);
   process_template (d, XTMPL (insn, 3));
 }
@@ -862,7 +899,7 @@ gen_insn (rtx insn, int lineno)
 static void
 gen_peephole (rtx peep, int lineno)
 {
 static void
 gen_peephole (rtx peep, int lineno)
 {
-  struct data *d = xmalloc (sizeof (struct data));
+  struct data *d = XNEW (struct data);
   int i;
 
   d->code_number = next_code_number;
   int i;
 
   d->code_number = next_code_number;
@@ -901,7 +938,7 @@ gen_peephole (rtx peep, int lineno)
 static void
 gen_expand (rtx insn, int lineno)
 {
 static void
 gen_expand (rtx insn, int lineno)
 {
-  struct data *d = xmalloc (sizeof (struct data));
+  struct data *d = XNEW (struct data);
   int i;
 
   d->code_number = next_code_number;
   int i;
 
   d->code_number = next_code_number;
@@ -932,10 +969,11 @@ gen_expand (rtx insn, int lineno)
 
   d->n_operands = max_opno + 1;
   d->n_dups = num_dups;
 
   d->n_operands = max_opno + 1;
   d->n_dups = num_dups;
-  d->template = 0;
+  d->template_code = 0;
   d->output_format = INSN_OUTPUT_FORMAT_NONE;
 
   validate_insn_alternatives (d);
   d->output_format = INSN_OUTPUT_FORMAT_NONE;
 
   validate_insn_alternatives (d);
+  validate_optab_operands (d);
   place_operands (d);
 }
 \f
   place_operands (d);
 }
 \f
@@ -945,7 +983,7 @@ gen_expand (rtx insn, int lineno)
 static void
 gen_split (rtx split, int lineno)
 {
 static void
 gen_split (rtx split, int lineno)
 {
-  struct data *d = xmalloc (sizeof (struct data));
+  struct data *d = XNEW (struct data);
   int i;
 
   d->code_number = next_code_number;
   int i;
 
   d->code_number = next_code_number;
@@ -973,7 +1011,7 @@ gen_split (rtx split, int lineno)
   d->n_operands = max_opno + 1;
   d->n_dups = 0;
   d->n_alternatives = 0;
   d->n_operands = max_opno + 1;
   d->n_dups = 0;
   d->n_alternatives = 0;
-  d->template = 0;
+  d->template_code = 0;
   d->output_format = INSN_OUTPUT_FORMAT_NONE;
 
   place_operands (d);
   d->output_format = INSN_OUTPUT_FORMAT_NONE;
 
   place_operands (d);
@@ -1005,15 +1043,37 @@ main (int argc, char **argv)
       if (desc == NULL)
        break;
 
       if (desc == NULL)
        break;
 
-      if (GET_CODE (desc) == DEFINE_INSN)
-       gen_insn (desc, line_no);
-      if (GET_CODE (desc) == DEFINE_PEEPHOLE)
-       gen_peephole (desc, line_no);
-      if (GET_CODE (desc) == DEFINE_EXPAND)
-       gen_expand (desc, line_no);
-      if (GET_CODE (desc) == DEFINE_SPLIT
-         || GET_CODE (desc) == DEFINE_PEEPHOLE2)
-       gen_split (desc, line_no);
+      switch (GET_CODE (desc))
+       {
+       case DEFINE_INSN:
+         gen_insn (desc, line_no);
+         break;
+
+       case DEFINE_PEEPHOLE:
+         gen_peephole (desc, line_no);
+         break;
+
+       case DEFINE_EXPAND:
+         gen_expand (desc, line_no);
+         break;
+
+       case DEFINE_SPLIT:
+       case DEFINE_PEEPHOLE2:
+         gen_split (desc, line_no);
+         break;
+
+#ifdef USE_MD_CONSTRAINTS
+       case DEFINE_CONSTRAINT:
+       case DEFINE_REGISTER_CONSTRAINT:
+       case DEFINE_ADDRESS_CONSTRAINT:
+       case DEFINE_MEMORY_CONSTRAINT:
+         note_constraint (desc, line_no);
+         break;
+#endif
+
+       default:
+         break;
+       }
       next_index_number++;
     }
 
       next_index_number++;
     }
 
@@ -1056,7 +1116,7 @@ strip_whitespace (const char *s)
   if (s == 0)
     return 0;
 
   if (s == 0)
     return 0;
 
-  p = q = xmalloc (strlen (s) + 1);
+  p = q = XNEWVEC (char, strlen (s) + 1);
   while ((ch = *s++) != '\0')
     if (! ISSPACE (ch))
       *p++ = ch;
   while ((ch = *s++) != '\0')
     if (! ISSPACE (ch))
       *p++ = ch;
@@ -1065,6 +1125,105 @@ strip_whitespace (const char *s)
   return q;
 }
 
   return q;
 }
 
+#ifdef USE_MD_CONSTRAINTS
+
+/* Record just enough information about a constraint to allow checking
+   of operand constraint strings above, in validate_insn_alternatives.
+   Does not validate most properties of the constraint itself; does
+   enforce no duplicate names, no overlap with MI constraints, and no
+   prefixes.  EXP is the define_*constraint form, LINENO the line number
+   reported by the reader.  */
+static void
+note_constraint (rtx exp, int lineno)
+{
+  const char *name = XSTR (exp, 0);
+  unsigned int namelen = strlen (name);
+  struct constraint_data **iter, **slot, *new_cdata;
+
+  /* The 'm' constraint is special here since that constraint letter
+     can be overridden by the back end by defining the
+     TARGET_MEM_CONSTRAINT macro.  */
+  if (strchr (indep_constraints, name[0]) && name[0] != 'm')
+    {
+      if (name[1] == '\0')
+       message_with_line (lineno, "constraint letter '%s' cannot be "
+                          "redefined by the machine description", name);
+      else
+       message_with_line (lineno, "constraint name '%s' cannot be defined by "
+                          "the machine description, as it begins with '%c'",
+                          name, name[0]);
+      have_error = 1;
+      return;
+    }
+
+  slot = &constraints_by_letter_table[(unsigned int)name[0]];
+  for (iter = slot; *iter; iter = &(*iter)->next_this_letter)
+    {
+      /* This causes slot to end up pointing to the
+        next_this_letter field of the last constraint with a name
+        of equal or greater length than the new constraint; hence
+        the new constraint will be inserted after all previous
+        constraints with names of the same length.  */
+      if ((*iter)->namelen >= namelen)
+       slot = iter;
+
+      if (!strcmp ((*iter)->name, name))
+       {
+         message_with_line (lineno, "redefinition of constraint '%s'", name);
+         message_with_line ((*iter)->lineno, "previous definition is here");
+         have_error = 1;
+         return;
+       }
+      else if (!strncmp ((*iter)->name, name, (*iter)->namelen))
+       {
+         message_with_line (lineno, "defining constraint '%s' here", name);
+         message_with_line ((*iter)->lineno, "renders constraint '%s' "
+                            "(defined here) a prefix", (*iter)->name);
+         have_error = 1;
+         return;
+       }
+      else if (!strncmp ((*iter)->name, name, namelen))
+       {
+         message_with_line (lineno, "constraint '%s' is a prefix", name);
+         message_with_line ((*iter)->lineno, "of constraint '%s' "
+                            "(defined here)", (*iter)->name);
+         have_error = 1;
+         return;
+       }
+    }
+  new_cdata = XNEWVAR (struct constraint_data, sizeof (struct constraint_data) + namelen);
+  strcpy ((char *)new_cdata + offsetof(struct constraint_data, name), name);
+  new_cdata->namelen = namelen;
+  new_cdata->lineno = lineno;
+  new_cdata->next_this_letter = *slot;
+  *slot = new_cdata;
+}
+
+/* Return the length of the constraint name beginning at position S
+   of an operand constraint string, or issue an error message if there
+   is no such constraint.  Does not expect to be called for generic
+   constraints.  */
+static int
+mdep_constraint_len (const char *s, int lineno, int opno)
+{
+  struct constraint_data *p;
+
+  p = constraints_by_letter_table[(unsigned int)s[0]];
+
+  if (p)
+    for (; p; p = p->next_this_letter)
+      if (!strncmp (s, p->name, p->namelen))
+       return p->namelen;
+
+  message_with_line (lineno,
+                    "error: undefined machine-specific constraint "
+                    "at this point: \"%s\"", s);
+  message_with_line (lineno, "note:  in operand %d", opno);
+  have_error = 1;
+  return 1; /* safe */
+}
+
+#else
 /* Verify that DEFAULT_CONSTRAINT_LEN is used properly and not
    tampered with.  This isn't bullet-proof, but it should catch
    most genuine mistakes.  */
 /* Verify that DEFAULT_CONSTRAINT_LEN is used properly and not
    tampered with.  This isn't bullet-proof, but it should catch
    most genuine mistakes.  */
@@ -1098,3 +1257,4 @@ constraint_len (const char *p, int genoutput_default_constraint_len)
 #undef DEFAULT_CONSTRAINT_LEN
 #define DEFAULT_CONSTRAINT_LEN(C,STR) 1
 }
 #undef DEFAULT_CONSTRAINT_LEN
 #define DEFAULT_CONSTRAINT_LEN(C,STR) 1
 }
+#endif