OSDN Git Service

* gensupport.c (process_one_cond_exec): Derive name for COND_EXEC
[pf3gnuchains/gcc-fork.git] / gcc / gensupport.c
index 2acfc8a..3a96af8 100644 (file)
@@ -1,12 +1,12 @@
 /* Support routines for the various generation passes.
-   Copyright (C) 2000, 2001, 2002, 2003, 2004
+   Copyright (C) 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009
    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 Software Foundation; either version 2, or (at your option)
+   the Free 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
@@ -15,9 +15,8 @@
    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/>.  */
 
 #include "bconfig.h"
 #include "system.h"
@@ -35,6 +34,12 @@ int target_flags;
 
 int insn_elision = 1;
 
+const char *in_fname;
+
+/* This callback will be invoked whenever an rtl include directive is
+   processed.  To be used for creation of the dependency file.  */
+void (*include_callback) (const char *);
+
 static struct obstack obstack;
 struct obstack *rtl_obstack = &obstack;
 
@@ -65,6 +70,8 @@ struct queue_elem
 
 static struct queue_elem *define_attr_queue;
 static struct queue_elem **define_attr_tail = &define_attr_queue;
+static struct queue_elem *define_pred_queue;
+static struct queue_elem **define_pred_tail = &define_pred_queue;
 static struct queue_elem *define_insn_queue;
 static struct queue_elem **define_insn_tail = &define_insn_queue;
 static struct queue_elem *define_cond_exec_queue;
@@ -109,6 +116,8 @@ static void process_one_cond_exec (struct queue_elem *);
 static void process_define_cond_exec (void);
 static void process_include (rtx, int);
 static char *save_string (const char *, int);
+static void init_predicate_table (void);
+static void record_insn_name (int, const char *);
 \f
 void
 message_with_line (int lineno, const char *msg, ...)
@@ -240,21 +249,12 @@ process_include (rtx desc, int lineno)
   read_rtx_filename = pathname;
   read_rtx_lineno = 1;
 
-  /* Read the entire file.  */
-  while (1)
-    {
-      rtx desc;
-      int c;
+  if (include_callback)
+    include_callback (pathname);
 
-      c = read_skip_spaces (input_file);
-      if (c == EOF)
-       break;
-
-      ungetc (c, input_file);
-      lineno = read_rtx_lineno;
-      desc = read_rtx (input_file);
-      process_rtx (desc, lineno);
-    }
+  /* Read the entire file.  */
+  while (read_rtx (input_file, &desc, &lineno))
+    process_rtx (desc, lineno);
 
   /* Do not free pathname.  It is attached to the various rtx queue
      elements.  */
@@ -284,6 +284,15 @@ process_rtx (rtx desc, int lineno)
       queue_pattern (desc, &define_attr_tail, read_rtx_filename, lineno);
       break;
 
+    case DEFINE_PREDICATE:
+    case DEFINE_SPECIAL_PREDICATE:
+    case DEFINE_CONSTRAINT:
+    case DEFINE_REGISTER_CONSTRAINT:
+    case DEFINE_MEMORY_CONSTRAINT:
+    case DEFINE_ADDRESS_CONSTRAINT:
+      queue_pattern (desc, &define_pred_tail, read_rtx_filename, lineno);
+      break;
+
     case INCLUDE:
       process_include (desc, lineno);
       break;
@@ -312,7 +321,10 @@ process_rtx (rtx desc, int lineno)
           insn condition to create the new split condition.  */
        split_cond = XSTR (desc, 4);
        if (split_cond[0] == '&' && split_cond[1] == '&')
-         split_cond = concat (XSTR (desc, 2), split_cond, NULL);
+         {
+           copy_rtx_ptr_loc (split_cond + 2, split_cond);
+           split_cond = join_c_conditions (XSTR (desc, 2), split_cond + 2);
+         }
        XSTR (split, 1) = split_cond;
        XVEC (split, 2) = XVEC (desc, 5);
        XSTR (split, 3) = XSTR (desc, 6);
