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