gensupport.c revision 90075
190075Sobrien/* Support routines for the various generation passes. 290075Sobrien Copyright (C) 2000, 2001 Free Software Foundation, Inc. 390075Sobrien 490075Sobrien This file is part of GCC. 590075Sobrien 690075Sobrien GCC is free software; you can redistribute it and/or modify it 790075Sobrien under the terms of the GNU General Public License as published by 890075Sobrien the Free Software Foundation; either version 2, or (at your option) 990075Sobrien any later version. 1090075Sobrien 1190075Sobrien GCC is distributed in the hope that it will be useful, but WITHOUT 1290075Sobrien ANY WARRANTY; without even the implied warranty of MERCHANTABILITY 1390075Sobrien or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public 1490075Sobrien License for more details. 1590075Sobrien 1690075Sobrien You should have received a copy of the GNU General Public License 1790075Sobrien along with GCC; see the file COPYING. If not, write to the Free 1890075Sobrien Software Foundation, 59 Temple Place - Suite 330, Boston, MA 1990075Sobrien 02111-1307, USA. */ 2090075Sobrien 2190075Sobrien#include "hconfig.h" 2290075Sobrien#include "system.h" 2390075Sobrien#include "rtl.h" 2490075Sobrien#include "obstack.h" 2590075Sobrien#include "errors.h" 2690075Sobrien#include "gensupport.h" 2790075Sobrien 2890075Sobrien 2990075Sobrien/* In case some macros used by files we include need it, define this here. */ 3090075Sobrienint target_flags; 3190075Sobrien 3290075Sobrienstatic struct obstack obstack; 3390075Sobrienstruct obstack *rtl_obstack = &obstack; 3490075Sobrien 3590075Sobrien#define obstack_chunk_alloc xmalloc 3690075Sobrien#define obstack_chunk_free free 3790075Sobrien 3890075Sobrienstatic int sequence_num; 3990075Sobrienstatic int errors; 4090075Sobrien 4190075Sobrienstatic int predicable_default; 4290075Sobrienstatic const char *predicable_true; 4390075Sobrienstatic const char *predicable_false; 4490075Sobrien 4590075Sobrienstatic char *base_dir = NULL; 4690075Sobrien 4790075Sobrien/* We initially queue all patterns, process the define_insn and 4890075Sobrien define_cond_exec patterns, then return them one at a time. */ 4990075Sobrien 5090075Sobrienstruct queue_elem 5190075Sobrien{ 5290075Sobrien rtx data; 5390075Sobrien int lineno; 5490075Sobrien struct queue_elem *next; 5590075Sobrien}; 5690075Sobrien 5790075Sobrienstatic struct queue_elem *define_attr_queue; 5890075Sobrienstatic struct queue_elem **define_attr_tail = &define_attr_queue; 5990075Sobrienstatic struct queue_elem *define_insn_queue; 6090075Sobrienstatic struct queue_elem **define_insn_tail = &define_insn_queue; 6190075Sobrienstatic struct queue_elem *define_cond_exec_queue; 6290075Sobrienstatic struct queue_elem **define_cond_exec_tail = &define_cond_exec_queue; 6390075Sobrienstatic struct queue_elem *other_queue; 6490075Sobrienstatic struct queue_elem **other_tail = &other_queue; 6590075Sobrien 6690075Sobrienstatic void queue_pattern PARAMS ((rtx, struct queue_elem ***, int)); 6790075Sobrien 6890075Sobrien/* Current maximum length of directory names in the search path 6990075Sobrien for include files. (Altered as we get more of them.) */ 7090075Sobrien 7190075Sobriensize_t max_include_len; 7290075Sobrien 7390075Sobrienstruct file_name_list 7490075Sobrien { 7590075Sobrien struct file_name_list *next; 7690075Sobrien const char *fname; 7790075Sobrien }; 7890075Sobrien 7990075Sobrienstruct file_name_list *include = 0; /* First dir to search */ 8090075Sobrien /* First dir to search for <file> */ 8190075Sobrienstruct file_name_list *first_bracket_include = 0; 8290075Sobrienstruct file_name_list *last_include = 0; /* Last in chain */ 8390075Sobrien 8490075Sobrienstatic void remove_constraints PARAMS ((rtx)); 8590075Sobrienstatic void process_rtx PARAMS ((rtx, int)); 8690075Sobrien 8790075Sobrienstatic int is_predicable PARAMS ((struct queue_elem *)); 8890075Sobrienstatic void identify_predicable_attribute PARAMS ((void)); 8990075Sobrienstatic int n_alternatives PARAMS ((const char *)); 9090075Sobrienstatic void collect_insn_data PARAMS ((rtx, int *, int *)); 9190075Sobrienstatic rtx alter_predicate_for_insn PARAMS ((rtx, int, int, int)); 9290075Sobrienstatic const char *alter_test_for_insn PARAMS ((struct queue_elem *, 9390075Sobrien struct queue_elem *)); 9490075Sobrienstatic char *shift_output_template PARAMS ((char *, const char *, int)); 9590075Sobrienstatic const char *alter_output_for_insn PARAMS ((struct queue_elem *, 9690075Sobrien struct queue_elem *, 9790075Sobrien int, int)); 9890075Sobrienstatic void process_one_cond_exec PARAMS ((struct queue_elem *)); 9990075Sobrienstatic void process_define_cond_exec PARAMS ((void)); 10090075Sobrienstatic int process_include PARAMS ((rtx, int)); 10190075Sobrienstatic char *save_string PARAMS ((const char *, int)); 10290075Sobrienstatic int init_include_reader PARAMS ((FILE *)); 10390075Sobrien 10490075Sobrienvoid 10590075Sobrienmessage_with_line VPARAMS ((int lineno, const char *msg, ...)) 10690075Sobrien{ 10790075Sobrien VA_OPEN (ap, msg); 10890075Sobrien VA_FIXEDARG (ap, int, lineno); 10990075Sobrien VA_FIXEDARG (ap, const char *, msg); 11090075Sobrien 11190075Sobrien fprintf (stderr, "%s:%d: ", read_rtx_filename, lineno); 11290075Sobrien vfprintf (stderr, msg, ap); 11390075Sobrien fputc ('\n', stderr); 11490075Sobrien 11590075Sobrien VA_CLOSE (ap); 11690075Sobrien} 11790075Sobrien 11890075Sobrien/* Make a version of gen_rtx_CONST_INT so that GEN_INT can be used in 11990075Sobrien the gensupport programs. */ 12090075Sobrien 12190075Sobrienrtx 12290075Sobriengen_rtx_CONST_INT (mode, arg) 12390075Sobrien enum machine_mode mode ATTRIBUTE_UNUSED; 12490075Sobrien HOST_WIDE_INT arg; 12590075Sobrien{ 12690075Sobrien rtx rt = rtx_alloc (CONST_INT); 12790075Sobrien 12890075Sobrien XWINT (rt, 0) = arg; 12990075Sobrien return rt; 13090075Sobrien} 13190075Sobrien 13290075Sobrien/* Queue PATTERN on LIST_TAIL. */ 13390075Sobrien 13490075Sobrienstatic void 13590075Sobrienqueue_pattern (pattern, list_tail, lineno) 13690075Sobrien rtx pattern; 13790075Sobrien struct queue_elem ***list_tail; 13890075Sobrien int lineno; 13990075Sobrien{ 14090075Sobrien struct queue_elem *e = (struct queue_elem *) xmalloc (sizeof (*e)); 14190075Sobrien e->data = pattern; 14290075Sobrien e->lineno = lineno; 14390075Sobrien e->next = NULL; 14490075Sobrien **list_tail = e; 14590075Sobrien *list_tail = &e->next; 14690075Sobrien} 14790075Sobrien 14890075Sobrien/* Recursively remove constraints from an rtx. */ 14990075Sobrien 15090075Sobrienstatic void 15190075Sobrienremove_constraints (part) 15290075Sobrien rtx part; 15390075Sobrien{ 15490075Sobrien int i, j; 15590075Sobrien const char *format_ptr; 15690075Sobrien 15790075Sobrien if (part == 0) 15890075Sobrien return; 15990075Sobrien 16090075Sobrien if (GET_CODE (part) == MATCH_OPERAND) 16190075Sobrien XSTR (part, 2) = ""; 16290075Sobrien else if (GET_CODE (part) == MATCH_SCRATCH) 16390075Sobrien XSTR (part, 1) = ""; 16490075Sobrien 16590075Sobrien format_ptr = GET_RTX_FORMAT (GET_CODE (part)); 16690075Sobrien 16790075Sobrien for (i = 0; i < GET_RTX_LENGTH (GET_CODE (part)); i++) 16890075Sobrien switch (*format_ptr++) 16990075Sobrien { 17090075Sobrien case 'e': 17190075Sobrien case 'u': 17290075Sobrien remove_constraints (XEXP (part, i)); 17390075Sobrien break; 17490075Sobrien case 'E': 17590075Sobrien if (XVEC (part, i) != NULL) 17690075Sobrien for (j = 0; j < XVECLEN (part, i); j++) 17790075Sobrien remove_constraints (XVECEXP (part, i, j)); 17890075Sobrien break; 17990075Sobrien } 18090075Sobrien} 18190075Sobrien 18290075Sobrien/* The entry point for initializing the reader. */ 18390075Sobrien 18490075Sobrienstatic int 18590075Sobrieninit_include_reader (inf) 18690075Sobrien FILE *inf; 18790075Sobrien{ 18890075Sobrien int c; 18990075Sobrien 19090075Sobrien errors = 0; 19190075Sobrien 19290075Sobrien /* Read the entire file. */ 19390075Sobrien while (1) 19490075Sobrien { 19590075Sobrien rtx desc; 19690075Sobrien int lineno; 19790075Sobrien 19890075Sobrien c = read_skip_spaces (inf); 19990075Sobrien if (c == EOF) 20090075Sobrien break; 20190075Sobrien 20290075Sobrien ungetc (c, inf); 20390075Sobrien lineno = read_rtx_lineno; 20490075Sobrien desc = read_rtx (inf); 20590075Sobrien process_rtx (desc, lineno); 20690075Sobrien } 20790075Sobrien fclose (inf); 20890075Sobrien 20990075Sobrien /* Process define_cond_exec patterns. */ 21090075Sobrien if (define_cond_exec_queue != NULL) 21190075Sobrien process_define_cond_exec (); 21290075Sobrien 21390075Sobrien return errors ? FATAL_EXIT_CODE : SUCCESS_EXIT_CODE; 21490075Sobrien} 21590075Sobrien 21690075Sobrien/* Process an include file assuming that it lives in gcc/config/{target}/ 21790075Sobrien if the include looks line (include "file" ) */ 21890075Sobrienstatic int 21990075Sobrienprocess_include (desc, lineno) 22090075Sobrien rtx desc; 22190075Sobrien int lineno; 22290075Sobrien{ 22390075Sobrien const char *filename = XSTR (desc, 0); 22490075Sobrien char *pathname = NULL; 22590075Sobrien FILE *input_file; 22690075Sobrien char *fname = NULL; 22790075Sobrien struct file_name_list *stackp; 22890075Sobrien int flen; 22990075Sobrien 23090075Sobrien stackp = include; 23190075Sobrien 23290075Sobrien /* If specified file name is absolute, just open it. */ 23390075Sobrien if (IS_ABSOLUTE_PATHNAME (filename) || !stackp) 23490075Sobrien { 23590075Sobrien if (base_dir) 23690075Sobrien { 23790075Sobrien pathname = xmalloc (strlen (base_dir) + strlen (filename) + 1); 23890075Sobrien pathname = strcpy (pathname, base_dir); 23990075Sobrien strcat (pathname, filename); 24090075Sobrien strcat (pathname, "\0"); 24190075Sobrien } 24290075Sobrien else 24390075Sobrien { 24490075Sobrien pathname = xstrdup (filename); 24590075Sobrien } 24690075Sobrien read_rtx_filename = pathname; 24790075Sobrien input_file = fopen (pathname, "r"); 24890075Sobrien 24990075Sobrien if (input_file == 0) 25090075Sobrien { 25190075Sobrien perror (pathname); 25290075Sobrien return FATAL_EXIT_CODE; 25390075Sobrien } 25490075Sobrien } 25590075Sobrien else if (stackp) 25690075Sobrien { 25790075Sobrien 25890075Sobrien flen = strlen (filename); 25990075Sobrien 26090075Sobrien fname = (char *) xmalloc (max_include_len + flen + 2); 26190075Sobrien 26290075Sobrien /* + 2 above for slash and terminating null. */ 26390075Sobrien 26490075Sobrien /* Search directory path, trying to open the file. 26590075Sobrien Copy each filename tried into FNAME. */ 26690075Sobrien 26790075Sobrien for (; stackp; stackp = stackp->next) 26890075Sobrien { 26990075Sobrien if (stackp->fname) 27090075Sobrien { 27190075Sobrien strcpy (fname, stackp->fname); 27290075Sobrien strcat (fname, "/"); 27390075Sobrien fname[strlen (fname) + flen] = 0; 27490075Sobrien } 27590075Sobrien else 27690075Sobrien { 27790075Sobrien fname[0] = 0; 27890075Sobrien } 27990075Sobrien strncat (fname, (const char *) filename, flen); 28090075Sobrien read_rtx_filename = fname; 28190075Sobrien input_file = fopen (fname, "r"); 28290075Sobrien if (input_file != NULL) 28390075Sobrien break; 28490075Sobrien } 28590075Sobrien if (stackp == NULL) 28690075Sobrien { 28790075Sobrien if (strchr (fname, '/') == NULL || strchr (fname, '\\' ) || base_dir) 28890075Sobrien { 28990075Sobrien if (base_dir) 29090075Sobrien { 29190075Sobrien pathname = 29290075Sobrien xmalloc (strlen (base_dir) + strlen (filename) + 1); 29390075Sobrien pathname = strcpy (pathname, base_dir); 29490075Sobrien strcat (pathname, filename); 29590075Sobrien strcat (pathname, "\0"); 29690075Sobrien } 29790075Sobrien else 29890075Sobrien pathname = xstrdup (filename); 29990075Sobrien } 30090075Sobrien read_rtx_filename = pathname; 30190075Sobrien input_file = fopen (pathname, "r"); 30290075Sobrien 30390075Sobrien if (input_file == 0) 30490075Sobrien { 30590075Sobrien perror (filename); 30690075Sobrien return FATAL_EXIT_CODE; 30790075Sobrien } 30890075Sobrien } 30990075Sobrien 31090075Sobrien } 31190075Sobrien 31290075Sobrien if (init_include_reader (input_file) == FATAL_EXIT_CODE) 31390075Sobrien message_with_line (lineno, "read errors found in include file %s\n", pathname); 31490075Sobrien 31590075Sobrien if (fname) 31690075Sobrien free (fname); 31790075Sobrien return SUCCESS_EXIT_CODE; 31890075Sobrien} 31990075Sobrien 32090075Sobrien/* Process a top level rtx in some way, queueing as appropriate. */ 32190075Sobrien 32290075Sobrienstatic void 32390075Sobrienprocess_rtx (desc, lineno) 32490075Sobrien rtx desc; 32590075Sobrien int lineno; 32690075Sobrien{ 32790075Sobrien switch (GET_CODE (desc)) 32890075Sobrien { 32990075Sobrien case DEFINE_INSN: 33090075Sobrien queue_pattern (desc, &define_insn_tail, lineno); 33190075Sobrien break; 33290075Sobrien 33390075Sobrien case DEFINE_COND_EXEC: 33490075Sobrien queue_pattern (desc, &define_cond_exec_tail, lineno); 33590075Sobrien break; 33690075Sobrien 33790075Sobrien case DEFINE_ATTR: 33890075Sobrien queue_pattern (desc, &define_attr_tail, lineno); 33990075Sobrien break; 34090075Sobrien 34190075Sobrien case INCLUDE: 34290075Sobrien if (process_include (desc, lineno) == FATAL_EXIT_CODE) 34390075Sobrien { 34490075Sobrien const char *filename = XSTR (desc, 0); 34590075Sobrien message_with_line (lineno, "include file at %s not found\n", 34690075Sobrien filename); 34790075Sobrien } 34890075Sobrien break; 34990075Sobrien 35090075Sobrien case DEFINE_INSN_AND_SPLIT: 35190075Sobrien { 35290075Sobrien const char *split_cond; 35390075Sobrien rtx split; 35490075Sobrien rtvec attr; 35590075Sobrien int i; 35690075Sobrien 35790075Sobrien /* Create a split with values from the insn_and_split. */ 35890075Sobrien split = rtx_alloc (DEFINE_SPLIT); 35990075Sobrien 36090075Sobrien i = XVECLEN (desc, 1); 36190075Sobrien XVEC (split, 0) = rtvec_alloc (i); 36290075Sobrien while (--i >= 0) 36390075Sobrien { 36490075Sobrien XVECEXP (split, 0, i) = copy_rtx (XVECEXP (desc, 1, i)); 36590075Sobrien remove_constraints (XVECEXP (split, 0, i)); 36690075Sobrien } 36790075Sobrien 36890075Sobrien /* If the split condition starts with "&&", append it to the 36990075Sobrien insn condition to create the new split condition. */ 37090075Sobrien split_cond = XSTR (desc, 4); 37190075Sobrien if (split_cond[0] == '&' && split_cond[1] == '&') 37290075Sobrien { 37390075Sobrien const char *insn_cond = XSTR (desc, 2); 37490075Sobrien size_t insn_cond_len = strlen (insn_cond); 37590075Sobrien size_t split_cond_len = strlen (split_cond); 37690075Sobrien char *combined; 37790075Sobrien 37890075Sobrien combined = (char *) xmalloc (insn_cond_len + split_cond_len + 1); 37990075Sobrien memcpy (combined, insn_cond, insn_cond_len); 38090075Sobrien memcpy (combined + insn_cond_len, split_cond, split_cond_len + 1); 38190075Sobrien 38290075Sobrien split_cond = combined; 38390075Sobrien } 38490075Sobrien XSTR (split, 1) = split_cond; 38590075Sobrien XVEC (split, 2) = XVEC (desc, 5); 38690075Sobrien XSTR (split, 3) = XSTR (desc, 6); 38790075Sobrien 38890075Sobrien /* Fix up the DEFINE_INSN. */ 38990075Sobrien attr = XVEC (desc, 7); 39090075Sobrien PUT_CODE (desc, DEFINE_INSN); 39190075Sobrien XVEC (desc, 4) = attr; 39290075Sobrien 39390075Sobrien /* Queue them. */ 39490075Sobrien queue_pattern (desc, &define_insn_tail, lineno); 39590075Sobrien queue_pattern (split, &other_tail, lineno); 39690075Sobrien break; 39790075Sobrien } 39890075Sobrien 39990075Sobrien default: 40090075Sobrien queue_pattern (desc, &other_tail, lineno); 40190075Sobrien break; 40290075Sobrien } 40390075Sobrien} 40490075Sobrien 40590075Sobrien/* Return true if attribute PREDICABLE is true for ELEM, which holds 40690075Sobrien a DEFINE_INSN. */ 40790075Sobrien 40890075Sobrienstatic int 40990075Sobrienis_predicable (elem) 41090075Sobrien struct queue_elem *elem; 41190075Sobrien{ 41290075Sobrien rtvec vec = XVEC (elem->data, 4); 41390075Sobrien const char *value; 41490075Sobrien int i; 41590075Sobrien 41690075Sobrien if (! vec) 41790075Sobrien return predicable_default; 41890075Sobrien 41990075Sobrien for (i = GET_NUM_ELEM (vec) - 1; i >= 0; --i) 42090075Sobrien { 42190075Sobrien rtx sub = RTVEC_ELT (vec, i); 42290075Sobrien switch (GET_CODE (sub)) 42390075Sobrien { 42490075Sobrien case SET_ATTR: 42590075Sobrien if (strcmp (XSTR (sub, 0), "predicable") == 0) 42690075Sobrien { 42790075Sobrien value = XSTR (sub, 1); 42890075Sobrien goto found; 42990075Sobrien } 43090075Sobrien break; 43190075Sobrien 43290075Sobrien case SET_ATTR_ALTERNATIVE: 43390075Sobrien if (strcmp (XSTR (sub, 0), "predicable") == 0) 43490075Sobrien { 43590075Sobrien message_with_line (elem->lineno, 43690075Sobrien "multiple alternatives for `predicable'"); 43790075Sobrien errors = 1; 43890075Sobrien return 0; 43990075Sobrien } 44090075Sobrien break; 44190075Sobrien 44290075Sobrien case SET: 44390075Sobrien if (GET_CODE (SET_DEST (sub)) != ATTR 44490075Sobrien || strcmp (XSTR (SET_DEST (sub), 0), "predicable") != 0) 44590075Sobrien break; 44690075Sobrien sub = SET_SRC (sub); 44790075Sobrien if (GET_CODE (sub) == CONST_STRING) 44890075Sobrien { 44990075Sobrien value = XSTR (sub, 0); 45090075Sobrien goto found; 45190075Sobrien } 45290075Sobrien 45390075Sobrien /* ??? It would be possible to handle this if we really tried. 45490075Sobrien It's not easy though, and I'm not going to bother until it 45590075Sobrien really proves necessary. */ 45690075Sobrien message_with_line (elem->lineno, 45790075Sobrien "non-constant value for `predicable'"); 45890075Sobrien errors = 1; 45990075Sobrien return 0; 46090075Sobrien 46190075Sobrien default: 46290075Sobrien abort (); 46390075Sobrien } 46490075Sobrien } 46590075Sobrien 46690075Sobrien return predicable_default; 46790075Sobrien 46890075Sobrien found: 46990075Sobrien /* Verify that predicability does not vary on the alternative. */ 47090075Sobrien /* ??? It should be possible to handle this by simply eliminating 47190075Sobrien the non-predicable alternatives from the insn. FRV would like 47290075Sobrien to do this. Delay this until we've got the basics solid. */ 47390075Sobrien if (strchr (value, ',') != NULL) 47490075Sobrien { 47590075Sobrien message_with_line (elem->lineno, 47690075Sobrien "multiple alternatives for `predicable'"); 47790075Sobrien errors = 1; 47890075Sobrien return 0; 47990075Sobrien } 48090075Sobrien 48190075Sobrien /* Find out which value we're looking at. */ 48290075Sobrien if (strcmp (value, predicable_true) == 0) 48390075Sobrien return 1; 48490075Sobrien if (strcmp (value, predicable_false) == 0) 48590075Sobrien return 0; 48690075Sobrien 48790075Sobrien message_with_line (elem->lineno, 48890075Sobrien "unknown value `%s' for `predicable' attribute", 48990075Sobrien value); 49090075Sobrien errors = 1; 49190075Sobrien return 0; 49290075Sobrien} 49390075Sobrien 49490075Sobrien/* Examine the attribute "predicable"; discover its boolean values 49590075Sobrien and its default. */ 49690075Sobrien 49790075Sobrienstatic void 49890075Sobrienidentify_predicable_attribute () 49990075Sobrien{ 50090075Sobrien struct queue_elem *elem; 50190075Sobrien char *p_true, *p_false; 50290075Sobrien const char *value; 50390075Sobrien size_t len; 50490075Sobrien 50590075Sobrien /* Look for the DEFINE_ATTR for `predicable', which must exist. */ 50690075Sobrien for (elem = define_attr_queue; elem ; elem = elem->next) 50790075Sobrien if (strcmp (XSTR (elem->data, 0), "predicable") == 0) 50890075Sobrien goto found; 50990075Sobrien 51090075Sobrien message_with_line (define_cond_exec_queue->lineno, 51190075Sobrien "attribute `predicable' not defined"); 51290075Sobrien errors = 1; 51390075Sobrien return; 51490075Sobrien 51590075Sobrien found: 51690075Sobrien value = XSTR (elem->data, 1); 51790075Sobrien len = strlen (value); 51890075Sobrien p_false = (char *) xmalloc (len + 1); 51990075Sobrien memcpy (p_false, value, len + 1); 52090075Sobrien 52190075Sobrien p_true = strchr (p_false, ','); 52290075Sobrien if (p_true == NULL || strchr (++p_true, ',') != NULL) 52390075Sobrien { 52490075Sobrien message_with_line (elem->lineno, 52590075Sobrien "attribute `predicable' is not a boolean"); 52690075Sobrien errors = 1; 52790075Sobrien return; 52890075Sobrien } 52990075Sobrien p_true[-1] = '\0'; 53090075Sobrien 53190075Sobrien predicable_true = p_true; 53290075Sobrien predicable_false = p_false; 53390075Sobrien 53490075Sobrien switch (GET_CODE (XEXP (elem->data, 2))) 53590075Sobrien { 53690075Sobrien case CONST_STRING: 53790075Sobrien value = XSTR (XEXP (elem->data, 2), 0); 53890075Sobrien break; 53990075Sobrien 54090075Sobrien case CONST: 54190075Sobrien message_with_line (elem->lineno, 54290075Sobrien "attribute `predicable' cannot be const"); 54390075Sobrien errors = 1; 54490075Sobrien return; 54590075Sobrien 54690075Sobrien default: 54790075Sobrien message_with_line (elem->lineno, 54890075Sobrien "attribute `predicable' must have a constant default"); 54990075Sobrien errors = 1; 55090075Sobrien return; 55190075Sobrien } 55290075Sobrien 55390075Sobrien if (strcmp (value, p_true) == 0) 55490075Sobrien predicable_default = 1; 55590075Sobrien else if (strcmp (value, p_false) == 0) 55690075Sobrien predicable_default = 0; 55790075Sobrien else 55890075Sobrien { 55990075Sobrien message_with_line (elem->lineno, 56090075Sobrien "unknown value `%s' for `predicable' attribute", 56190075Sobrien value); 56290075Sobrien errors = 1; 56390075Sobrien } 56490075Sobrien} 56590075Sobrien 56690075Sobrien/* Return the number of alternatives in constraint S. */ 56790075Sobrien 56890075Sobrienstatic int 56990075Sobrienn_alternatives (s) 57090075Sobrien const char *s; 57190075Sobrien{ 57290075Sobrien int n = 1; 57390075Sobrien 57490075Sobrien if (s) 57590075Sobrien while (*s) 57690075Sobrien n += (*s++ == ','); 57790075Sobrien 57890075Sobrien return n; 57990075Sobrien} 58090075Sobrien 58190075Sobrien/* Determine how many alternatives there are in INSN, and how many 58290075Sobrien operands. */ 58390075Sobrien 58490075Sobrienstatic void 58590075Sobriencollect_insn_data (pattern, palt, pmax) 58690075Sobrien rtx pattern; 58790075Sobrien int *palt, *pmax; 58890075Sobrien{ 58990075Sobrien const char *fmt; 59090075Sobrien enum rtx_code code; 59190075Sobrien int i, j, len; 59290075Sobrien 59390075Sobrien code = GET_CODE (pattern); 59490075Sobrien switch (code) 59590075Sobrien { 59690075Sobrien case MATCH_OPERAND: 59790075Sobrien i = n_alternatives (XSTR (pattern, 2)); 59890075Sobrien *palt = (i > *palt ? i : *palt); 59990075Sobrien /* FALLTHRU */ 60090075Sobrien 60190075Sobrien case MATCH_OPERATOR: 60290075Sobrien case MATCH_SCRATCH: 60390075Sobrien case MATCH_PARALLEL: 60490075Sobrien case MATCH_INSN: 60590075Sobrien i = XINT (pattern, 0); 60690075Sobrien if (i > *pmax) 60790075Sobrien *pmax = i; 60890075Sobrien break; 60990075Sobrien 61090075Sobrien default: 61190075Sobrien break; 61290075Sobrien } 61390075Sobrien 61490075Sobrien fmt = GET_RTX_FORMAT (code); 61590075Sobrien len = GET_RTX_LENGTH (code); 61690075Sobrien for (i = 0; i < len; i++) 61790075Sobrien { 61890075Sobrien switch (fmt[i]) 61990075Sobrien { 62090075Sobrien case 'e': case 'u': 62190075Sobrien collect_insn_data (XEXP (pattern, i), palt, pmax); 62290075Sobrien break; 62390075Sobrien 62490075Sobrien case 'V': 62590075Sobrien if (XVEC (pattern, i) == NULL) 62690075Sobrien break; 62790075Sobrien /* FALLTHRU */ 62890075Sobrien case 'E': 62990075Sobrien for (j = XVECLEN (pattern, i) - 1; j >= 0; --j) 63090075Sobrien collect_insn_data (XVECEXP (pattern, i, j), palt, pmax); 63190075Sobrien break; 63290075Sobrien 63390075Sobrien case 'i': case 'w': case '0': case 's': case 'S': case 'T': 63490075Sobrien break; 63590075Sobrien 63690075Sobrien default: 63790075Sobrien abort (); 63890075Sobrien } 63990075Sobrien } 64090075Sobrien} 64190075Sobrien 64290075Sobrienstatic rtx 64390075Sobrienalter_predicate_for_insn (pattern, alt, max_op, lineno) 64490075Sobrien rtx pattern; 64590075Sobrien int alt, max_op, lineno; 64690075Sobrien{ 64790075Sobrien const char *fmt; 64890075Sobrien enum rtx_code code; 64990075Sobrien int i, j, len; 65090075Sobrien 65190075Sobrien code = GET_CODE (pattern); 65290075Sobrien switch (code) 65390075Sobrien { 65490075Sobrien case MATCH_OPERAND: 65590075Sobrien { 65690075Sobrien const char *c = XSTR (pattern, 2); 65790075Sobrien 65890075Sobrien if (n_alternatives (c) != 1) 65990075Sobrien { 66090075Sobrien message_with_line (lineno, 66190075Sobrien "too many alternatives for operand %d", 66290075Sobrien XINT (pattern, 0)); 66390075Sobrien errors = 1; 66490075Sobrien return NULL; 66590075Sobrien } 66690075Sobrien 66790075Sobrien /* Replicate C as needed to fill out ALT alternatives. */ 66890075Sobrien if (c && *c && alt > 1) 66990075Sobrien { 67090075Sobrien size_t c_len = strlen (c); 67190075Sobrien size_t len = alt * (c_len + 1); 67290075Sobrien char *new_c = (char *) xmalloc (len); 67390075Sobrien 67490075Sobrien memcpy (new_c, c, c_len); 67590075Sobrien for (i = 1; i < alt; ++i) 67690075Sobrien { 67790075Sobrien new_c[i * (c_len + 1) - 1] = ','; 67890075Sobrien memcpy (&new_c[i * (c_len + 1)], c, c_len); 67990075Sobrien } 68090075Sobrien new_c[len - 1] = '\0'; 68190075Sobrien XSTR (pattern, 2) = new_c; 68290075Sobrien } 68390075Sobrien } 68490075Sobrien /* FALLTHRU */ 68590075Sobrien 68690075Sobrien case MATCH_OPERATOR: 68790075Sobrien case MATCH_SCRATCH: 68890075Sobrien case MATCH_PARALLEL: 68990075Sobrien case MATCH_INSN: 69090075Sobrien XINT (pattern, 0) += max_op; 69190075Sobrien break; 69290075Sobrien 69390075Sobrien default: 69490075Sobrien break; 69590075Sobrien } 69690075Sobrien 69790075Sobrien fmt = GET_RTX_FORMAT (code); 69890075Sobrien len = GET_RTX_LENGTH (code); 69990075Sobrien for (i = 0; i < len; i++) 70090075Sobrien { 70190075Sobrien rtx r; 70290075Sobrien 70390075Sobrien switch (fmt[i]) 70490075Sobrien { 70590075Sobrien case 'e': case 'u': 70690075Sobrien r = alter_predicate_for_insn (XEXP (pattern, i), alt, 70790075Sobrien max_op, lineno); 70890075Sobrien if (r == NULL) 70990075Sobrien return r; 71090075Sobrien break; 71190075Sobrien 71290075Sobrien case 'E': 71390075Sobrien for (j = XVECLEN (pattern, i) - 1; j >= 0; --j) 71490075Sobrien { 71590075Sobrien r = alter_predicate_for_insn (XVECEXP (pattern, i, j), 71690075Sobrien alt, max_op, lineno); 71790075Sobrien if (r == NULL) 71890075Sobrien return r; 71990075Sobrien } 72090075Sobrien break; 72190075Sobrien 72290075Sobrien case 'i': case 'w': case '0': case 's': 72390075Sobrien break; 72490075Sobrien 72590075Sobrien default: 72690075Sobrien abort (); 72790075Sobrien } 72890075Sobrien } 72990075Sobrien 73090075Sobrien return pattern; 73190075Sobrien} 73290075Sobrien 73390075Sobrienstatic const char * 73490075Sobrienalter_test_for_insn (ce_elem, insn_elem) 73590075Sobrien struct queue_elem *ce_elem, *insn_elem; 73690075Sobrien{ 73790075Sobrien const char *ce_test, *insn_test; 73890075Sobrien char *new_test; 73990075Sobrien size_t len, ce_len, insn_len; 74090075Sobrien 74190075Sobrien ce_test = XSTR (ce_elem->data, 1); 74290075Sobrien insn_test = XSTR (insn_elem->data, 2); 74390075Sobrien if (!ce_test || *ce_test == '\0') 74490075Sobrien return insn_test; 74590075Sobrien if (!insn_test || *insn_test == '\0') 74690075Sobrien return ce_test; 74790075Sobrien 74890075Sobrien ce_len = strlen (ce_test); 74990075Sobrien insn_len = strlen (insn_test); 75090075Sobrien len = 1 + ce_len + 1 + 4 + 1 + insn_len + 1 + 1; 75190075Sobrien new_test = (char *) xmalloc (len); 75290075Sobrien 75390075Sobrien sprintf (new_test, "(%s) && (%s)", ce_test, insn_test); 75490075Sobrien 75590075Sobrien return new_test; 75690075Sobrien} 75790075Sobrien 75890075Sobrien/* Adjust all of the operand numbers in OLD to match the shift they'll 75990075Sobrien get from an operand displacement of DISP. Return a pointer after the 76090075Sobrien adjusted string. */ 76190075Sobrien 76290075Sobrienstatic char * 76390075Sobrienshift_output_template (new, old, disp) 76490075Sobrien char *new; 76590075Sobrien const char *old; 76690075Sobrien int disp; 76790075Sobrien{ 76890075Sobrien while (*old) 76990075Sobrien { 77090075Sobrien char c = *old++; 77190075Sobrien *new++ = c; 77290075Sobrien if (c == '%') 77390075Sobrien { 77490075Sobrien c = *old++; 77590075Sobrien if (ISDIGIT ((unsigned char) c)) 77690075Sobrien c += disp; 77790075Sobrien else if (ISALPHA (c)) 77890075Sobrien { 77990075Sobrien *new++ = c; 78090075Sobrien c = *old++ + disp; 78190075Sobrien } 78290075Sobrien *new++ = c; 78390075Sobrien } 78490075Sobrien } 78590075Sobrien 78690075Sobrien return new; 78790075Sobrien} 78890075Sobrien 78990075Sobrienstatic const char * 79090075Sobrienalter_output_for_insn (ce_elem, insn_elem, alt, max_op) 79190075Sobrien struct queue_elem *ce_elem, *insn_elem; 79290075Sobrien int alt, max_op; 79390075Sobrien{ 79490075Sobrien const char *ce_out, *insn_out; 79590075Sobrien char *new, *p; 79690075Sobrien size_t len, ce_len, insn_len; 79790075Sobrien 79890075Sobrien /* ??? Could coordinate with genoutput to not duplicate code here. */ 79990075Sobrien 80090075Sobrien ce_out = XSTR (ce_elem->data, 2); 80190075Sobrien insn_out = XTMPL (insn_elem->data, 3); 80290075Sobrien if (!ce_out || *ce_out == '\0') 80390075Sobrien return insn_out; 80490075Sobrien 80590075Sobrien ce_len = strlen (ce_out); 80690075Sobrien insn_len = strlen (insn_out); 80790075Sobrien 80890075Sobrien if (*insn_out == '*') 80990075Sobrien /* You must take care of the predicate yourself. */ 81090075Sobrien return insn_out; 81190075Sobrien 81290075Sobrien if (*insn_out == '@') 81390075Sobrien { 81490075Sobrien len = (ce_len + 1) * alt + insn_len + 1; 81590075Sobrien p = new = xmalloc (len); 81690075Sobrien 81790075Sobrien do 81890075Sobrien { 81990075Sobrien do 82090075Sobrien *p++ = *insn_out++; 82190075Sobrien while (ISSPACE ((unsigned char) *insn_out)); 82290075Sobrien 82390075Sobrien if (*insn_out != '#') 82490075Sobrien { 82590075Sobrien p = shift_output_template (p, ce_out, max_op); 82690075Sobrien *p++ = ' '; 82790075Sobrien } 82890075Sobrien 82990075Sobrien do 83090075Sobrien *p++ = *insn_out++; 83190075Sobrien while (*insn_out && *insn_out != '\n'); 83290075Sobrien } 83390075Sobrien while (*insn_out); 83490075Sobrien *p = '\0'; 83590075Sobrien } 83690075Sobrien else 83790075Sobrien { 83890075Sobrien len = ce_len + 1 + insn_len + 1; 83990075Sobrien new = xmalloc (len); 84090075Sobrien 84190075Sobrien p = shift_output_template (new, ce_out, max_op); 84290075Sobrien *p++ = ' '; 84390075Sobrien memcpy (p, insn_out, insn_len + 1); 84490075Sobrien } 84590075Sobrien 84690075Sobrien return new; 84790075Sobrien} 84890075Sobrien 84990075Sobrien/* Replicate insns as appropriate for the given DEFINE_COND_EXEC. */ 85090075Sobrien 85190075Sobrienstatic void 85290075Sobrienprocess_one_cond_exec (ce_elem) 85390075Sobrien struct queue_elem *ce_elem; 85490075Sobrien{ 85590075Sobrien struct queue_elem *insn_elem; 85690075Sobrien for (insn_elem = define_insn_queue; insn_elem ; insn_elem = insn_elem->next) 85790075Sobrien { 85890075Sobrien int alternatives, max_operand; 85990075Sobrien rtx pred, insn, pattern; 86090075Sobrien 86190075Sobrien if (! is_predicable (insn_elem)) 86290075Sobrien continue; 86390075Sobrien 86490075Sobrien alternatives = 1; 86590075Sobrien max_operand = -1; 86690075Sobrien collect_insn_data (insn_elem->data, &alternatives, &max_operand); 86790075Sobrien max_operand += 1; 86890075Sobrien 86990075Sobrien if (XVECLEN (ce_elem->data, 0) != 1) 87090075Sobrien { 87190075Sobrien message_with_line (ce_elem->lineno, 87290075Sobrien "too many patterns in predicate"); 87390075Sobrien errors = 1; 87490075Sobrien return; 87590075Sobrien } 87690075Sobrien 87790075Sobrien pred = copy_rtx (XVECEXP (ce_elem->data, 0, 0)); 87890075Sobrien pred = alter_predicate_for_insn (pred, alternatives, max_operand, 87990075Sobrien ce_elem->lineno); 88090075Sobrien if (pred == NULL) 88190075Sobrien return; 88290075Sobrien 88390075Sobrien /* Construct a new pattern for the new insn. */ 88490075Sobrien insn = copy_rtx (insn_elem->data); 88590075Sobrien XSTR (insn, 0) = ""; 88690075Sobrien pattern = rtx_alloc (COND_EXEC); 88790075Sobrien XEXP (pattern, 0) = pred; 88890075Sobrien if (XVECLEN (insn, 1) == 1) 88990075Sobrien { 89090075Sobrien XEXP (pattern, 1) = XVECEXP (insn, 1, 0); 89190075Sobrien XVECEXP (insn, 1, 0) = pattern; 89290075Sobrien PUT_NUM_ELEM (XVEC (insn, 1), 1); 89390075Sobrien } 89490075Sobrien else 89590075Sobrien { 89690075Sobrien XEXP (pattern, 1) = rtx_alloc (PARALLEL); 89790075Sobrien XVEC (XEXP (pattern, 1), 0) = XVEC (insn, 1); 89890075Sobrien XVEC (insn, 1) = rtvec_alloc (1); 89990075Sobrien XVECEXP (insn, 1, 0) = pattern; 90090075Sobrien } 90190075Sobrien 90290075Sobrien XSTR (insn, 2) = alter_test_for_insn (ce_elem, insn_elem); 90390075Sobrien XTMPL (insn, 3) = alter_output_for_insn (ce_elem, insn_elem, 90490075Sobrien alternatives, max_operand); 90590075Sobrien 90690075Sobrien /* ??? Set `predicable' to false. Not crucial since it's really 90790075Sobrien only used here, and we won't reprocess this new pattern. */ 90890075Sobrien 90990075Sobrien /* Put the new pattern on the `other' list so that it 91090075Sobrien (a) is not reprocessed by other define_cond_exec patterns 91190075Sobrien (b) appears after all normal define_insn patterns. 91290075Sobrien 91390075Sobrien ??? B is debatable. If one has normal insns that match 91490075Sobrien cond_exec patterns, they will be preferred over these 91590075Sobrien generated patterns. Whether this matters in practice, or if 91690075Sobrien it's a good thing, or whether we should thread these new 91790075Sobrien patterns into the define_insn chain just after their generator 91890075Sobrien is something we'll have to experiment with. */ 91990075Sobrien 92090075Sobrien queue_pattern (insn, &other_tail, insn_elem->lineno); 92190075Sobrien } 92290075Sobrien} 92390075Sobrien 92490075Sobrien/* If we have any DEFINE_COND_EXEC patterns, expand the DEFINE_INSN 92590075Sobrien patterns appropriately. */ 92690075Sobrien 92790075Sobrienstatic void 92890075Sobrienprocess_define_cond_exec () 92990075Sobrien{ 93090075Sobrien struct queue_elem *elem; 93190075Sobrien 93290075Sobrien identify_predicable_attribute (); 93390075Sobrien if (errors) 93490075Sobrien return; 93590075Sobrien 93690075Sobrien for (elem = define_cond_exec_queue; elem ; elem = elem->next) 93790075Sobrien process_one_cond_exec (elem); 93890075Sobrien} 93990075Sobrien 94090075Sobrienstatic char * 94190075Sobriensave_string (s, len) 94290075Sobrien const char *s; 94390075Sobrien int len; 94490075Sobrien{ 94590075Sobrien register char *result = xmalloc (len + 1); 94690075Sobrien 94790075Sobrien memcpy (result, s, len); 94890075Sobrien result[len] = 0; 94990075Sobrien return result; 95090075Sobrien} 95190075Sobrien 95290075Sobrien 95390075Sobrien/* The entry point for initializing the reader. */ 95490075Sobrien 95590075Sobrienint 95690075Sobrieninit_md_reader_args (argc, argv) 95790075Sobrien int argc; 95890075Sobrien char **argv; 95990075Sobrien{ 96090075Sobrien int i; 96190075Sobrien const char *in_fname; 96290075Sobrien 96390075Sobrien max_include_len = 0; 96490075Sobrien in_fname = NULL; 96590075Sobrien for (i = 1; i < argc; i++) 96690075Sobrien { 96790075Sobrien if (argv[i][0] != '-') 96890075Sobrien { 96990075Sobrien if (in_fname == NULL) 97090075Sobrien in_fname = argv[i]; 97190075Sobrien } 97290075Sobrien else 97390075Sobrien { 97490075Sobrien int c = argv[i][1]; 97590075Sobrien switch (c) 97690075Sobrien { 97790075Sobrien case 'I': /* Add directory to path for includes. */ 97890075Sobrien { 97990075Sobrien struct file_name_list *dirtmp; 98090075Sobrien 98190075Sobrien dirtmp = (struct file_name_list *) 98290075Sobrien xmalloc (sizeof (struct file_name_list)); 98390075Sobrien dirtmp->next = 0; /* New one goes on the end */ 98490075Sobrien if (include == 0) 98590075Sobrien include = dirtmp; 98690075Sobrien else 98790075Sobrien last_include->next = dirtmp; 98890075Sobrien last_include = dirtmp; /* Tail follows the last one */ 98990075Sobrien if (argv[i][1] == 'I' && argv[i][2] != 0) 99090075Sobrien dirtmp->fname = argv[i] + 2; 99190075Sobrien else if (i + 1 == argc) 99290075Sobrien fatal ("directory name missing after -I option"); 99390075Sobrien else 99490075Sobrien dirtmp->fname = argv[++i]; 99590075Sobrien if (strlen (dirtmp->fname) > max_include_len) 99690075Sobrien max_include_len = strlen (dirtmp->fname); 99790075Sobrien } 99890075Sobrien break; 99990075Sobrien default: 100090075Sobrien fatal ("invalid option `%s'", argv[i]); 100190075Sobrien 100290075Sobrien } 100390075Sobrien } 100490075Sobrien } 100590075Sobrien return init_md_reader (in_fname); 100690075Sobrien} 100790075Sobrien 100890075Sobrien/* The entry point for initializing the reader. */ 100990075Sobrien 101090075Sobrienint 101190075Sobrieninit_md_reader (filename) 101290075Sobrien const char *filename; 101390075Sobrien{ 101490075Sobrien FILE *input_file; 101590075Sobrien int c; 101690075Sobrien char *lastsl; 101790075Sobrien 101890075Sobrien if (!IS_ABSOLUTE_PATHNAME (filename)) 101990075Sobrien { 102090075Sobrien lastsl = strrchr (filename, '/'); 102190075Sobrien if (lastsl != NULL) 102290075Sobrien base_dir = save_string (filename, lastsl - filename + 1 ); 102390075Sobrien } 102490075Sobrien 102590075Sobrien read_rtx_filename = filename; 102690075Sobrien input_file = fopen (filename, "r"); 102790075Sobrien if (input_file == 0) 102890075Sobrien { 102990075Sobrien perror (filename); 103090075Sobrien return FATAL_EXIT_CODE; 103190075Sobrien } 103290075Sobrien 103390075Sobrien obstack_init (rtl_obstack); 103490075Sobrien errors = 0; 103590075Sobrien sequence_num = 0; 103690075Sobrien 103790075Sobrien /* Read the entire file. */ 103890075Sobrien while (1) 103990075Sobrien { 104090075Sobrien rtx desc; 104190075Sobrien int lineno; 104290075Sobrien 104390075Sobrien c = read_skip_spaces (input_file); 104490075Sobrien if (c == EOF) 104590075Sobrien break; 104690075Sobrien 104790075Sobrien ungetc (c, input_file); 104890075Sobrien lineno = read_rtx_lineno; 104990075Sobrien desc = read_rtx (input_file); 105090075Sobrien process_rtx (desc, lineno); 105190075Sobrien } 105290075Sobrien fclose (input_file); 105390075Sobrien 105490075Sobrien /* Process define_cond_exec patterns. */ 105590075Sobrien if (define_cond_exec_queue != NULL) 105690075Sobrien process_define_cond_exec (); 105790075Sobrien 105890075Sobrien return errors ? FATAL_EXIT_CODE : SUCCESS_EXIT_CODE; 105990075Sobrien} 106090075Sobrien 106190075Sobrien/* The entry point for reading a single rtx from an md file. */ 106290075Sobrien 106390075Sobrienrtx 106490075Sobrienread_md_rtx (lineno, seqnr) 106590075Sobrien int *lineno; 106690075Sobrien int *seqnr; 106790075Sobrien{ 106890075Sobrien struct queue_elem **queue, *elem; 106990075Sobrien rtx desc; 107090075Sobrien 107190075Sobrien /* Read all patterns from a given queue before moving on to the next. */ 107290075Sobrien if (define_attr_queue != NULL) 107390075Sobrien queue = &define_attr_queue; 107490075Sobrien else if (define_insn_queue != NULL) 107590075Sobrien queue = &define_insn_queue; 107690075Sobrien else if (other_queue != NULL) 107790075Sobrien queue = &other_queue; 107890075Sobrien else 107990075Sobrien return NULL_RTX; 108090075Sobrien 108190075Sobrien elem = *queue; 108290075Sobrien *queue = elem->next; 108390075Sobrien desc = elem->data; 108490075Sobrien *lineno = elem->lineno; 108590075Sobrien *seqnr = sequence_num; 108690075Sobrien 108790075Sobrien free (elem); 108890075Sobrien 108990075Sobrien switch (GET_CODE (desc)) 109090075Sobrien { 109190075Sobrien case DEFINE_INSN: 109290075Sobrien case DEFINE_EXPAND: 109390075Sobrien case DEFINE_SPLIT: 109490075Sobrien case DEFINE_PEEPHOLE: 109590075Sobrien case DEFINE_PEEPHOLE2: 109690075Sobrien sequence_num++; 109790075Sobrien break; 109890075Sobrien 109990075Sobrien default: 110090075Sobrien break; 110190075Sobrien } 110290075Sobrien 110390075Sobrien return desc; 110490075Sobrien} 1105