@@ -324,7 +336,7 @@ process_rtx (rtx desc, int lineno)
 
        /* Queue them.  */
        insn_elem
-         = queue_pattern (desc, &define_insn_tail, read_rtx_filename, 
+         = queue_pattern (desc, &define_insn_tail, read_rtx_filename,
                           lineno);
        split_elem
          = queue_pattern (split, &other_tail, read_rtx_filename, lineno);
@@ -394,7 +406,7 @@ is_predicable (struct queue_elem *elem)
          return 0;
 
        default:
-         abort ();
+         gcc_unreachable ();
        }
     }
 
@@ -455,6 +467,8 @@ identify_predicable_attribute (void)
       message_with_line (elem->lineno,
                         "attribute `predicable' is not a boolean");
       errors = 1;
+      if (p_false)
+        free (p_false);
       return;
     }
   p_true[-1] = '\0';
@@ -472,12 +486,16 @@ identify_predicable_attribute (void)
       message_with_line (elem->lineno,
                         "attribute `predicable' cannot be const");
       errors = 1;
+      if (p_false)
+       free (p_false);
       return;
 
     default:
       message_with_line (elem->lineno,
                         "attribute `predicable' must have a constant default");
       errors = 1;
+      if (p_false)
+       free (p_false);
       return;
     }
 
@@ -491,6 +509,8 @@ identify_predicable_attribute (void)
                         "unknown value `%s' for `predicable' attribute",
                         value);
       errors = 1;
+      if (p_false)
+       free (p_false);
     }
 }
 
@@ -561,7 +581,7 @@ collect_insn_data (rtx pattern, int *palt, int *pmax)
          break;
 
        default:
-         abort ();
+         gcc_unreachable ();
        }
     }
 }
@@ -647,7 +667,7 @@ alter_predicate_for_insn (rtx pattern, int alt, int max_op, int lineno)
          break;
 
        default:
-         abort ();
+         gcc_unreachable ();
        }
     }
 
@@ -658,16 +678,8 @@ static const char *
 alter_test_for_insn (struct queue_elem *ce_elem,
                     struct queue_elem *insn_elem)
 {
-  const char *ce_test, *insn_test;
-
-  ce_test = XSTR (ce_elem->data, 1);
-  insn_test = XSTR (insn_elem->data, 2);
-  if (!ce_test || *ce_test == '\0')
-    return insn_test;
-  if (!insn_test || *insn_test == '\0')
-    return ce_test;
-
-  return concat ("(", ce_test, ") && (", insn_test, ")", NULL);
+  return join_c_conditions (XSTR (ce_elem->data, 1),
+                           XSTR (insn_elem->data, 2));
 }
 
 /* Adjust all of the operand numbers in SRC to match the shift they'll
@@ -768,6 +780,7 @@ process_one_cond_exec (struct queue_elem *ce_elem)
     {
       int alternatives, max_operand;
       rtx pred, insn, pattern, split;
+      char *new_name;
       int i;
 
       if (! is_predicable (insn_elem))
@@ -794,7 +807,9 @@ process_one_cond_exec (struct queue_elem *ce_elem)
 
       /* Construct a new pattern for the new insn.  */
       insn = copy_rtx (insn_elem->data);
-      XSTR (insn, 0) = "";
+      new_name = XNEWVAR (char, strlen XSTR (insn_elem->data, 0) + 4);
+      sprintf (new_name, "*p %s", XSTR (insn_elem->data, 0));
+      XSTR (insn, 0) = new_name;
       pattern = rtx_alloc (COND_EXEC);
       XEXP (pattern, 0) = pred;
       if (XVECLEN (insn, 1) == 1)
@@ -863,7 +878,7 @@ process_one_cond_exec (struct queue_elem *ce_elem)
          XVECEXP (split, 2, i) = pattern;
        }
       /* Add the new split to the queue.  */
