read-rtl.c revision 132718
1132718Skan/* RTL reader for GCC.
2132718Skan   Copyright (C) 1987, 1988, 1991, 1994, 1997, 1998, 1999, 2000, 2001, 2002,
3132718Skan   2003
490075Sobrien   Free Software Foundation, Inc.
590075Sobrien
690075SobrienThis file is part of GCC.
790075Sobrien
890075SobrienGCC is free software; you can redistribute it and/or modify it under
990075Sobrienthe terms of the GNU General Public License as published by the Free
1090075SobrienSoftware Foundation; either version 2, or (at your option) any later
1190075Sobrienversion.
1290075Sobrien
1390075SobrienGCC is distributed in the hope that it will be useful, but WITHOUT ANY
1490075SobrienWARRANTY; without even the implied warranty of MERCHANTABILITY or
1590075SobrienFITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
1690075Sobrienfor more details.
1790075Sobrien
1890075SobrienYou should have received a copy of the GNU General Public License
1990075Sobrienalong with GCC; see the file COPYING.  If not, write to the Free
2090075SobrienSoftware Foundation, 59 Temple Place - Suite 330, Boston, MA
2190075Sobrien02111-1307, USA.  */
2290075Sobrien
23132718Skan#include "bconfig.h"
2490075Sobrien#include "system.h"
25132718Skan#include "coretypes.h"
26132718Skan#include "tm.h"
2790075Sobrien#include "rtl.h"
2890075Sobrien#include "obstack.h"
2990075Sobrien#include "hashtab.h"
3090075Sobrien
3190075Sobrienstatic htab_t md_constants;
3290075Sobrien
33132718Skanstatic void fatal_with_file_and_line (FILE *, const char *, ...)
3490075Sobrien  ATTRIBUTE_PRINTF_2 ATTRIBUTE_NORETURN;
35132718Skanstatic void fatal_expected_char (FILE *, int, int) ATTRIBUTE_NORETURN;
36132718Skanstatic void read_name (char *, FILE *);
37132718Skanstatic char *read_string (struct obstack *, FILE *, int);
38132718Skanstatic char *read_quoted_string (struct obstack *, FILE *);
39132718Skanstatic char *read_braced_string (struct obstack *, FILE *);
40132718Skanstatic void read_escape (struct obstack *, FILE *);
41132718Skanstatic hashval_t def_hash (const void *);
42132718Skanstatic int def_name_eq_p (const void *, const void *);
43132718Skanstatic void read_constants (FILE *infile, char *tmp_char);
44132718Skanstatic void validate_const_int (FILE *, const char *);
4590075Sobrien
4690075Sobrien/* Subroutines of read_rtx.  */
4790075Sobrien
4890075Sobrien/* The current line number for the file.  */
4990075Sobrienint read_rtx_lineno = 1;
5090075Sobrien
5190075Sobrien/* The filename for aborting with file and line.  */
5290075Sobrienconst char *read_rtx_filename = "<unknown>";
5390075Sobrien
5490075Sobrienstatic void
55132718Skanfatal_with_file_and_line (FILE *infile, const char *msg, ...)
5690075Sobrien{
5790075Sobrien  char context[64];
5890075Sobrien  size_t i;
5990075Sobrien  int c;
60132718Skan  va_list ap;
6190075Sobrien
62132718Skan  va_start (ap, msg);
6390075Sobrien
6490075Sobrien  fprintf (stderr, "%s:%d: ", read_rtx_filename, read_rtx_lineno);
6590075Sobrien  vfprintf (stderr, msg, ap);
6690075Sobrien  putc ('\n', stderr);
6790075Sobrien
6890075Sobrien  /* Gather some following context.  */
6990075Sobrien  for (i = 0; i < sizeof (context)-1; ++i)
7090075Sobrien    {
7190075Sobrien      c = getc (infile);
7290075Sobrien      if (c == EOF)
7390075Sobrien	break;
7490075Sobrien      if (c == '\r' || c == '\n')
7590075Sobrien	break;
7690075Sobrien      context[i] = c;
7790075Sobrien    }
7890075Sobrien  context[i] = '\0';
7990075Sobrien
8090075Sobrien  fprintf (stderr, "%s:%d: following context is `%s'\n",
8190075Sobrien	   read_rtx_filename, read_rtx_lineno, context);
8290075Sobrien
83132718Skan  va_end (ap);
8490075Sobrien  exit (1);
8590075Sobrien}
8690075Sobrien
8790075Sobrien/* Dump code after printing a message.  Used when read_rtx finds
8890075Sobrien   invalid data.  */
8990075Sobrien
9090075Sobrienstatic void
91132718Skanfatal_expected_char (FILE *infile, int expected_c, int actual_c)
9290075Sobrien{
9390075Sobrien  fatal_with_file_and_line (infile, "expected character `%c', found `%c'",
9490075Sobrien			    expected_c, actual_c);
9590075Sobrien}
9690075Sobrien
9790075Sobrien/* Read chars from INFILE until a non-whitespace char
9890075Sobrien   and return that.  Comments, both Lisp style and C style,
9990075Sobrien   are treated as whitespace.
10090075Sobrien   Tools such as genflags use this function.  */
10190075Sobrien
10290075Sobrienint
103132718Skanread_skip_spaces (FILE *infile)
10490075Sobrien{
10590075Sobrien  int c;
10690075Sobrien
10790075Sobrien  while (1)
10890075Sobrien    {
10990075Sobrien      c = getc (infile);
11090075Sobrien      switch (c)
11190075Sobrien	{
11290075Sobrien	case '\n':
11390075Sobrien	  read_rtx_lineno++;
11490075Sobrien	  break;
11590075Sobrien
11690075Sobrien	case ' ': case '\t': case '\f': case '\r':
11790075Sobrien	  break;
11890075Sobrien
11990075Sobrien	case ';':
12090075Sobrien	  do
12190075Sobrien	    c = getc (infile);
12290075Sobrien	  while (c != '\n' && c != EOF);
12390075Sobrien	  read_rtx_lineno++;
12490075Sobrien	  break;
12590075Sobrien
12690075Sobrien	case '/':
12790075Sobrien	  {
12890075Sobrien	    int prevc;
12990075Sobrien	    c = getc (infile);
13090075Sobrien	    if (c != '*')
13190075Sobrien	      fatal_expected_char (infile, '*', c);
13290075Sobrien
13390075Sobrien	    prevc = 0;
13490075Sobrien	    while ((c = getc (infile)) && c != EOF)
13590075Sobrien	      {
13690075Sobrien		if (c == '\n')
13790075Sobrien		   read_rtx_lineno++;
13890075Sobrien	        else if (prevc == '*' && c == '/')
13990075Sobrien		  break;
14090075Sobrien	        prevc = c;
14190075Sobrien	      }
14290075Sobrien	  }
14390075Sobrien	  break;
14490075Sobrien
14590075Sobrien	default:
14690075Sobrien	  return c;
14790075Sobrien	}
14890075Sobrien    }
14990075Sobrien}
15090075Sobrien
15190075Sobrien/* Read an rtx code name into the buffer STR[].
15290075Sobrien   It is terminated by any of the punctuation chars of rtx printed syntax.  */
15390075Sobrien
15490075Sobrienstatic void
155132718Skanread_name (char *str, FILE *infile)
15690075Sobrien{
15790075Sobrien  char *p;
15890075Sobrien  int c;
15990075Sobrien
16090075Sobrien  c = read_skip_spaces (infile);
16190075Sobrien
16290075Sobrien  p = str;
16390075Sobrien  while (1)
16490075Sobrien    {
16590075Sobrien      if (c == ' ' || c == '\n' || c == '\t' || c == '\f' || c == '\r')
16690075Sobrien	break;
16790075Sobrien      if (c == ':' || c == ')' || c == ']' || c == '"' || c == '/'
16890075Sobrien	  || c == '(' || c == '[')
16990075Sobrien	{
17090075Sobrien	  ungetc (c, infile);
17190075Sobrien	  break;
17290075Sobrien	}
17390075Sobrien      *p++ = c;
17490075Sobrien      c = getc (infile);
17590075Sobrien    }
17690075Sobrien  if (p == str)
17790075Sobrien    fatal_with_file_and_line (infile, "missing name or number");
17890075Sobrien  if (c == '\n')
17990075Sobrien    read_rtx_lineno++;
18090075Sobrien
18190075Sobrien  *p = 0;
18290075Sobrien
18390075Sobrien  if (md_constants)
18490075Sobrien    {
18590075Sobrien      /* Do constant expansion.  */
18690075Sobrien      struct md_constant *def;
18790075Sobrien
18890075Sobrien      p = str;
18990075Sobrien      do
19090075Sobrien	{
19190075Sobrien	  struct md_constant tmp_def;
19290075Sobrien
19390075Sobrien	  tmp_def.name = p;
19490075Sobrien	  def = htab_find (md_constants, &tmp_def);
19590075Sobrien	  if (def)
19690075Sobrien	    p = def->value;
19790075Sobrien	} while (def);
19890075Sobrien      if (p != str)
19990075Sobrien	strcpy (str, p);
20090075Sobrien    }
20190075Sobrien}
20290075Sobrien
20390075Sobrien/* Subroutine of the string readers.  Handles backslash escapes.
20490075Sobrien   Caller has read the backslash, but not placed it into the obstack.  */
20590075Sobrienstatic void
206132718Skanread_escape (struct obstack *ob, FILE *infile)
20790075Sobrien{
20890075Sobrien  int c = getc (infile);
20990075Sobrien
21090075Sobrien  switch (c)
21190075Sobrien    {
21290075Sobrien      /* Backslash-newline is replaced by nothing, as in C.  */
21390075Sobrien    case '\n':
21490075Sobrien      read_rtx_lineno++;
21590075Sobrien      return;
21690075Sobrien
21790075Sobrien      /* \" \' \\ are replaced by the second character.  */
21890075Sobrien    case '\\':
21990075Sobrien    case '"':
22090075Sobrien    case '\'':
22190075Sobrien      break;
22290075Sobrien
22390075Sobrien      /* Standard C string escapes:
22490075Sobrien	 \a \b \f \n \r \t \v
22590075Sobrien	 \[0-7] \x
22690075Sobrien	 all are passed through to the output string unmolested.
22790075Sobrien	 In normal use these wind up in a string constant processed
22890075Sobrien	 by the C compiler, which will translate them appropriately.
22990075Sobrien	 We do not bother checking that \[0-7] are followed by up to
23090075Sobrien	 two octal digits, or that \x is followed by N hex digits.
23190075Sobrien	 \? \u \U are left out because they are not in traditional C.  */
23290075Sobrien    case 'a': case 'b': case 'f': case 'n': case 'r': case 't': case 'v':
23390075Sobrien    case '0': case '1': case '2': case '3': case '4': case '5': case '6':
23490075Sobrien    case '7': case 'x':
23590075Sobrien      obstack_1grow (ob, '\\');
23690075Sobrien      break;
23790075Sobrien
23890075Sobrien      /* \; makes stuff for a C string constant containing
23990075Sobrien	 newline and tab.  */
24090075Sobrien    case ';':
24190075Sobrien      obstack_grow (ob, "\\n\\t", 4);
24290075Sobrien      return;
24390075Sobrien
24490075Sobrien      /* pass anything else through, but issue a warning.  */
24590075Sobrien    default:
24690075Sobrien      fprintf (stderr, "%s:%d: warning: unrecognized escape \\%c\n",
24790075Sobrien	       read_rtx_filename, read_rtx_lineno, c);
24890075Sobrien      obstack_1grow (ob, '\\');
24990075Sobrien      break;
25090075Sobrien    }
25190075Sobrien
25290075Sobrien  obstack_1grow (ob, c);
25390075Sobrien}
25490075Sobrien
255117395Skan
25690075Sobrien/* Read a double-quoted string onto the obstack.  Caller has scanned
25790075Sobrien   the leading quote.  */
25890075Sobrienstatic char *
259132718Skanread_quoted_string (struct obstack *ob, FILE *infile)
26090075Sobrien{
26190075Sobrien  int c;
26290075Sobrien
26390075Sobrien  while (1)
26490075Sobrien    {
26590075Sobrien      c = getc (infile); /* Read the string  */
26690075Sobrien      if (c == '\n')
26790075Sobrien	read_rtx_lineno++;
26890075Sobrien      else if (c == '\\')
26990075Sobrien	{
27090075Sobrien	  read_escape (ob, infile);
27190075Sobrien	  continue;
27290075Sobrien	}
27390075Sobrien      else if (c == '"')
27490075Sobrien	break;
27590075Sobrien
27690075Sobrien      obstack_1grow (ob, c);
27790075Sobrien    }
27890075Sobrien
27990075Sobrien  obstack_1grow (ob, 0);
28090075Sobrien  return obstack_finish (ob);
28190075Sobrien}
28290075Sobrien
28390075Sobrien/* Read a braced string (a la Tcl) onto the obstack.  Caller has
28490075Sobrien   scanned the leading brace.  Note that unlike quoted strings,
28590075Sobrien   the outermost braces _are_ included in the string constant.  */
28690075Sobrienstatic char *
287132718Skanread_braced_string (struct obstack *ob, FILE *infile)
28890075Sobrien{
28990075Sobrien  int c;
29090075Sobrien  int brace_depth = 1;  /* caller-processed */
291132718Skan  unsigned long starting_read_rtx_lineno = read_rtx_lineno;
29290075Sobrien
29390075Sobrien  obstack_1grow (ob, '{');
29490075Sobrien  while (brace_depth)
29590075Sobrien    {
29690075Sobrien      c = getc (infile); /* Read the string  */
297132718Skan
29890075Sobrien      if (c == '\n')
29990075Sobrien	read_rtx_lineno++;
30090075Sobrien      else if (c == '{')
30190075Sobrien	brace_depth++;
30290075Sobrien      else if (c == '}')
30390075Sobrien	brace_depth--;
30490075Sobrien      else if (c == '\\')
30590075Sobrien	{
30690075Sobrien	  read_escape (ob, infile);
30790075Sobrien	  continue;
30890075Sobrien	}
309132718Skan      else if (c == EOF)
310132718Skan	fatal_with_file_and_line
311132718Skan	  (infile, "missing closing } for opening brace on line %lu",
312132718Skan	   starting_read_rtx_lineno);
31390075Sobrien
31490075Sobrien      obstack_1grow (ob, c);
31590075Sobrien    }
316117395Skan
31790075Sobrien  obstack_1grow (ob, 0);
31890075Sobrien  return obstack_finish (ob);
31990075Sobrien}
32090075Sobrien
32190075Sobrien/* Read some kind of string constant.  This is the high-level routine
32290075Sobrien   used by read_rtx.  It handles surrounding parentheses, leading star,
32390075Sobrien   and dispatch to the appropriate string constant reader.  */
32490075Sobrien
32590075Sobrienstatic char *
326132718Skanread_string (struct obstack *ob, FILE *infile, int star_if_braced)
32790075Sobrien{
32890075Sobrien  char *stringbuf;
32990075Sobrien  int saw_paren = 0;
33090075Sobrien  int c;
33190075Sobrien
33290075Sobrien  c = read_skip_spaces (infile);
33390075Sobrien  if (c == '(')
33490075Sobrien    {
33590075Sobrien      saw_paren = 1;
33690075Sobrien      c = read_skip_spaces (infile);
33790075Sobrien    }
33890075Sobrien
33990075Sobrien  if (c == '"')
34090075Sobrien    stringbuf = read_quoted_string (ob, infile);
34190075Sobrien  else if (c == '{')
34290075Sobrien    {
34390075Sobrien      if (star_if_braced)
34490075Sobrien	obstack_1grow (ob, '*');
34590075Sobrien      stringbuf = read_braced_string (ob, infile);
34690075Sobrien    }
34790075Sobrien  else
34890075Sobrien    fatal_with_file_and_line (infile, "expected `\"' or `{', found `%c'", c);
349117395Skan
35090075Sobrien  if (saw_paren)
35190075Sobrien    {
35290075Sobrien      c = read_skip_spaces (infile);
35390075Sobrien      if (c != ')')
35490075Sobrien	fatal_expected_char (infile, ')', c);
35590075Sobrien    }
35690075Sobrien
35790075Sobrien  return stringbuf;
35890075Sobrien}
35990075Sobrien
36090075Sobrien/* Provide a version of a function to read a long long if the system does
36190075Sobrien   not provide one.  */
36290075Sobrien#if HOST_BITS_PER_WIDE_INT > HOST_BITS_PER_LONG && !defined(HAVE_ATOLL) && !defined(HAVE_ATOQ)
363132718SkanHOST_WIDE_INT atoll (const char *);
364132718Skan
36590075SobrienHOST_WIDE_INT
366132718Skanatoll (const char *p)
36790075Sobrien{
36890075Sobrien  int neg = 0;
36990075Sobrien  HOST_WIDE_INT tmp_wide;
37090075Sobrien
37190075Sobrien  while (ISSPACE (*p))
37290075Sobrien    p++;
37390075Sobrien  if (*p == '-')
37490075Sobrien    neg = 1, p++;
37590075Sobrien  else if (*p == '+')
37690075Sobrien    p++;
37790075Sobrien
37890075Sobrien  tmp_wide = 0;
37990075Sobrien  while (ISDIGIT (*p))
38090075Sobrien    {
38190075Sobrien      HOST_WIDE_INT new_wide = tmp_wide*10 + (*p - '0');
38290075Sobrien      if (new_wide < tmp_wide)
38390075Sobrien	{
38490075Sobrien	  /* Return INT_MAX equiv on overflow.  */
38590075Sobrien	  tmp_wide = (~(unsigned HOST_WIDE_INT) 0) >> 1;
38690075Sobrien	  break;
38790075Sobrien	}
38890075Sobrien      tmp_wide = new_wide;
38990075Sobrien      p++;
39090075Sobrien    }
39190075Sobrien
39290075Sobrien  if (neg)
39390075Sobrien    tmp_wide = -tmp_wide;
39490075Sobrien  return tmp_wide;
39590075Sobrien}
39690075Sobrien#endif
39790075Sobrien
39890075Sobrien/* Given a constant definition, return a hash code for its name.  */
399117395Skanstatic hashval_t
400132718Skandef_hash (const void *def)
40190075Sobrien{
40290075Sobrien  unsigned result, i;
40390075Sobrien  const char *string = ((const struct md_constant *) def)->name;
40490075Sobrien
40590075Sobrien  for (result = i = 0;*string++ != '\0'; i++)
40690075Sobrien    result += ((unsigned char) *string << (i % CHAR_BIT));
40790075Sobrien  return result;
40890075Sobrien}
40990075Sobrien
41090075Sobrien/* Given two constant definitions, return true if they have the same name.  */
41190075Sobrienstatic int
412132718Skandef_name_eq_p (const void *def1, const void *def2)
41390075Sobrien{
41490075Sobrien  return ! strcmp (((const struct md_constant *) def1)->name,
41590075Sobrien		   ((const struct md_constant *) def2)->name);
41690075Sobrien}
41790075Sobrien
41890075Sobrien/* INFILE is a FILE pointer to read text from.  TMP_CHAR is a buffer suitable
41990075Sobrien   to read a name or number into.  Process a define_constants directive,
42090075Sobrien   starting with the optional space after the "define_constants".  */
42190075Sobrienstatic void
422132718Skanread_constants (FILE *infile, char *tmp_char)
42390075Sobrien{
42490075Sobrien  int c;
42590075Sobrien  htab_t defs;
42690075Sobrien
42790075Sobrien  c = read_skip_spaces (infile);
42890075Sobrien  if (c != '[')
42990075Sobrien    fatal_expected_char (infile, '[', c);
43090075Sobrien  defs = md_constants;
43190075Sobrien  if (! defs)
43290075Sobrien    defs = htab_create (32, def_hash, def_name_eq_p, (htab_del) 0);
43390075Sobrien  /* Disable constant expansion during definition processing.  */
43490075Sobrien  md_constants = 0;
43590075Sobrien  while ( (c = read_skip_spaces (infile)) != ']')
43690075Sobrien    {
43790075Sobrien      struct md_constant *def;
43890075Sobrien      void **entry_ptr;
43990075Sobrien
44090075Sobrien      if (c != '(')
44190075Sobrien	fatal_expected_char (infile, '(', c);
44290075Sobrien      def = xmalloc (sizeof (struct md_constant));
44390075Sobrien      def->name = tmp_char;
44490075Sobrien      read_name (tmp_char, infile);
44590075Sobrien      entry_ptr = htab_find_slot (defs, def, TRUE);
44690075Sobrien      if (! *entry_ptr)
44790075Sobrien	def->name = xstrdup (tmp_char);
44890075Sobrien      c = read_skip_spaces (infile);
44990075Sobrien      ungetc (c, infile);
45090075Sobrien      read_name (tmp_char, infile);
45190075Sobrien      if (! *entry_ptr)
45290075Sobrien	{
45390075Sobrien	  def->value = xstrdup (tmp_char);
45490075Sobrien	  *entry_ptr = def;
45590075Sobrien	}
45690075Sobrien      else
45790075Sobrien	{
45890075Sobrien	  def = *entry_ptr;
45990075Sobrien	  if (strcmp (def->value, tmp_char))
46090075Sobrien	    fatal_with_file_and_line (infile,
46190075Sobrien				      "redefinition of %s, was %s, now %s",
46290075Sobrien				      def->name, def->value, tmp_char);
46390075Sobrien	}
46490075Sobrien      c = read_skip_spaces (infile);
46590075Sobrien      if (c != ')')
46690075Sobrien	fatal_expected_char (infile, ')', c);
46790075Sobrien    }
46890075Sobrien  md_constants = defs;
46990075Sobrien  c = read_skip_spaces (infile);
47090075Sobrien  if (c != ')')
47190075Sobrien    fatal_expected_char (infile, ')', c);
47290075Sobrien}
47390075Sobrien
47490075Sobrien/* For every constant definition, call CALLBACK with two arguments:
47590075Sobrien   a pointer a pointer to the constant definition and INFO.
47690075Sobrien   Stops when CALLBACK returns zero.  */
47790075Sobrienvoid
478132718Skantraverse_md_constants (htab_trav callback, void *info)
47990075Sobrien{
48090075Sobrien  if (md_constants)
48190075Sobrien    htab_traverse (md_constants, callback, info);
48290075Sobrien}
48390075Sobrien
48490075Sobrienstatic void
485132718Skanvalidate_const_int (FILE *infile, const char *string)
48690075Sobrien{
48790075Sobrien  const char *cp;
48890075Sobrien  int valid = 1;
48990075Sobrien
49090075Sobrien  cp = string;
49190075Sobrien  while (*cp && ISSPACE (*cp))
49290075Sobrien    cp++;
49390075Sobrien  if (*cp == '-' || *cp == '+')
49490075Sobrien    cp++;
49590075Sobrien  if (*cp == 0)
49690075Sobrien    valid = 0;
49790075Sobrien  for (; *cp; cp++)
49890075Sobrien    if (! ISDIGIT (*cp))
49990075Sobrien      valid = 0;
50090075Sobrien  if (!valid)
50190075Sobrien    fatal_with_file_and_line (infile, "invalid decimal constant \"%s\"\n", string);
50290075Sobrien}
50390075Sobrien
50490075Sobrien/* Read an rtx in printed representation from INFILE
50590075Sobrien   and return an actual rtx in core constructed accordingly.
50690075Sobrien   read_rtx is not used in the compiler proper, but rather in
50790075Sobrien   the utilities gen*.c that construct C code from machine descriptions.  */
50890075Sobrien
50990075Sobrienrtx
510132718Skanread_rtx (FILE *infile)
51190075Sobrien{
51290075Sobrien  int i, j;
51390075Sobrien  RTX_CODE tmp_code;
51490075Sobrien  const char *format_ptr;
51590075Sobrien  /* tmp_char is a buffer used for reading decimal integers
51690075Sobrien     and names of rtx types and machine modes.
51790075Sobrien     Therefore, 256 must be enough.  */
51890075Sobrien  char tmp_char[256];
51990075Sobrien  rtx return_rtx;
52090075Sobrien  int c;
52190075Sobrien  int tmp_int;
52290075Sobrien  HOST_WIDE_INT tmp_wide;
52390075Sobrien
52490075Sobrien  /* Obstack used for allocating RTL objects.  */
52590075Sobrien  static struct obstack rtl_obstack;
52690075Sobrien  static int initialized;
52790075Sobrien
52890075Sobrien  /* Linked list structure for making RTXs: */
52990075Sobrien  struct rtx_list
53090075Sobrien    {
53190075Sobrien      struct rtx_list *next;
53290075Sobrien      rtx value;		/* Value of this node.  */
53390075Sobrien    };
53490075Sobrien
53590075Sobrien  if (!initialized) {
53690075Sobrien    obstack_init (&rtl_obstack);
53790075Sobrien    initialized = 1;
53890075Sobrien  }
53990075Sobrien
54090075Sobrienagain:
54190075Sobrien  c = read_skip_spaces (infile); /* Should be open paren.  */
54290075Sobrien  if (c != '(')
54390075Sobrien    fatal_expected_char (infile, '(', c);
54490075Sobrien
54590075Sobrien  read_name (tmp_char, infile);
54690075Sobrien
54790075Sobrien  tmp_code = UNKNOWN;
54890075Sobrien
54990075Sobrien  if (! strcmp (tmp_char, "define_constants"))
55090075Sobrien    {
55190075Sobrien      read_constants (infile, tmp_char);
55290075Sobrien      goto again;
55390075Sobrien    }
55490075Sobrien  for (i = 0; i < NUM_RTX_CODE; i++)
55590075Sobrien    if (! strcmp (tmp_char, GET_RTX_NAME (i)))
55690075Sobrien      {
55790075Sobrien	tmp_code = (RTX_CODE) i;	/* get value for name */
55890075Sobrien	break;
55990075Sobrien      }
56090075Sobrien
56190075Sobrien  if (tmp_code == UNKNOWN)
56290075Sobrien    fatal_with_file_and_line (infile, "unknown rtx code `%s'", tmp_char);
56390075Sobrien
56490075Sobrien  /* (NIL) stands for an expression that isn't there.  */
56590075Sobrien  if (tmp_code == NIL)
56690075Sobrien    {
56790075Sobrien      /* Discard the closeparen.  */
56890075Sobrien      while ((c = getc (infile)) && c != ')')
56990075Sobrien	;
57090075Sobrien
57190075Sobrien      return 0;
57290075Sobrien    }
57390075Sobrien
57490075Sobrien  /* If we end up with an insn expression then we free this space below.  */
57590075Sobrien  return_rtx = rtx_alloc (tmp_code);
57690075Sobrien  format_ptr = GET_RTX_FORMAT (GET_CODE (return_rtx));
57790075Sobrien
57890075Sobrien  /* If what follows is `: mode ', read it and
57990075Sobrien     store the mode in the rtx.  */
58090075Sobrien
58190075Sobrien  i = read_skip_spaces (infile);
58290075Sobrien  if (i == ':')
58390075Sobrien    {
58490075Sobrien      read_name (tmp_char, infile);
58590075Sobrien      for (j = 0; j < NUM_MACHINE_MODES; j++)
58690075Sobrien	if (! strcmp (GET_MODE_NAME (j), tmp_char))
58790075Sobrien	  break;
58890075Sobrien
58990075Sobrien      if (j == MAX_MACHINE_MODE)
59090075Sobrien	fatal_with_file_and_line (infile, "unknown mode `%s'", tmp_char);
59190075Sobrien
59290075Sobrien      PUT_MODE (return_rtx, (enum machine_mode) j);
59390075Sobrien    }
59490075Sobrien  else
59590075Sobrien    ungetc (i, infile);
59690075Sobrien
59790075Sobrien  for (i = 0; i < GET_RTX_LENGTH (GET_CODE (return_rtx)); i++)
59890075Sobrien    switch (*format_ptr++)
59990075Sobrien      {
60090075Sobrien	/* 0 means a field for internal use only.
60190075Sobrien	   Don't expect it to be present in the input.  */
60290075Sobrien      case '0':
60390075Sobrien	break;
60490075Sobrien
60590075Sobrien      case 'e':
60690075Sobrien      case 'u':
60790075Sobrien	XEXP (return_rtx, i) = read_rtx (infile);
60890075Sobrien	break;
60990075Sobrien
61090075Sobrien      case 'V':
61190075Sobrien	/* 'V' is an optional vector: if a closeparen follows,
61290075Sobrien	   just store NULL for this element.  */
61390075Sobrien	c = read_skip_spaces (infile);
61490075Sobrien	ungetc (c, infile);
61590075Sobrien	if (c == ')')
61690075Sobrien	  {
61790075Sobrien	    XVEC (return_rtx, i) = 0;
61890075Sobrien	    break;
619117395Skan	  }
62090075Sobrien	/* Now process the vector.  */
62190075Sobrien
62290075Sobrien      case 'E':
62390075Sobrien	{
62490075Sobrien	  /* Obstack to store scratch vector in.  */
62590075Sobrien	  struct obstack vector_stack;
62690075Sobrien	  int list_counter = 0;
62790075Sobrien	  rtvec return_vec = NULL_RTVEC;
62890075Sobrien
62990075Sobrien	  c = read_skip_spaces (infile);
63090075Sobrien	  if (c != '[')
63190075Sobrien	    fatal_expected_char (infile, '[', c);
63290075Sobrien
63390075Sobrien	  /* add expressions to a list, while keeping a count */
63490075Sobrien	  obstack_init (&vector_stack);
63590075Sobrien	  while ((c = read_skip_spaces (infile)) && c != ']')
63690075Sobrien	    {
63790075Sobrien	      ungetc (c, infile);
63890075Sobrien	      list_counter++;
639132718Skan	      obstack_ptr_grow (&vector_stack, read_rtx (infile));
64090075Sobrien	    }
64190075Sobrien	  if (list_counter > 0)
64290075Sobrien	    {
64390075Sobrien	      return_vec = rtvec_alloc (list_counter);
64490075Sobrien	      memcpy (&return_vec->elem[0], obstack_finish (&vector_stack),
64590075Sobrien		      list_counter * sizeof (rtx));
64690075Sobrien	    }
64790075Sobrien	  XVEC (return_rtx, i) = return_vec;
64890075Sobrien	  obstack_free (&vector_stack, NULL);
64990075Sobrien	  /* close bracket gotten */
65090075Sobrien	}
65190075Sobrien	break;
65290075Sobrien
65390075Sobrien      case 'S':
65490075Sobrien	/* 'S' is an optional string: if a closeparen follows,
65590075Sobrien	   just store NULL for this element.  */
65690075Sobrien	c = read_skip_spaces (infile);
65790075Sobrien	ungetc (c, infile);
65890075Sobrien	if (c == ')')
65990075Sobrien	  {
66090075Sobrien	    XSTR (return_rtx, i) = 0;
66190075Sobrien	    break;
66290075Sobrien	  }
66390075Sobrien
66490075Sobrien      case 'T':
66590075Sobrien      case 's':
66690075Sobrien	{
66790075Sobrien	  char *stringbuf;
66890075Sobrien
66990075Sobrien	  /* The output template slot of a DEFINE_INSN,
67090075Sobrien	     DEFINE_INSN_AND_SPLIT, or DEFINE_PEEPHOLE automatically
67190075Sobrien	     gets a star inserted as its first character, if it is
67290075Sobrien	     written with a brace block instead of a string constant.  */
67390075Sobrien	  int star_if_braced = (format_ptr[-1] == 'T');
674117395Skan
67590075Sobrien	  stringbuf = read_string (&rtl_obstack, infile, star_if_braced);
67690075Sobrien
67790075Sobrien	  /* For insn patterns, we want to provide a default name
67890075Sobrien	     based on the file and line, like "*foo.md:12", if the
67990075Sobrien	     given name is blank.  These are only for define_insn and
68090075Sobrien	     define_insn_and_split, to aid debugging.  */
68190075Sobrien	  if (*stringbuf == '\0'
68290075Sobrien	      && i == 0
68390075Sobrien	      && (GET_CODE (return_rtx) == DEFINE_INSN
68490075Sobrien		  || GET_CODE (return_rtx) == DEFINE_INSN_AND_SPLIT))
68590075Sobrien	    {
68690075Sobrien	      char line_name[20];
68790075Sobrien	      const char *fn = (read_rtx_filename ? read_rtx_filename : "rtx");
68890075Sobrien	      const char *slash;
68990075Sobrien	      for (slash = fn; *slash; slash ++)
69090075Sobrien		if (*slash == '/' || *slash == '\\' || *slash == ':')
69190075Sobrien		  fn = slash + 1;
69290075Sobrien	      obstack_1grow (&rtl_obstack, '*');
69390075Sobrien	      obstack_grow (&rtl_obstack, fn, strlen (fn));
69490075Sobrien	      sprintf (line_name, ":%d", read_rtx_lineno);
69590075Sobrien	      obstack_grow (&rtl_obstack, line_name, strlen (line_name)+1);
69690075Sobrien	      stringbuf = (char *) obstack_finish (&rtl_obstack);
69790075Sobrien	    }
69890075Sobrien
69990075Sobrien	  if (star_if_braced)
70090075Sobrien	    XTMPL (return_rtx, i) = stringbuf;
70190075Sobrien	  else
70290075Sobrien	    XSTR (return_rtx, i) = stringbuf;
70390075Sobrien	}
70490075Sobrien	break;
70590075Sobrien
70690075Sobrien      case 'w':
70790075Sobrien	read_name (tmp_char, infile);
70890075Sobrien	validate_const_int (infile, tmp_char);
70990075Sobrien#if HOST_BITS_PER_WIDE_INT == HOST_BITS_PER_INT
71090075Sobrien	tmp_wide = atoi (tmp_char);
71190075Sobrien#else
71290075Sobrien#if HOST_BITS_PER_WIDE_INT == HOST_BITS_PER_LONG
71390075Sobrien	tmp_wide = atol (tmp_char);
71490075Sobrien#else
71590075Sobrien	/* Prefer atoll over atoq, since the former is in the ISO C99 standard.
71690075Sobrien	   But prefer not to use our hand-rolled function above either.  */
71790075Sobrien#if defined(HAVE_ATOLL) || !defined(HAVE_ATOQ)
71890075Sobrien	tmp_wide = atoll (tmp_char);
71990075Sobrien#else
72090075Sobrien	tmp_wide = atoq (tmp_char);
72190075Sobrien#endif
72290075Sobrien#endif
72390075Sobrien#endif
72490075Sobrien	XWINT (return_rtx, i) = tmp_wide;
72590075Sobrien	break;
72690075Sobrien
72790075Sobrien      case 'i':
72890075Sobrien      case 'n':
72990075Sobrien	read_name (tmp_char, infile);
73090075Sobrien	validate_const_int (infile, tmp_char);
73190075Sobrien	tmp_int = atoi (tmp_char);
73290075Sobrien	XINT (return_rtx, i) = tmp_int;
73390075Sobrien	break;
73490075Sobrien
73590075Sobrien      default:
73690075Sobrien	fprintf (stderr,
73790075Sobrien		 "switch format wrong in rtl.read_rtx(). format was: %c.\n",
73890075Sobrien		 format_ptr[-1]);
73990075Sobrien	fprintf (stderr, "\tfile position: %ld\n", ftell (infile));
74090075Sobrien	abort ();
74190075Sobrien      }
74290075Sobrien
74390075Sobrien  c = read_skip_spaces (infile);
74490075Sobrien  if (c != ')')
74590075Sobrien    fatal_expected_char (infile, ')', c);
74690075Sobrien
74790075Sobrien  return return_rtx;
74890075Sobrien}
749