-      queue_pattern (split, &other_tail, read_rtx_filename, 
+      queue_pattern (split, &other_tail, read_rtx_filename,
                     insn_elem->split->lineno);
     }
 }
@@ -901,101 +916,148 @@ int
 init_md_reader_args_cb (int argc, char **argv, bool (*parse_opt)(const char *))
 {
   FILE *input_file;
-  int i;
-  size_t ix;
+  int c, i, lineno;
   char *lastsl;
-  const char *in_fname;
+  rtx desc;
+  bool no_more_options;
+  bool already_read_stdin;
 
-  max_include_len = 0;
-  in_fname = NULL;
+  /* Unlock the stdio streams.  */
+  unlock_std_streams ();
+
+  /* First we loop over all the options.  */
   for (i = 1; i < argc; i++)
     {
       if (argv[i][0] != '-')
-       {
-         if (in_fname)
-           fatal ("too many input files");
+       continue;
 
-         in_fname = argv[i];
-       }
-      else
+      c = argv[i][1];
+      switch (c)
        {
-         int c = argv[i][1];
-         switch (c)
-           {
-           case 'I':           /* Add directory to path for includes.  */
-             {
-               struct file_name_list *dirtmp;
-
-               dirtmp = XNEW (struct file_name_list);
-               dirtmp->next = 0;       /* New one goes on the end */
-               if (first_dir_md_include == 0)
-                 first_dir_md_include = dirtmp;
-               else
-                 last_dir_md_include->next = dirtmp;
-               last_dir_md_include = dirtmp;   /* Tail follows the last one */
-               if (argv[i][1] == 'I' && argv[i][2] != 0)
-                 dirtmp->fname = argv[i] + 2;
-               else if (i + 1 == argc)
-                 fatal ("directory name missing after -I option");
-               else
-                 dirtmp->fname = argv[++i];
-               if (strlen (dirtmp->fname) > max_include_len)
-                 max_include_len = strlen (dirtmp->fname);
-             }
-             break;
-           default:
-             /* The program may have provided a callback so it can
-                accept its own options.  */
-             if (parse_opt && parse_opt (argv[i]))
-               break;
-
-             fatal ("invalid option `%s'", argv[i]);
-           }
-       }
-    }
+       case 'I':               /* Add directory to path for includes.  */
+         {
+           struct file_name_list *dirtmp;
+
+           dirtmp = XNEW (struct file_name_list);
+           dirtmp->next = 0;   /* New one goes on the end */
+           if (first_dir_md_include == 0)
+             first_dir_md_include = dirtmp;
+           else
+             last_dir_md_include->next = dirtmp;
+           last_dir_md_include = dirtmp;       /* Tail follows the last one */
+           if (argv[i][1] == 'I' && argv[i][2] != 0)
+             dirtmp->fname = argv[i] + 2;
+           else if (i + 1 == argc)
+             fatal ("directory name missing after -I option");
+           else
+             dirtmp->fname = argv[++i];
+           if (strlen (dirtmp->fname) > max_include_len)
+             max_include_len = strlen (dirtmp->fname);
+         }
+         break;
 
-  if (!in_fname)
-    fatal ("no input file name");
+       case '\0':
+         /* An argument consisting of exactly one dash is a request to
+            read stdin.  This will be handled in the second loop.  */
+         continue;
 
-  lastsl = strrchr (in_fname, '/');
-  if (lastsl != NULL)
-    base_dir = save_string (in_fname, lastsl - in_fname + 1 );
+       case '-':
+         /* An argument consisting of just two dashes causes option
+            parsing to cease.  */
+         if (argv[i][2] == '\0')
+           goto stop_parsing_options;
 
-  read_rtx_filename = in_fname;
-  input_file = fopen (in_fname, "r");
-  if (input_file == 0)
-    {
-      perror (in_fname);
-      return FATAL_EXIT_CODE;
-    }
+       default:
+         /* The program may have provided a callback so it can
+            accept its own options.  */
+         if (parse_opt && parse_opt (argv[i]))
+           break;
 
-  /* Initialize the table of insn conditions.  */
-  condition_table = htab_create (n_insn_conditions,
-                                hash_c_test, cmp_c_test, NULL);
+         fatal ("invalid option `%s'", argv[i]);
+       }
+    }
 
-  for (ix = 0; ix < n_insn_conditions; ix++)
-    *(htab_find_slot (condition_table, &insn_conditions[ix], INSERT))
-      = (void *) &insn_conditions[ix];
+ stop_parsing_options:
 
+  /* Prepare to read input.  */
+  condition_table = htab_create (500, hash_c_test, cmp_c_test, NULL);
+  init_predicate_table ();
   obstack_init (rtl_obstack);
   errors = 0;
   sequence_num = 0;
+  no_more_options = false;
+  already_read_stdin = false;
 
-  /* Read the entire file.  */
-  while (1)
+
+  /* Now loop over all input files.  */
+  for (i = 1; i < argc; i++)
     {
-      rtx desc;
-      int lineno;
-      int c = read_skip_spaces (input_file);
-      if (c == EOF)
-        break;
-
-      ungetc (c, input_file);
-      lineno = read_rtx_lineno;
-      desc = read_rtx (input_file);
-      process_rtx (desc, lineno);
+      if (argv[i][0] == '-')
+       {
+         if (argv[i][1] == '\0')
+           {
+             /* Read stdin.  */
+             if (already_read_stdin)
+               fatal ("cannot read standard input twice");
+
+             base_dir = NULL;
+             read_rtx_filename = in_fname = "<stdin>";
+             read_rtx_lineno = 1;
+             input_file = stdin;
+             already_read_stdin = true;
+
+             while (read_rtx (input_file, &desc, &lineno))
+               process_rtx (desc, lineno);
+             fclose (input_file);
+             continue;
+           }
+         else if (argv[i][1] == '-' && argv[i][2] == '\0')
+           {
+             /* No further arguments are to be treated as options.  */
+             no_more_options = true;
+             continue;
+           }
+         else if (!no_more_options)
+           continue;
+       }
+
+      /* If we get here we are looking at a non-option argument, i.e.
+        a file to be processed.  */
+
+      in_fname = argv[i];
+      lastsl = strrchr (in_fname, '/');
+      if (lastsl != NULL)
+       base_dir = save_string (in_fname, lastsl - in_fname + 1 );
+      else
+       base_dir = NULL;
+
+      read_rtx_filename = in_fname;
+      read_rtx_lineno = 1;
+      input_file = fopen (in_fname, "r");
+      if (input_file == 0)
+       {
+         perror (in_fname);
+         return FATAL_EXIT_CODE;
+       }
+
+      while (read_rtx (input_file, &desc, &lineno))
+       process_rtx (desc, lineno);
+      fclose (input_file);
+    }
+
+  /* If we get to this point without having seen any files to process,
+     read standard input now.  */
+  if (!in_fname)
+    {
+      base_dir = NULL;
+      read_rtx_filename = in_fname = "<stdin>";
+      read_rtx_lineno = 1;
+      input_file = stdin;
+
+      while (read_rtx (input_file, &desc, &lineno))
+       process_rtx (desc, lineno);
+      fclose (input_file);
     }
-  fclose (input_file);
 
   /* Process define_cond_exec patterns.  */
   if (define_cond_exec_queue != NULL)
@@ -1025,6 +1087,8 @@ read_md_rtx (int *lineno, int *seqnr)
   /* Read all patterns from a given queue before moving on to the next.  */
   if (define_attr_queue != NULL)
     queue = &define_attr_queue;
+  else if (define_pred_queue != NULL)
+    queue = &define_pred_queue;
   else if (define_insn_queue != NULL)
     queue = &define_insn_queue;
   else if (other_queue != NULL)
@@ -1055,6 +1119,10 @@ read_md_rtx (int *lineno, int *seqnr)
        sequence_num++;
       else if (insn_elision)
        goto discard;
+
+      /* *seqnr is used here so the name table will match caller's
+        idea of insn numbering, whether or not elision is active.  */
+      record_insn_name (*seqnr, XSTR (desc, 0));
       break;
 
     case DEFINE_SPLIT:
@@ -1125,17 +1193,41 @@ maybe_eval_c_test (const char *expr)
   if (expr[0] == 0)
     return 1;
 
-  if (insn_elision_unavailable)
-    return -1;
-
   dummy.expr = expr;
   test = (const struct c_test *)htab_find (condition_table, &dummy);
   if (!test)
-    abort ();
-
+    return -1;
   return test->value;
 }
 
+/* Record the C test expression EXPR in the condition_table, with
+   value VAL.  Duplicates clobber previous entries.  */
+
+void
+add_c_test (const char *expr, int value)
+{
+  struct c_test *test;
+
+  if (expr[0] == 0)
+    return;
+
+  test = XNEW (struct c_test);
+  test->expr = expr;
+  test->value = value;
+
+  *(htab_find_slot (condition_table, test, INSERT)) = test;
+}
+
+/* For every C test, call CALLBACK with two arguments: a pointer to
+   the condition structure and INFO.  Stops when CALLBACK returns zero.  */
+void
+traverse_c_tests (htab_trav callback, void *info)
+{
+  if (condition_table)
+    htab_traverse (condition_table, callback, info);
+}
+
+
 /* Given a string, return the number of comma-separated elements in it.
    Return 0 for the null string.  */
 int
@@ -1181,3 +1273,189 @@ scan_comma_elt (const char **pstr)
   *pstr = p;
   return start;
 }
+
+/* Helper functions for define_predicate and define_special_predicate
+   processing.  Shared between genrecog.c and genpreds.c.  */
+
+static htab_t predicate_table;
+struct pred_data *first_predicate;
+static struct pred_data **last_predicate = &first_predicate;
+
+static hashval_t
+hash_struct_pred_data (const void *ptr)
+{
+  return htab_hash_string (((const struct pred_data *)ptr)->name);
+}
+
+static int
+eq_struct_pred_data (const void *a, const void *b)
+{
+  return !strcmp (((const struct pred_data *)a)->name,
+                 ((const struct pred_data *)b)->name);
+}
+
+struct pred_data *
+lookup_predicate (const char *name)
+{
+  struct pred_data key;
+  key.name = name;
+  return (struct pred_data *) htab_find (predicate_table, &key);
+}
+
+/* Record that predicate PRED can accept CODE.  */
+
+void
+add_predicate_code (struct pred_data *pred, enum rtx_code code)
+{
+  if (!pred->codes[code])
+    {
+      pred->num_codes++;
+      pred->codes[code] = true;
+
+      if (GET_RTX_CLASS (code) != RTX_CONST_OBJ)
+       pred->allows_non_const = true;
+
+      if (code != REG
+         && code != SUBREG
+         && code != MEM
+         && code != CONCAT
+         && code != PARALLEL
+         && code != STRICT_LOW_PART)
+       pred->allows_non_lvalue = true;
+
+      if (pred->num_codes == 1)
+       pred->singleton = code;
+      else if (pred->num_codes == 2)
+       pred->singleton = UNKNOWN;
+    }
+}
+
+void
+add_predicate (struct pred_data *pred)
+{
+  void **slot = htab_find_slot (predicate_table, pred, INSERT);
+  if (*slot)
+    {
+      error ("duplicate predicate definition for '%s'", pred->name);
+      return;
+    }
+  *slot = pred;
+  *last_predicate = pred;
+  last_predicate = &pred->next;
+}
+
+/* This array gives the initial content of the predicate table.  It
+   has entries for all predicates defined in recog.c.  */
+
+struct std_pred_table
+{
+  const char *name;
+  bool special;
+  bool allows_const_p;
+  RTX_CODE codes[NUM_RTX_CODE];
+};
+
+static const struct std_pred_table std_preds[] = {
+  {"general_operand", false, true, {SUBREG, REG, MEM}},
+  {"address_operand", true, true, {SUBREG, REG, MEM, PLUS, MINUS, MULT}},
+  {"register_operand", false, false, {SUBREG, REG}},
+  {"pmode_register_operand", true, false, {SUBREG, REG}},
+  {"scratch_operand", false, false, {SCRATCH, REG}},
+  {"immediate_operand", false, true, {UNKNOWN}},
+  {"const_int_operand", false, false, {CONST_INT}},
+  {"const_double_operand", false, false, {CONST_INT, CONST_DOUBLE}},
+  {"nonimmediate_operand", false, false, {SUBREG, REG, MEM}},
+  {"nonmemory_operand", false, true, {SUBREG, REG}},
+  {"push_operand", false, false, {MEM}},
+  {"pop_operand", false, false, {MEM}},
+  {"memory_operand", false, false, {SUBREG, MEM}},
+  {"indirect_operand", false, false, {SUBREG, MEM}},
+  {"ordered_comparison_operator", false, false, {EQ, NE,
+                                                LE, LT, GE, GT,
+                                                LEU, LTU, GEU, GTU}},
+  {"comparison_operator", false, false, {EQ, NE,
+                                        LE, LT, GE, GT,
+                                        LEU, LTU, GEU, GTU,
+                                        UNORDERED, ORDERED,
+                                        UNEQ, UNGE, UNGT,
+                                        UNLE, UNLT, LTGT}}
+};
+#define NUM_KNOWN_STD_PREDS ARRAY_SIZE (std_preds)
+
+/* Initialize the table of predicate definitions, starting with
+   the information we have on generic predicates.  */
+
+static void
+init_predicate_table (void)
+{
+  size_t i, j;
+  struct pred_data *pred;
+
+  predicate_table = htab_create_alloc (37, hash_struct_pred_data,
+                                      eq_struct_pred_data, 0,
+                                      xcalloc, free);
+
+  for (i = 0; i < NUM_KNOWN_STD_PREDS; i++)
+    {
+      pred = XCNEW (struct pred_data);
+      pred->name = std_preds[i].name;
+      pred->special = std_preds[i].special;
+
+      for (j = 0; std_preds[i].codes[j] != 0; j++)
+       add_predicate_code (pred, std_preds[i].codes[j]);
+
+      if (std_preds[i].allows_const_p)
+       for (j = 0; j < NUM_RTX_CODE; j++)
+         if (GET_RTX_CLASS (j) == RTX_CONST_OBJ)
+           add_predicate_code (pred, (enum rtx_code) j);
+
+      add_predicate (pred);
+    }
+}
+\f
+/* These functions allow linkage with print-rtl.c.  Also, some generators
+   like to annotate their output with insn names.  */
+
+/* Holds an array of names indexed by insn_code_number.  */
+static char **insn_name_ptr = 0;
+static int insn_name_ptr_size = 0;
+
+const char *
+get_insn_name (int code)
+{
+  if (code < insn_name_ptr_size)
+    return insn_name_ptr[code];
+  else
+    return NULL;
+}
+
+static void
+record_insn_name (int code, const char *name)
+{
+  static const char *last_real_name = "insn";
+  static int last_real_code = 0;
+  char *new_name;
+
+  if (insn_name_ptr_size <= code)
+    {
+      int new_size;
+      new_size = (insn_name_ptr_size ? insn_name_ptr_size * 2 : 512);
+      insn_name_ptr = XRESIZEVEC (char *, insn_name_ptr, 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;
+    }
+
+  if (!name || name[0] == '\0')
+    {
+      new_name = XNEWVAR (char, strlen (last_real_name) + 10);
+      sprintf (new_name, "%s+%d", last_real_name, code - last_real_code);
+    }
+  else
+    {
+      last_real_name = new_name = xstrdup (name);
+      last_real_code = code;
+    }
+
+  insn_name_ptr[code] = new_name;
+}