190075Sobrien/* Support routines for the various generation passes. 2169689Skan Copyright (C) 2000, 2001, 2002, 2003, 2004, 2005, 2006 3132718Skan Free Software Foundation, Inc. 490075Sobrien 590075Sobrien This file is part of GCC. 690075Sobrien 790075Sobrien GCC is free software; you can redistribute it and/or modify it 890075Sobrien under the terms of the GNU General Public License as published by 990075Sobrien the Free Software Foundation; either version 2, or (at your option) 1090075Sobrien any later version. 1190075Sobrien 1290075Sobrien GCC is distributed in the hope that it will be useful, but WITHOUT 1390075Sobrien ANY WARRANTY; without even the implied warranty of MERCHANTABILITY 1490075Sobrien or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public 1590075Sobrien License for more details. 1690075Sobrien 1790075Sobrien You should have received a copy of the GNU General Public License 1890075Sobrien along with GCC; see the file COPYING. If not, write to the Free 19169689Skan Software Foundation, 51 Franklin Street, Fifth Floor, Boston, MA 20169689Skan 02110-1301, USA. */ 2190075Sobrien 22132718Skan#include "bconfig.h" 2390075Sobrien#include "system.h" 24132718Skan#include "coretypes.h" 25132718Skan#include "tm.h" 2690075Sobrien#include "rtl.h" 2790075Sobrien#include "obstack.h" 2890075Sobrien#include "errors.h" 29117395Skan#include "hashtab.h" 3090075Sobrien#include "gensupport.h" 3190075Sobrien 3290075Sobrien 3390075Sobrien/* In case some macros used by files we include need it, define this here. */ 3490075Sobrienint target_flags; 3590075Sobrien 36117395Skanint insn_elision = 1; 37117395Skan 38169689Skanconst char *in_fname; 39169689Skan 40169689Skan/* This callback will be invoked whenever an rtl include directive is 41169689Skan processed. To be used for creation of the dependency file. */ 42169689Skanvoid (*include_callback) (const char *); 43169689Skan 4490075Sobrienstatic struct obstack obstack; 4590075Sobrienstruct obstack *rtl_obstack = &obstack; 4690075Sobrien 4790075Sobrienstatic int sequence_num; 4890075Sobrienstatic int errors; 4990075Sobrien 5090075Sobrienstatic int predicable_default; 5190075Sobrienstatic const char *predicable_true; 5290075Sobrienstatic const char *predicable_false; 5390075Sobrien 54117395Skanstatic htab_t condition_table; 55117395Skan 5690075Sobrienstatic char *base_dir = NULL; 5790075Sobrien 5890075Sobrien/* We initially queue all patterns, process the define_insn and 5990075Sobrien define_cond_exec patterns, then return them one at a time. */ 6090075Sobrien 6190075Sobrienstruct queue_elem 6290075Sobrien{ 6390075Sobrien rtx data; 64117395Skan const char *filename; 6590075Sobrien int lineno; 6690075Sobrien struct queue_elem *next; 67169689Skan /* In a DEFINE_INSN that came from a DEFINE_INSN_AND_SPLIT, SPLIT 68169689Skan points to the generated DEFINE_SPLIT. */ 69169689Skan struct queue_elem *split; 7090075Sobrien}; 7190075Sobrien 7290075Sobrienstatic struct queue_elem *define_attr_queue; 7390075Sobrienstatic struct queue_elem **define_attr_tail = &define_attr_queue; 74169689Skanstatic struct queue_elem *define_pred_queue; 75169689Skanstatic struct queue_elem **define_pred_tail = &define_pred_queue; 7690075Sobrienstatic struct queue_elem *define_insn_queue; 7790075Sobrienstatic struct queue_elem **define_insn_tail = &define_insn_queue; 7890075Sobrienstatic struct queue_elem *define_cond_exec_queue; 7990075Sobrienstatic struct queue_elem **define_cond_exec_tail = &define_cond_exec_queue; 8090075Sobrienstatic struct queue_elem *other_queue; 8190075Sobrienstatic struct queue_elem **other_tail = &other_queue; 8290075Sobrien 83169689Skanstatic struct queue_elem *queue_pattern (rtx, struct queue_elem ***, 84169689Skan const char *, int); 8590075Sobrien 8690075Sobrien/* Current maximum length of directory names in the search path 8790075Sobrien for include files. (Altered as we get more of them.) */ 8890075Sobrien 8990075Sobriensize_t max_include_len; 9090075Sobrien 9190075Sobrienstruct file_name_list 9290075Sobrien { 9390075Sobrien struct file_name_list *next; 9490075Sobrien const char *fname; 9590075Sobrien }; 9690075Sobrien 97117395Skanstruct file_name_list *first_dir_md_include = 0; /* First dir to search */ 9890075Sobrien /* First dir to search for <file> */ 9990075Sobrienstruct file_name_list *first_bracket_include = 0; 100117395Skanstruct file_name_list *last_dir_md_include = 0; /* Last in chain */ 10190075Sobrien 102132718Skanstatic void remove_constraints (rtx); 103132718Skanstatic void process_rtx (rtx, int); 10490075Sobrien 105132718Skanstatic int is_predicable (struct queue_elem *); 106132718Skanstatic void identify_predicable_attribute (void); 107132718Skanstatic int n_alternatives (const char *); 108132718Skanstatic void collect_insn_data (rtx, int *, int *); 109132718Skanstatic rtx alter_predicate_for_insn (rtx, int, int, int); 110132718Skanstatic const char *alter_test_for_insn (struct queue_elem *, 111132718Skan struct queue_elem *); 112132718Skanstatic char *shift_output_template (char *, const char *, int); 113132718Skanstatic const char *alter_output_for_insn (struct queue_elem *, 114132718Skan struct queue_elem *, 115132718Skan int, int); 116132718Skanstatic void process_one_cond_exec (struct queue_elem *); 117132718Skanstatic void process_define_cond_exec (void); 118132718Skanstatic void process_include (rtx, int); 119132718Skanstatic char *save_string (const char *, int); 120169689Skanstatic void init_predicate_table (void); 121169689Skanstatic void record_insn_name (int, const char *); 12290075Sobrien 12390075Sobrienvoid 124132718Skanmessage_with_line (int lineno, const char *msg, ...) 12590075Sobrien{ 126132718Skan va_list ap; 12790075Sobrien 128132718Skan va_start (ap, msg); 129132718Skan 13090075Sobrien fprintf (stderr, "%s:%d: ", read_rtx_filename, lineno); 13190075Sobrien vfprintf (stderr, msg, ap); 13290075Sobrien fputc ('\n', stderr); 13390075Sobrien 134132718Skan va_end (ap); 13590075Sobrien} 13690075Sobrien 13790075Sobrien/* Make a version of gen_rtx_CONST_INT so that GEN_INT can be used in 13890075Sobrien the gensupport programs. */ 13990075Sobrien 14090075Sobrienrtx 141169689Skangen_rtx_CONST_INT (enum machine_mode ARG_UNUSED (mode), 142132718Skan HOST_WIDE_INT arg) 14390075Sobrien{ 14490075Sobrien rtx rt = rtx_alloc (CONST_INT); 14590075Sobrien 14690075Sobrien XWINT (rt, 0) = arg; 14790075Sobrien return rt; 14890075Sobrien} 14990075Sobrien 150169689Skan/* Queue PATTERN on LIST_TAIL. Return the address of the new queue 151169689Skan element. */ 15290075Sobrien 153169689Skanstatic struct queue_elem * 154132718Skanqueue_pattern (rtx pattern, struct queue_elem ***list_tail, 155132718Skan const char *filename, int lineno) 15690075Sobrien{ 157169689Skan struct queue_elem *e = XNEW(struct queue_elem); 15890075Sobrien e->data = pattern; 159117395Skan e->filename = filename; 16090075Sobrien e->lineno = lineno; 16190075Sobrien e->next = NULL; 162169689Skan e->split = NULL; 16390075Sobrien **list_tail = e; 16490075Sobrien *list_tail = &e->next; 165169689Skan return e; 16690075Sobrien} 16790075Sobrien 16890075Sobrien/* Recursively remove constraints from an rtx. */ 16990075Sobrien 17090075Sobrienstatic void 171132718Skanremove_constraints (rtx part) 17290075Sobrien{ 17390075Sobrien int i, j; 17490075Sobrien const char *format_ptr; 17590075Sobrien 17690075Sobrien if (part == 0) 17790075Sobrien return; 17890075Sobrien 17990075Sobrien if (GET_CODE (part) == MATCH_OPERAND) 18090075Sobrien XSTR (part, 2) = ""; 18190075Sobrien else if (GET_CODE (part) == MATCH_SCRATCH) 18290075Sobrien XSTR (part, 1) = ""; 18390075Sobrien 18490075Sobrien format_ptr = GET_RTX_FORMAT (GET_CODE (part)); 18590075Sobrien 18690075Sobrien for (i = 0; i < GET_RTX_LENGTH (GET_CODE (part)); i++) 18790075Sobrien switch (*format_ptr++) 18890075Sobrien { 18990075Sobrien case 'e': 19090075Sobrien case 'u': 19190075Sobrien remove_constraints (XEXP (part, i)); 19290075Sobrien break; 19390075Sobrien case 'E': 19490075Sobrien if (XVEC (part, i) != NULL) 19590075Sobrien for (j = 0; j < XVECLEN (part, i); j++) 19690075Sobrien remove_constraints (XVECEXP (part, i, j)); 19790075Sobrien break; 19890075Sobrien } 19990075Sobrien} 20090075Sobrien 201132718Skan/* Process an include file assuming that it lives in gcc/config/{target}/ 202117395Skan if the include looks like (include "file"). */ 20390075Sobrien 204117395Skanstatic void 205132718Skanprocess_include (rtx desc, int lineno) 20690075Sobrien{ 20790075Sobrien const char *filename = XSTR (desc, 0); 208117395Skan const char *old_filename; 209117395Skan int old_lineno; 210117395Skan char *pathname; 21190075Sobrien FILE *input_file; 21290075Sobrien 213117395Skan /* If specified file name is absolute, skip the include stack. */ 214132718Skan if (! IS_ABSOLUTE_PATH (filename)) 21590075Sobrien { 216117395Skan struct file_name_list *stackp; 21790075Sobrien 218117395Skan /* Search directory path, trying to open the file. */ 219117395Skan for (stackp = first_dir_md_include; stackp; stackp = stackp->next) 22090075Sobrien { 221117395Skan static const char sep[2] = { DIR_SEPARATOR, '\0' }; 222117395Skan 223117395Skan pathname = concat (stackp->fname, sep, filename, NULL); 224117395Skan input_file = fopen (pathname, "r"); 225132718Skan if (input_file != NULL) 226117395Skan goto success; 227117395Skan free (pathname); 22890075Sobrien } 22990075Sobrien } 230117395Skan 231117395Skan if (base_dir) 232117395Skan pathname = concat (base_dir, filename, NULL); 233117395Skan else 234117395Skan pathname = xstrdup (filename); 235117395Skan input_file = fopen (pathname, "r"); 236117395Skan if (input_file == NULL) 23790075Sobrien { 238117395Skan free (pathname); 239117395Skan message_with_line (lineno, "include file `%s' not found", filename); 240117395Skan errors = 1; 241117395Skan return; 242117395Skan } 243117395Skan success: 24490075Sobrien 245117395Skan /* Save old cursor; setup new for the new file. Note that "lineno" the 246117395Skan argument to this function is the beginning of the include statement, 247117395Skan while read_rtx_lineno has already been advanced. */ 248117395Skan old_filename = read_rtx_filename; 249117395Skan old_lineno = read_rtx_lineno; 250117395Skan read_rtx_filename = pathname; 251117395Skan read_rtx_lineno = 1; 25290075Sobrien 253169689Skan if (include_callback) 254169689Skan include_callback (pathname); 255169689Skan 256117395Skan /* Read the entire file. */ 257169689Skan while (read_rtx (input_file, &desc, &lineno)) 258169689Skan process_rtx (desc, lineno); 25990075Sobrien 260117395Skan /* Do not free pathname. It is attached to the various rtx queue 261117395Skan elements. */ 26290075Sobrien 263117395Skan read_rtx_filename = old_filename; 264117395Skan read_rtx_lineno = old_lineno; 26590075Sobrien 266117395Skan fclose (input_file); 26790075Sobrien} 26890075Sobrien 269132718Skan/* Process a top level rtx in some way, queuing as appropriate. */ 27090075Sobrien 27190075Sobrienstatic void 272132718Skanprocess_rtx (rtx desc, int lineno) 27390075Sobrien{ 27490075Sobrien switch (GET_CODE (desc)) 27590075Sobrien { 27690075Sobrien case DEFINE_INSN: 277117395Skan queue_pattern (desc, &define_insn_tail, read_rtx_filename, lineno); 27890075Sobrien break; 27990075Sobrien 28090075Sobrien case DEFINE_COND_EXEC: 281117395Skan queue_pattern (desc, &define_cond_exec_tail, read_rtx_filename, lineno); 28290075Sobrien break; 28390075Sobrien 28490075Sobrien case DEFINE_ATTR: 285117395Skan queue_pattern (desc, &define_attr_tail, read_rtx_filename, lineno); 28690075Sobrien break; 28790075Sobrien 288169689Skan case DEFINE_PREDICATE: 289169689Skan case DEFINE_SPECIAL_PREDICATE: 290169689Skan case DEFINE_CONSTRAINT: 291169689Skan case DEFINE_REGISTER_CONSTRAINT: 292169689Skan case DEFINE_MEMORY_CONSTRAINT: 293169689Skan case DEFINE_ADDRESS_CONSTRAINT: 294169689Skan queue_pattern (desc, &define_pred_tail, read_rtx_filename, lineno); 295169689Skan break; 296169689Skan 29790075Sobrien case INCLUDE: 298117395Skan process_include (desc, lineno); 29990075Sobrien break; 30090075Sobrien 30190075Sobrien case DEFINE_INSN_AND_SPLIT: 30290075Sobrien { 30390075Sobrien const char *split_cond; 30490075Sobrien rtx split; 30590075Sobrien rtvec attr; 30690075Sobrien int i; 307169689Skan struct queue_elem *insn_elem; 308169689Skan struct queue_elem *split_elem; 30990075Sobrien 31090075Sobrien /* Create a split with values from the insn_and_split. */ 31190075Sobrien split = rtx_alloc (DEFINE_SPLIT); 31290075Sobrien 31390075Sobrien i = XVECLEN (desc, 1); 31490075Sobrien XVEC (split, 0) = rtvec_alloc (i); 31590075Sobrien while (--i >= 0) 31690075Sobrien { 31790075Sobrien XVECEXP (split, 0, i) = copy_rtx (XVECEXP (desc, 1, i)); 31890075Sobrien remove_constraints (XVECEXP (split, 0, i)); 31990075Sobrien } 32090075Sobrien 32190075Sobrien /* If the split condition starts with "&&", append it to the 32290075Sobrien insn condition to create the new split condition. */ 32390075Sobrien split_cond = XSTR (desc, 4); 32490075Sobrien if (split_cond[0] == '&' && split_cond[1] == '&') 325169689Skan { 326169689Skan copy_rtx_ptr_loc (split_cond + 2, split_cond); 327169689Skan split_cond = join_c_conditions (XSTR (desc, 2), split_cond + 2); 328169689Skan } 32990075Sobrien XSTR (split, 1) = split_cond; 33090075Sobrien XVEC (split, 2) = XVEC (desc, 5); 33190075Sobrien XSTR (split, 3) = XSTR (desc, 6); 33290075Sobrien 33390075Sobrien /* Fix up the DEFINE_INSN. */ 33490075Sobrien attr = XVEC (desc, 7); 33590075Sobrien PUT_CODE (desc, DEFINE_INSN); 33690075Sobrien XVEC (desc, 4) = attr; 33790075Sobrien 33890075Sobrien /* Queue them. */ 339169689Skan insn_elem 340169689Skan = queue_pattern (desc, &define_insn_tail, read_rtx_filename, 341169689Skan lineno); 342169689Skan split_elem 343169689Skan = queue_pattern (split, &other_tail, read_rtx_filename, lineno); 344169689Skan insn_elem->split = split_elem; 34590075Sobrien break; 34690075Sobrien } 34790075Sobrien 34890075Sobrien default: 349117395Skan queue_pattern (desc, &other_tail, read_rtx_filename, lineno); 35090075Sobrien break; 35190075Sobrien } 35290075Sobrien} 35390075Sobrien 35490075Sobrien/* Return true if attribute PREDICABLE is true for ELEM, which holds 35590075Sobrien a DEFINE_INSN. */ 35690075Sobrien 35790075Sobrienstatic int 358132718Skanis_predicable (struct queue_elem *elem) 35990075Sobrien{ 36090075Sobrien rtvec vec = XVEC (elem->data, 4); 36190075Sobrien const char *value; 36290075Sobrien int i; 36390075Sobrien 36490075Sobrien if (! vec) 36590075Sobrien return predicable_default; 36690075Sobrien 36790075Sobrien for (i = GET_NUM_ELEM (vec) - 1; i >= 0; --i) 36890075Sobrien { 36990075Sobrien rtx sub = RTVEC_ELT (vec, i); 37090075Sobrien switch (GET_CODE (sub)) 37190075Sobrien { 37290075Sobrien case SET_ATTR: 37390075Sobrien if (strcmp (XSTR (sub, 0), "predicable") == 0) 37490075Sobrien { 37590075Sobrien value = XSTR (sub, 1); 37690075Sobrien goto found; 37790075Sobrien } 37890075Sobrien break; 37990075Sobrien 38090075Sobrien case SET_ATTR_ALTERNATIVE: 38190075Sobrien if (strcmp (XSTR (sub, 0), "predicable") == 0) 38290075Sobrien { 38390075Sobrien message_with_line (elem->lineno, 38490075Sobrien "multiple alternatives for `predicable'"); 38590075Sobrien errors = 1; 38690075Sobrien return 0; 38790075Sobrien } 38890075Sobrien break; 38990075Sobrien 39090075Sobrien case SET: 39190075Sobrien if (GET_CODE (SET_DEST (sub)) != ATTR 39290075Sobrien || strcmp (XSTR (SET_DEST (sub), 0), "predicable") != 0) 39390075Sobrien break; 39490075Sobrien sub = SET_SRC (sub); 39590075Sobrien if (GET_CODE (sub) == CONST_STRING) 39690075Sobrien { 39790075Sobrien value = XSTR (sub, 0); 39890075Sobrien goto found; 39990075Sobrien } 40090075Sobrien 40190075Sobrien /* ??? It would be possible to handle this if we really tried. 40290075Sobrien It's not easy though, and I'm not going to bother until it 40390075Sobrien really proves necessary. */ 40490075Sobrien message_with_line (elem->lineno, 40590075Sobrien "non-constant value for `predicable'"); 40690075Sobrien errors = 1; 40790075Sobrien return 0; 40890075Sobrien 40990075Sobrien default: 410169689Skan gcc_unreachable (); 41190075Sobrien } 41290075Sobrien } 41390075Sobrien 41490075Sobrien return predicable_default; 41590075Sobrien 41690075Sobrien found: 41790075Sobrien /* Verify that predicability does not vary on the alternative. */ 41890075Sobrien /* ??? It should be possible to handle this by simply eliminating 41990075Sobrien the non-predicable alternatives from the insn. FRV would like 42090075Sobrien to do this. Delay this until we've got the basics solid. */ 42190075Sobrien if (strchr (value, ',') != NULL) 42290075Sobrien { 42390075Sobrien message_with_line (elem->lineno, 42490075Sobrien "multiple alternatives for `predicable'"); 42590075Sobrien errors = 1; 42690075Sobrien return 0; 42790075Sobrien } 42890075Sobrien 42990075Sobrien /* Find out which value we're looking at. */ 43090075Sobrien if (strcmp (value, predicable_true) == 0) 43190075Sobrien return 1; 43290075Sobrien if (strcmp (value, predicable_false) == 0) 43390075Sobrien return 0; 43490075Sobrien 43590075Sobrien message_with_line (elem->lineno, 43690075Sobrien "unknown value `%s' for `predicable' attribute", 43790075Sobrien value); 43890075Sobrien errors = 1; 43990075Sobrien return 0; 44090075Sobrien} 44190075Sobrien 44290075Sobrien/* Examine the attribute "predicable"; discover its boolean values 44390075Sobrien and its default. */ 44490075Sobrien 44590075Sobrienstatic void 446132718Skanidentify_predicable_attribute (void) 44790075Sobrien{ 44890075Sobrien struct queue_elem *elem; 44990075Sobrien char *p_true, *p_false; 45090075Sobrien const char *value; 45190075Sobrien 45290075Sobrien /* Look for the DEFINE_ATTR for `predicable', which must exist. */ 45390075Sobrien for (elem = define_attr_queue; elem ; elem = elem->next) 45490075Sobrien if (strcmp (XSTR (elem->data, 0), "predicable") == 0) 45590075Sobrien goto found; 45690075Sobrien 45790075Sobrien message_with_line (define_cond_exec_queue->lineno, 45890075Sobrien "attribute `predicable' not defined"); 45990075Sobrien errors = 1; 46090075Sobrien return; 46190075Sobrien 46290075Sobrien found: 46390075Sobrien value = XSTR (elem->data, 1); 464117395Skan p_false = xstrdup (value); 46590075Sobrien p_true = strchr (p_false, ','); 46690075Sobrien if (p_true == NULL || strchr (++p_true, ',') != NULL) 46790075Sobrien { 46890075Sobrien message_with_line (elem->lineno, 46990075Sobrien "attribute `predicable' is not a boolean"); 47090075Sobrien errors = 1; 471169689Skan if (p_false) 472169689Skan free (p_false); 47390075Sobrien return; 47490075Sobrien } 47590075Sobrien p_true[-1] = '\0'; 47690075Sobrien 47790075Sobrien predicable_true = p_true; 47890075Sobrien predicable_false = p_false; 47990075Sobrien 48090075Sobrien switch (GET_CODE (XEXP (elem->data, 2))) 48190075Sobrien { 48290075Sobrien case CONST_STRING: 48390075Sobrien value = XSTR (XEXP (elem->data, 2), 0); 48490075Sobrien break; 48590075Sobrien 48690075Sobrien case CONST: 48790075Sobrien message_with_line (elem->lineno, 48890075Sobrien "attribute `predicable' cannot be const"); 48990075Sobrien errors = 1; 490169689Skan if (p_false) 491169689Skan free (p_false); 49290075Sobrien return; 49390075Sobrien 49490075Sobrien default: 49590075Sobrien message_with_line (elem->lineno, 49690075Sobrien "attribute `predicable' must have a constant default"); 49790075Sobrien errors = 1; 498169689Skan if (p_false) 499169689Skan free (p_false); 50090075Sobrien return; 50190075Sobrien } 50290075Sobrien 50390075Sobrien if (strcmp (value, p_true) == 0) 50490075Sobrien predicable_default = 1; 50590075Sobrien else if (strcmp (value, p_false) == 0) 50690075Sobrien predicable_default = 0; 50790075Sobrien else 50890075Sobrien { 50990075Sobrien message_with_line (elem->lineno, 51090075Sobrien "unknown value `%s' for `predicable' attribute", 51190075Sobrien value); 51290075Sobrien errors = 1; 513169689Skan if (p_false) 514169689Skan free (p_false); 51590075Sobrien } 51690075Sobrien} 51790075Sobrien 51890075Sobrien/* Return the number of alternatives in constraint S. */ 51990075Sobrien 52090075Sobrienstatic int 521132718Skann_alternatives (const char *s) 52290075Sobrien{ 52390075Sobrien int n = 1; 52490075Sobrien 52590075Sobrien if (s) 52690075Sobrien while (*s) 52790075Sobrien n += (*s++ == ','); 52890075Sobrien 52990075Sobrien return n; 53090075Sobrien} 53190075Sobrien 53290075Sobrien/* Determine how many alternatives there are in INSN, and how many 53390075Sobrien operands. */ 53490075Sobrien 53590075Sobrienstatic void 536132718Skancollect_insn_data (rtx pattern, int *palt, int *pmax) 53790075Sobrien{ 53890075Sobrien const char *fmt; 53990075Sobrien enum rtx_code code; 54090075Sobrien int i, j, len; 54190075Sobrien 54290075Sobrien code = GET_CODE (pattern); 54390075Sobrien switch (code) 54490075Sobrien { 54590075Sobrien case MATCH_OPERAND: 54690075Sobrien i = n_alternatives (XSTR (pattern, 2)); 54790075Sobrien *palt = (i > *palt ? i : *palt); 548132718Skan /* Fall through. */ 54990075Sobrien 55090075Sobrien case MATCH_OPERATOR: 55190075Sobrien case MATCH_SCRATCH: 55290075Sobrien case MATCH_PARALLEL: 55390075Sobrien i = XINT (pattern, 0); 55490075Sobrien if (i > *pmax) 55590075Sobrien *pmax = i; 55690075Sobrien break; 55790075Sobrien 55890075Sobrien default: 55990075Sobrien break; 56090075Sobrien } 56190075Sobrien 56290075Sobrien fmt = GET_RTX_FORMAT (code); 56390075Sobrien len = GET_RTX_LENGTH (code); 56490075Sobrien for (i = 0; i < len; i++) 56590075Sobrien { 56690075Sobrien switch (fmt[i]) 56790075Sobrien { 56890075Sobrien case 'e': case 'u': 56990075Sobrien collect_insn_data (XEXP (pattern, i), palt, pmax); 57090075Sobrien break; 57190075Sobrien 57290075Sobrien case 'V': 57390075Sobrien if (XVEC (pattern, i) == NULL) 57490075Sobrien break; 575132718Skan /* Fall through. */ 57690075Sobrien case 'E': 57790075Sobrien for (j = XVECLEN (pattern, i) - 1; j >= 0; --j) 57890075Sobrien collect_insn_data (XVECEXP (pattern, i, j), palt, pmax); 57990075Sobrien break; 58090075Sobrien 58190075Sobrien case 'i': case 'w': case '0': case 's': case 'S': case 'T': 58290075Sobrien break; 58390075Sobrien 58490075Sobrien default: 585169689Skan gcc_unreachable (); 58690075Sobrien } 58790075Sobrien } 58890075Sobrien} 58990075Sobrien 59090075Sobrienstatic rtx 591132718Skanalter_predicate_for_insn (rtx pattern, int alt, int max_op, int lineno) 59290075Sobrien{ 59390075Sobrien const char *fmt; 59490075Sobrien enum rtx_code code; 59590075Sobrien int i, j, len; 59690075Sobrien 59790075Sobrien code = GET_CODE (pattern); 59890075Sobrien switch (code) 59990075Sobrien { 60090075Sobrien case MATCH_OPERAND: 60190075Sobrien { 60290075Sobrien const char *c = XSTR (pattern, 2); 60390075Sobrien 60490075Sobrien if (n_alternatives (c) != 1) 60590075Sobrien { 60690075Sobrien message_with_line (lineno, 60790075Sobrien "too many alternatives for operand %d", 60890075Sobrien XINT (pattern, 0)); 60990075Sobrien errors = 1; 61090075Sobrien return NULL; 61190075Sobrien } 61290075Sobrien 61390075Sobrien /* Replicate C as needed to fill out ALT alternatives. */ 61490075Sobrien if (c && *c && alt > 1) 61590075Sobrien { 61690075Sobrien size_t c_len = strlen (c); 61790075Sobrien size_t len = alt * (c_len + 1); 618169689Skan char *new_c = XNEWVEC(char, len); 61990075Sobrien 62090075Sobrien memcpy (new_c, c, c_len); 62190075Sobrien for (i = 1; i < alt; ++i) 62290075Sobrien { 62390075Sobrien new_c[i * (c_len + 1) - 1] = ','; 62490075Sobrien memcpy (&new_c[i * (c_len + 1)], c, c_len); 62590075Sobrien } 62690075Sobrien new_c[len - 1] = '\0'; 62790075Sobrien XSTR (pattern, 2) = new_c; 62890075Sobrien } 62990075Sobrien } 630132718Skan /* Fall through. */ 63190075Sobrien 63290075Sobrien case MATCH_OPERATOR: 63390075Sobrien case MATCH_SCRATCH: 63490075Sobrien case MATCH_PARALLEL: 63590075Sobrien XINT (pattern, 0) += max_op; 63690075Sobrien break; 63790075Sobrien 63890075Sobrien default: 63990075Sobrien break; 64090075Sobrien } 64190075Sobrien 64290075Sobrien fmt = GET_RTX_FORMAT (code); 64390075Sobrien len = GET_RTX_LENGTH (code); 64490075Sobrien for (i = 0; i < len; i++) 64590075Sobrien { 64690075Sobrien rtx r; 64790075Sobrien 64890075Sobrien switch (fmt[i]) 64990075Sobrien { 65090075Sobrien case 'e': case 'u': 65190075Sobrien r = alter_predicate_for_insn (XEXP (pattern, i), alt, 65290075Sobrien max_op, lineno); 65390075Sobrien if (r == NULL) 65490075Sobrien return r; 65590075Sobrien break; 65690075Sobrien 65790075Sobrien case 'E': 65890075Sobrien for (j = XVECLEN (pattern, i) - 1; j >= 0; --j) 65990075Sobrien { 66090075Sobrien r = alter_predicate_for_insn (XVECEXP (pattern, i, j), 66190075Sobrien alt, max_op, lineno); 66290075Sobrien if (r == NULL) 66390075Sobrien return r; 66490075Sobrien } 66590075Sobrien break; 66690075Sobrien 66790075Sobrien case 'i': case 'w': case '0': case 's': 66890075Sobrien break; 66990075Sobrien 67090075Sobrien default: 671169689Skan gcc_unreachable (); 67290075Sobrien } 67390075Sobrien } 67490075Sobrien 67590075Sobrien return pattern; 67690075Sobrien} 67790075Sobrien 67890075Sobrienstatic const char * 679132718Skanalter_test_for_insn (struct queue_elem *ce_elem, 680132718Skan struct queue_elem *insn_elem) 68190075Sobrien{ 682169689Skan return join_c_conditions (XSTR (ce_elem->data, 1), 683169689Skan XSTR (insn_elem->data, 2)); 68490075Sobrien} 68590075Sobrien 686169689Skan/* Adjust all of the operand numbers in SRC to match the shift they'll 68790075Sobrien get from an operand displacement of DISP. Return a pointer after the 68890075Sobrien adjusted string. */ 68990075Sobrien 69090075Sobrienstatic char * 691169689Skanshift_output_template (char *dest, const char *src, int disp) 69290075Sobrien{ 693169689Skan while (*src) 69490075Sobrien { 695169689Skan char c = *src++; 696169689Skan *dest++ = c; 69790075Sobrien if (c == '%') 69890075Sobrien { 699169689Skan c = *src++; 70090075Sobrien if (ISDIGIT ((unsigned char) c)) 70190075Sobrien c += disp; 70290075Sobrien else if (ISALPHA (c)) 70390075Sobrien { 704169689Skan *dest++ = c; 705169689Skan c = *src++ + disp; 70690075Sobrien } 707169689Skan *dest++ = c; 70890075Sobrien } 70990075Sobrien } 71090075Sobrien 711169689Skan return dest; 71290075Sobrien} 71390075Sobrien 71490075Sobrienstatic const char * 715132718Skanalter_output_for_insn (struct queue_elem *ce_elem, 716132718Skan struct queue_elem *insn_elem, 717132718Skan int alt, int max_op) 71890075Sobrien{ 71990075Sobrien const char *ce_out, *insn_out; 720169689Skan char *result, *p; 72190075Sobrien size_t len, ce_len, insn_len; 72290075Sobrien 72390075Sobrien /* ??? Could coordinate with genoutput to not duplicate code here. */ 72490075Sobrien 72590075Sobrien ce_out = XSTR (ce_elem->data, 2); 72690075Sobrien insn_out = XTMPL (insn_elem->data, 3); 72790075Sobrien if (!ce_out || *ce_out == '\0') 72890075Sobrien return insn_out; 72990075Sobrien 73090075Sobrien ce_len = strlen (ce_out); 73190075Sobrien insn_len = strlen (insn_out); 73290075Sobrien 73390075Sobrien if (*insn_out == '*') 73490075Sobrien /* You must take care of the predicate yourself. */ 73590075Sobrien return insn_out; 73690075Sobrien 73790075Sobrien if (*insn_out == '@') 73890075Sobrien { 73990075Sobrien len = (ce_len + 1) * alt + insn_len + 1; 740169689Skan p = result = XNEWVEC(char, len); 74190075Sobrien 74290075Sobrien do 74390075Sobrien { 74490075Sobrien do 74590075Sobrien *p++ = *insn_out++; 74690075Sobrien while (ISSPACE ((unsigned char) *insn_out)); 74790075Sobrien 74890075Sobrien if (*insn_out != '#') 74990075Sobrien { 75090075Sobrien p = shift_output_template (p, ce_out, max_op); 75190075Sobrien *p++ = ' '; 75290075Sobrien } 75390075Sobrien 75490075Sobrien do 75590075Sobrien *p++ = *insn_out++; 75690075Sobrien while (*insn_out && *insn_out != '\n'); 75790075Sobrien } 75890075Sobrien while (*insn_out); 75990075Sobrien *p = '\0'; 76090075Sobrien } 76190075Sobrien else 76290075Sobrien { 76390075Sobrien len = ce_len + 1 + insn_len + 1; 764169689Skan result = XNEWVEC (char, len); 76590075Sobrien 766169689Skan p = shift_output_template (result, ce_out, max_op); 76790075Sobrien *p++ = ' '; 76890075Sobrien memcpy (p, insn_out, insn_len + 1); 76990075Sobrien } 77090075Sobrien 771169689Skan return result; 77290075Sobrien} 77390075Sobrien 77490075Sobrien/* Replicate insns as appropriate for the given DEFINE_COND_EXEC. */ 77590075Sobrien 77690075Sobrienstatic void 777132718Skanprocess_one_cond_exec (struct queue_elem *ce_elem) 77890075Sobrien{ 77990075Sobrien struct queue_elem *insn_elem; 78090075Sobrien for (insn_elem = define_insn_queue; insn_elem ; insn_elem = insn_elem->next) 78190075Sobrien { 78290075Sobrien int alternatives, max_operand; 783169689Skan rtx pred, insn, pattern, split; 784169689Skan int i; 78590075Sobrien 78690075Sobrien if (! is_predicable (insn_elem)) 78790075Sobrien continue; 78890075Sobrien 78990075Sobrien alternatives = 1; 79090075Sobrien max_operand = -1; 79190075Sobrien collect_insn_data (insn_elem->data, &alternatives, &max_operand); 79290075Sobrien max_operand += 1; 79390075Sobrien 79490075Sobrien if (XVECLEN (ce_elem->data, 0) != 1) 79590075Sobrien { 79690075Sobrien message_with_line (ce_elem->lineno, 79790075Sobrien "too many patterns in predicate"); 79890075Sobrien errors = 1; 79990075Sobrien return; 80090075Sobrien } 80190075Sobrien 80290075Sobrien pred = copy_rtx (XVECEXP (ce_elem->data, 0, 0)); 80390075Sobrien pred = alter_predicate_for_insn (pred, alternatives, max_operand, 80490075Sobrien ce_elem->lineno); 80590075Sobrien if (pred == NULL) 80690075Sobrien return; 80790075Sobrien 80890075Sobrien /* Construct a new pattern for the new insn. */ 80990075Sobrien insn = copy_rtx (insn_elem->data); 81090075Sobrien XSTR (insn, 0) = ""; 81190075Sobrien pattern = rtx_alloc (COND_EXEC); 81290075Sobrien XEXP (pattern, 0) = pred; 81390075Sobrien if (XVECLEN (insn, 1) == 1) 81490075Sobrien { 81590075Sobrien XEXP (pattern, 1) = XVECEXP (insn, 1, 0); 81690075Sobrien XVECEXP (insn, 1, 0) = pattern; 81790075Sobrien PUT_NUM_ELEM (XVEC (insn, 1), 1); 81890075Sobrien } 81990075Sobrien else 82090075Sobrien { 82190075Sobrien XEXP (pattern, 1) = rtx_alloc (PARALLEL); 82290075Sobrien XVEC (XEXP (pattern, 1), 0) = XVEC (insn, 1); 82390075Sobrien XVEC (insn, 1) = rtvec_alloc (1); 82490075Sobrien XVECEXP (insn, 1, 0) = pattern; 82590075Sobrien } 82690075Sobrien 82790075Sobrien XSTR (insn, 2) = alter_test_for_insn (ce_elem, insn_elem); 82890075Sobrien XTMPL (insn, 3) = alter_output_for_insn (ce_elem, insn_elem, 82990075Sobrien alternatives, max_operand); 83090075Sobrien 83190075Sobrien /* ??? Set `predicable' to false. Not crucial since it's really 83290075Sobrien only used here, and we won't reprocess this new pattern. */ 83390075Sobrien 83490075Sobrien /* Put the new pattern on the `other' list so that it 83590075Sobrien (a) is not reprocessed by other define_cond_exec patterns 83690075Sobrien (b) appears after all normal define_insn patterns. 83790075Sobrien 83890075Sobrien ??? B is debatable. If one has normal insns that match 83990075Sobrien cond_exec patterns, they will be preferred over these 84090075Sobrien generated patterns. Whether this matters in practice, or if 84190075Sobrien it's a good thing, or whether we should thread these new 84290075Sobrien patterns into the define_insn chain just after their generator 84390075Sobrien is something we'll have to experiment with. */ 84490075Sobrien 845117395Skan queue_pattern (insn, &other_tail, insn_elem->filename, 846117395Skan insn_elem->lineno); 847169689Skan 848169689Skan if (!insn_elem->split) 849169689Skan continue; 850169689Skan 851169689Skan /* If the original insn came from a define_insn_and_split, 852169689Skan generate a new split to handle the predicated insn. */ 853169689Skan split = copy_rtx (insn_elem->split->data); 854169689Skan /* Predicate the pattern matched by the split. */ 855169689Skan pattern = rtx_alloc (COND_EXEC); 856169689Skan XEXP (pattern, 0) = pred; 857169689Skan if (XVECLEN (split, 0) == 1) 858169689Skan { 859169689Skan XEXP (pattern, 1) = XVECEXP (split, 0, 0); 860169689Skan XVECEXP (split, 0, 0) = pattern; 861169689Skan PUT_NUM_ELEM (XVEC (split, 0), 1); 862169689Skan } 863169689Skan else 864169689Skan { 865169689Skan XEXP (pattern, 1) = rtx_alloc (PARALLEL); 866169689Skan XVEC (XEXP (pattern, 1), 0) = XVEC (split, 0); 867169689Skan XVEC (split, 0) = rtvec_alloc (1); 868169689Skan XVECEXP (split, 0, 0) = pattern; 869169689Skan } 870169689Skan /* Predicate all of the insns generated by the split. */ 871169689Skan for (i = 0; i < XVECLEN (split, 2); i++) 872169689Skan { 873169689Skan pattern = rtx_alloc (COND_EXEC); 874169689Skan XEXP (pattern, 0) = pred; 875169689Skan XEXP (pattern, 1) = XVECEXP (split, 2, i); 876169689Skan XVECEXP (split, 2, i) = pattern; 877169689Skan } 878169689Skan /* Add the new split to the queue. */ 879169689Skan queue_pattern (split, &other_tail, read_rtx_filename, 880169689Skan insn_elem->split->lineno); 88190075Sobrien } 88290075Sobrien} 88390075Sobrien 88490075Sobrien/* If we have any DEFINE_COND_EXEC patterns, expand the DEFINE_INSN 88590075Sobrien patterns appropriately. */ 88690075Sobrien 88790075Sobrienstatic void 888132718Skanprocess_define_cond_exec (void) 88990075Sobrien{ 89090075Sobrien struct queue_elem *elem; 89190075Sobrien 89290075Sobrien identify_predicable_attribute (); 89390075Sobrien if (errors) 89490075Sobrien return; 89590075Sobrien 89690075Sobrien for (elem = define_cond_exec_queue; elem ; elem = elem->next) 89790075Sobrien process_one_cond_exec (elem); 89890075Sobrien} 89990075Sobrien 90090075Sobrienstatic char * 901132718Skansave_string (const char *s, int len) 90290075Sobrien{ 903169689Skan char *result = XNEWVEC (char, len + 1); 90490075Sobrien 90590075Sobrien memcpy (result, s, len); 90690075Sobrien result[len] = 0; 90790075Sobrien return result; 90890075Sobrien} 90990075Sobrien 91090075Sobrien 91190075Sobrien/* The entry point for initializing the reader. */ 91290075Sobrien 91390075Sobrienint 914169689Skaninit_md_reader_args_cb (int argc, char **argv, bool (*parse_opt)(const char *)) 91590075Sobrien{ 916169689Skan FILE *input_file; 917169689Skan int c, i, lineno; 918169689Skan char *lastsl; 919169689Skan rtx desc; 920169689Skan bool no_more_options; 921169689Skan bool already_read_stdin; 92290075Sobrien 923169689Skan /* Unlock the stdio streams. */ 924169689Skan unlock_std_streams (); 925169689Skan 926169689Skan /* First we loop over all the options. */ 92790075Sobrien for (i = 1; i < argc; i++) 92890075Sobrien { 92990075Sobrien if (argv[i][0] != '-') 930169689Skan continue; 931169689Skan 932169689Skan c = argv[i][1]; 933169689Skan switch (c) 93490075Sobrien { 935169689Skan case 'I': /* Add directory to path for includes. */ 936169689Skan { 937169689Skan struct file_name_list *dirtmp; 93890075Sobrien 939169689Skan dirtmp = XNEW (struct file_name_list); 940169689Skan dirtmp->next = 0; /* New one goes on the end */ 941169689Skan if (first_dir_md_include == 0) 942169689Skan first_dir_md_include = dirtmp; 943169689Skan else 944169689Skan last_dir_md_include->next = dirtmp; 945169689Skan last_dir_md_include = dirtmp; /* Tail follows the last one */ 946169689Skan if (argv[i][1] == 'I' && argv[i][2] != 0) 947169689Skan dirtmp->fname = argv[i] + 2; 948169689Skan else if (i + 1 == argc) 949169689Skan fatal ("directory name missing after -I option"); 950169689Skan else 951169689Skan dirtmp->fname = argv[++i]; 952169689Skan if (strlen (dirtmp->fname) > max_include_len) 953169689Skan max_include_len = strlen (dirtmp->fname); 954169689Skan } 955169689Skan break; 95690075Sobrien 957169689Skan case '\0': 958169689Skan /* An argument consisting of exactly one dash is a request to 959169689Skan read stdin. This will be handled in the second loop. */ 960169689Skan continue; 96190075Sobrien 962169689Skan case '-': 963169689Skan /* An argument consisting of just two dashes causes option 964169689Skan parsing to cease. */ 965169689Skan if (argv[i][2] == '\0') 966169689Skan goto stop_parsing_options; 96790075Sobrien 968169689Skan default: 969169689Skan /* The program may have provided a callback so it can 970169689Skan accept its own options. */ 971169689Skan if (parse_opt && parse_opt (argv[i])) 972169689Skan break; 97390075Sobrien 974169689Skan fatal ("invalid option `%s'", argv[i]); 975169689Skan } 97690075Sobrien } 97790075Sobrien 978169689Skan stop_parsing_options: 979117395Skan 980169689Skan /* Prepare to read input. */ 981169689Skan condition_table = htab_create (500, hash_c_test, cmp_c_test, NULL); 982169689Skan init_predicate_table (); 98390075Sobrien obstack_init (rtl_obstack); 98490075Sobrien errors = 0; 98590075Sobrien sequence_num = 0; 986169689Skan no_more_options = false; 987169689Skan already_read_stdin = false; 98890075Sobrien 989169689Skan 990169689Skan /* Now loop over all input files. */ 991169689Skan for (i = 1; i < argc; i++) 99290075Sobrien { 993169689Skan if (argv[i][0] == '-') 994169689Skan { 995169689Skan if (argv[i][1] == '\0') 996169689Skan { 997169689Skan /* Read stdin. */ 998169689Skan if (already_read_stdin) 999169689Skan fatal ("cannot read standard input twice"); 1000169689Skan 1001169689Skan base_dir = NULL; 1002169689Skan read_rtx_filename = in_fname = "<stdin>"; 1003169689Skan read_rtx_lineno = 1; 1004169689Skan input_file = stdin; 1005169689Skan already_read_stdin = true; 100690075Sobrien 1007169689Skan while (read_rtx (input_file, &desc, &lineno)) 1008169689Skan process_rtx (desc, lineno); 1009169689Skan fclose (input_file); 1010169689Skan continue; 1011169689Skan } 1012169689Skan else if (argv[i][1] == '-' && argv[i][2] == '\0') 1013169689Skan { 1014169689Skan /* No further arguments are to be treated as options. */ 1015169689Skan no_more_options = true; 1016169689Skan continue; 1017169689Skan } 1018169689Skan else if (!no_more_options) 1019169689Skan continue; 1020169689Skan } 102190075Sobrien 1022169689Skan /* If we get here we are looking at a non-option argument, i.e. 1023169689Skan a file to be processed. */ 1024169689Skan 1025169689Skan in_fname = argv[i]; 1026169689Skan lastsl = strrchr (in_fname, '/'); 1027169689Skan if (lastsl != NULL) 1028169689Skan base_dir = save_string (in_fname, lastsl - in_fname + 1 ); 1029169689Skan else 1030169689Skan base_dir = NULL; 1031169689Skan 1032169689Skan read_rtx_filename = in_fname; 1033169689Skan read_rtx_lineno = 1; 1034169689Skan input_file = fopen (in_fname, "r"); 1035169689Skan if (input_file == 0) 1036169689Skan { 1037169689Skan perror (in_fname); 1038169689Skan return FATAL_EXIT_CODE; 1039169689Skan } 1040169689Skan 1041169689Skan while (read_rtx (input_file, &desc, &lineno)) 1042169689Skan process_rtx (desc, lineno); 1043169689Skan fclose (input_file); 104490075Sobrien } 104590075Sobrien 1046169689Skan /* If we get to this point without having seen any files to process, 1047169689Skan read standard input now. */ 1048169689Skan if (!in_fname) 1049169689Skan { 1050169689Skan base_dir = NULL; 1051169689Skan read_rtx_filename = in_fname = "<stdin>"; 1052169689Skan read_rtx_lineno = 1; 1053169689Skan input_file = stdin; 1054169689Skan 1055169689Skan while (read_rtx (input_file, &desc, &lineno)) 1056169689Skan process_rtx (desc, lineno); 1057169689Skan fclose (input_file); 1058169689Skan } 1059169689Skan 106090075Sobrien /* Process define_cond_exec patterns. */ 106190075Sobrien if (define_cond_exec_queue != NULL) 106290075Sobrien process_define_cond_exec (); 106390075Sobrien 106490075Sobrien return errors ? FATAL_EXIT_CODE : SUCCESS_EXIT_CODE; 106590075Sobrien} 106690075Sobrien 1067169689Skan/* Programs that don't have their own options can use this entry point 1068169689Skan instead. */ 1069169689Skanint 1070169689Skaninit_md_reader_args (int argc, char **argv) 1071169689Skan{ 1072169689Skan return init_md_reader_args_cb (argc, argv, 0); 1073169689Skan} 1074169689Skan 107590075Sobrien/* The entry point for reading a single rtx from an md file. */ 107690075Sobrien 107790075Sobrienrtx 1078132718Skanread_md_rtx (int *lineno, int *seqnr) 107990075Sobrien{ 108090075Sobrien struct queue_elem **queue, *elem; 108190075Sobrien rtx desc; 108290075Sobrien 1083117395Skan discard: 1084117395Skan 108590075Sobrien /* Read all patterns from a given queue before moving on to the next. */ 108690075Sobrien if (define_attr_queue != NULL) 108790075Sobrien queue = &define_attr_queue; 1088169689Skan else if (define_pred_queue != NULL) 1089169689Skan queue = &define_pred_queue; 109090075Sobrien else if (define_insn_queue != NULL) 109190075Sobrien queue = &define_insn_queue; 109290075Sobrien else if (other_queue != NULL) 109390075Sobrien queue = &other_queue; 109490075Sobrien else 109590075Sobrien return NULL_RTX; 109690075Sobrien 109790075Sobrien elem = *queue; 109890075Sobrien *queue = elem->next; 109990075Sobrien desc = elem->data; 1100117395Skan read_rtx_filename = elem->filename; 110190075Sobrien *lineno = elem->lineno; 110290075Sobrien *seqnr = sequence_num; 110390075Sobrien 110490075Sobrien free (elem); 110590075Sobrien 1106117395Skan /* Discard insn patterns which we know can never match (because 1107117395Skan their C test is provably always false). If insn_elision is 1108117395Skan false, our caller needs to see all the patterns. Note that the 1109117395Skan elided patterns are never counted by the sequence numbering; it 1110117395Skan it is the caller's responsibility, when insn_elision is false, not 1111117395Skan to use elided pattern numbers for anything. */ 111290075Sobrien switch (GET_CODE (desc)) 111390075Sobrien { 111490075Sobrien case DEFINE_INSN: 111590075Sobrien case DEFINE_EXPAND: 1116117395Skan if (maybe_eval_c_test (XSTR (desc, 2)) != 0) 1117117395Skan sequence_num++; 1118117395Skan else if (insn_elision) 1119117395Skan goto discard; 1120169689Skan 1121169689Skan /* *seqnr is used here so the name table will match caller's 1122169689Skan idea of insn numbering, whether or not elision is active. */ 1123169689Skan record_insn_name (*seqnr, XSTR (desc, 0)); 1124117395Skan break; 1125117395Skan 112690075Sobrien case DEFINE_SPLIT: 112790075Sobrien case DEFINE_PEEPHOLE: 112890075Sobrien case DEFINE_PEEPHOLE2: 1129117395Skan if (maybe_eval_c_test (XSTR (desc, 1)) != 0) 1130117395Skan sequence_num++; 1131117395Skan else if (insn_elision) 1132117395Skan goto discard; 113390075Sobrien break; 113490075Sobrien 113590075Sobrien default: 113690075Sobrien break; 113790075Sobrien } 113890075Sobrien 113990075Sobrien return desc; 114090075Sobrien} 1141117395Skan 1142117395Skan/* Helper functions for insn elision. */ 1143117395Skan 1144117395Skan/* Compute a hash function of a c_test structure, which is keyed 1145117395Skan by its ->expr field. */ 1146117395Skanhashval_t 1147132718Skanhash_c_test (const void *x) 1148117395Skan{ 1149117395Skan const struct c_test *a = (const struct c_test *) x; 1150117395Skan const unsigned char *base, *s = (const unsigned char *) a->expr; 1151117395Skan hashval_t hash; 1152117395Skan unsigned char c; 1153117395Skan unsigned int len; 1154117395Skan 1155117395Skan base = s; 1156117395Skan hash = 0; 1157117395Skan 1158117395Skan while ((c = *s++) != '\0') 1159117395Skan { 1160117395Skan hash += c + (c << 17); 1161117395Skan hash ^= hash >> 2; 1162117395Skan } 1163117395Skan 1164117395Skan len = s - base; 1165117395Skan hash += len + (len << 17); 1166117395Skan hash ^= hash >> 2; 1167117395Skan 1168117395Skan return hash; 1169117395Skan} 1170117395Skan 1171117395Skan/* Compare two c_test expression structures. */ 1172117395Skanint 1173132718Skancmp_c_test (const void *x, const void *y) 1174117395Skan{ 1175117395Skan const struct c_test *a = (const struct c_test *) x; 1176117395Skan const struct c_test *b = (const struct c_test *) y; 1177117395Skan 1178117395Skan return !strcmp (a->expr, b->expr); 1179117395Skan} 1180117395Skan 1181117395Skan/* Given a string representing a C test expression, look it up in the 1182117395Skan condition_table and report whether or not its value is known 1183117395Skan at compile time. Returns a tristate: 1 for known true, 0 for 1184117395Skan known false, -1 for unknown. */ 1185117395Skanint 1186132718Skanmaybe_eval_c_test (const char *expr) 1187117395Skan{ 1188117395Skan const struct c_test *test; 1189117395Skan struct c_test dummy; 1190117395Skan 1191117395Skan if (expr[0] == 0) 1192117395Skan return 1; 1193117395Skan 1194117395Skan dummy.expr = expr; 1195169689Skan test = (const struct c_test *)htab_find (condition_table, &dummy); 1196117395Skan if (!test) 1197169689Skan return -1; 1198117395Skan return test->value; 1199117395Skan} 1200117395Skan 1201169689Skan/* Record the C test expression EXPR in the condition_table, with 1202169689Skan value VAL. Duplicates clobber previous entries. */ 1203169689Skan 1204169689Skanvoid 1205169689Skanadd_c_test (const char *expr, int value) 1206169689Skan{ 1207169689Skan struct c_test *test; 1208169689Skan 1209169689Skan if (expr[0] == 0) 1210169689Skan return; 1211169689Skan 1212169689Skan test = XNEW (struct c_test); 1213169689Skan test->expr = expr; 1214169689Skan test->value = value; 1215169689Skan 1216169689Skan *(htab_find_slot (condition_table, test, INSERT)) = test; 1217169689Skan} 1218169689Skan 1219169689Skan/* For every C test, call CALLBACK with two arguments: a pointer to 1220169689Skan the condition structure and INFO. Stops when CALLBACK returns zero. */ 1221169689Skanvoid 1222169689Skantraverse_c_tests (htab_trav callback, void *info) 1223169689Skan{ 1224169689Skan if (condition_table) 1225169689Skan htab_traverse (condition_table, callback, info); 1226169689Skan} 1227169689Skan 1228169689Skan 1229117395Skan/* Given a string, return the number of comma-separated elements in it. 1230117395Skan Return 0 for the null string. */ 1231117395Skanint 1232132718Skann_comma_elts (const char *s) 1233117395Skan{ 1234117395Skan int n; 1235117395Skan 1236117395Skan if (*s == '\0') 1237117395Skan return 0; 1238117395Skan 1239117395Skan for (n = 1; *s; s++) 1240117395Skan if (*s == ',') 1241117395Skan n++; 1242117395Skan 1243117395Skan return n; 1244117395Skan} 1245117395Skan 1246117395Skan/* Given a pointer to a (char *), return a pointer to the beginning of the 1247117395Skan next comma-separated element in the string. Advance the pointer given 1248117395Skan to the end of that element. Return NULL if at end of string. Caller 1249117395Skan is responsible for copying the string if necessary. White space between 1250117395Skan a comma and an element is ignored. */ 1251117395Skan 1252117395Skanconst char * 1253132718Skanscan_comma_elt (const char **pstr) 1254117395Skan{ 1255117395Skan const char *start; 1256117395Skan const char *p = *pstr; 1257117395Skan 1258117395Skan if (*p == ',') 1259117395Skan p++; 1260117395Skan while (ISSPACE(*p)) 1261117395Skan p++; 1262117395Skan 1263117395Skan if (*p == '\0') 1264117395Skan return NULL; 1265117395Skan 1266117395Skan start = p; 1267117395Skan 1268117395Skan while (*p != ',' && *p != '\0') 1269117395Skan p++; 1270117395Skan 1271117395Skan *pstr = p; 1272117395Skan return start; 1273117395Skan} 1274169689Skan 1275169689Skan/* Helper functions for define_predicate and define_special_predicate 1276169689Skan processing. Shared between genrecog.c and genpreds.c. */ 1277169689Skan 1278169689Skanstatic htab_t predicate_table; 1279169689Skanstruct pred_data *first_predicate; 1280169689Skanstatic struct pred_data **last_predicate = &first_predicate; 1281169689Skan 1282169689Skanstatic hashval_t 1283169689Skanhash_struct_pred_data (const void *ptr) 1284169689Skan{ 1285169689Skan return htab_hash_string (((const struct pred_data *)ptr)->name); 1286169689Skan} 1287169689Skan 1288169689Skanstatic int 1289169689Skaneq_struct_pred_data (const void *a, const void *b) 1290169689Skan{ 1291169689Skan return !strcmp (((const struct pred_data *)a)->name, 1292169689Skan ((const struct pred_data *)b)->name); 1293169689Skan} 1294169689Skan 1295169689Skanstruct pred_data * 1296169689Skanlookup_predicate (const char *name) 1297169689Skan{ 1298169689Skan struct pred_data key; 1299169689Skan key.name = name; 1300169689Skan return (struct pred_data *) htab_find (predicate_table, &key); 1301169689Skan} 1302169689Skan 1303169689Skanvoid 1304169689Skanadd_predicate (struct pred_data *pred) 1305169689Skan{ 1306169689Skan void **slot = htab_find_slot (predicate_table, pred, INSERT); 1307169689Skan if (*slot) 1308169689Skan { 1309169689Skan error ("duplicate predicate definition for '%s'", pred->name); 1310169689Skan return; 1311169689Skan } 1312169689Skan *slot = pred; 1313169689Skan *last_predicate = pred; 1314169689Skan last_predicate = &pred->next; 1315169689Skan} 1316169689Skan 1317169689Skan/* This array gives the initial content of the predicate table. It 1318169689Skan has entries for all predicates defined in recog.c. */ 1319169689Skan 1320169689Skanstruct std_pred_table 1321169689Skan{ 1322169689Skan const char *name; 1323169689Skan bool special; 1324169689Skan RTX_CODE codes[NUM_RTX_CODE]; 1325169689Skan}; 1326169689Skan 1327169689Skanstatic const struct std_pred_table std_preds[] = { 1328169689Skan {"general_operand", false, {CONST_INT, CONST_DOUBLE, CONST, SYMBOL_REF, 1329169689Skan LABEL_REF, SUBREG, REG, MEM }}, 1330169689Skan {"address_operand", true, {CONST_INT, CONST_DOUBLE, CONST, SYMBOL_REF, 1331169689Skan LABEL_REF, SUBREG, REG, MEM, 1332169689Skan PLUS, MINUS, MULT}}, 1333169689Skan {"register_operand", false, {SUBREG, REG}}, 1334169689Skan {"pmode_register_operand", true, {SUBREG, REG}}, 1335169689Skan {"scratch_operand", false, {SCRATCH, REG}}, 1336169689Skan {"immediate_operand", false, {CONST_INT, CONST_DOUBLE, CONST, SYMBOL_REF, 1337169689Skan LABEL_REF}}, 1338169689Skan {"const_int_operand", false, {CONST_INT}}, 1339169689Skan {"const_double_operand", false, {CONST_INT, CONST_DOUBLE}}, 1340169689Skan {"nonimmediate_operand", false, {SUBREG, REG, MEM}}, 1341169689Skan {"nonmemory_operand", false, {CONST_INT, CONST_DOUBLE, CONST, SYMBOL_REF, 1342169689Skan LABEL_REF, SUBREG, REG}}, 1343169689Skan {"push_operand", false, {MEM}}, 1344169689Skan {"pop_operand", false, {MEM}}, 1345169689Skan {"memory_operand", false, {SUBREG, MEM}}, 1346169689Skan {"indirect_operand", false, {SUBREG, MEM}}, 1347169689Skan {"comparison_operator", false, {EQ, NE, LE, LT, GE, GT, LEU, LTU, GEU, GTU, 1348169689Skan UNORDERED, ORDERED, UNEQ, UNGE, UNGT, UNLE, 1349169689Skan UNLT, LTGT}} 1350169689Skan}; 1351169689Skan#define NUM_KNOWN_STD_PREDS ARRAY_SIZE (std_preds) 1352169689Skan 1353169689Skan/* Initialize the table of predicate definitions, starting with 1354169689Skan the information we have on generic predicates. */ 1355169689Skan 1356169689Skanstatic void 1357169689Skaninit_predicate_table (void) 1358169689Skan{ 1359169689Skan size_t i, j; 1360169689Skan struct pred_data *pred; 1361169689Skan 1362169689Skan predicate_table = htab_create_alloc (37, hash_struct_pred_data, 1363169689Skan eq_struct_pred_data, 0, 1364169689Skan xcalloc, free); 1365169689Skan 1366169689Skan for (i = 0; i < NUM_KNOWN_STD_PREDS; i++) 1367169689Skan { 1368169689Skan pred = XCNEW (struct pred_data); 1369169689Skan pred->name = std_preds[i].name; 1370169689Skan pred->special = std_preds[i].special; 1371169689Skan 1372169689Skan for (j = 0; std_preds[i].codes[j] != 0; j++) 1373169689Skan { 1374169689Skan enum rtx_code code = std_preds[i].codes[j]; 1375169689Skan 1376169689Skan pred->codes[code] = true; 1377169689Skan if (GET_RTX_CLASS (code) != RTX_CONST_OBJ) 1378169689Skan pred->allows_non_const = true; 1379169689Skan if (code != REG 1380169689Skan && code != SUBREG 1381169689Skan && code != MEM 1382169689Skan && code != CONCAT 1383169689Skan && code != PARALLEL 1384169689Skan && code != STRICT_LOW_PART) 1385169689Skan pred->allows_non_lvalue = true; 1386169689Skan } 1387169689Skan if (j == 1) 1388169689Skan pred->singleton = std_preds[i].codes[0]; 1389169689Skan 1390169689Skan add_predicate (pred); 1391169689Skan } 1392169689Skan} 1393169689Skan 1394169689Skan/* These functions allow linkage with print-rtl.c. Also, some generators 1395169689Skan like to annotate their output with insn names. */ 1396169689Skan 1397169689Skan/* Holds an array of names indexed by insn_code_number. */ 1398169689Skanstatic char **insn_name_ptr = 0; 1399169689Skanstatic int insn_name_ptr_size = 0; 1400169689Skan 1401169689Skanconst char * 1402169689Skanget_insn_name (int code) 1403169689Skan{ 1404169689Skan if (code < insn_name_ptr_size) 1405169689Skan return insn_name_ptr[code]; 1406169689Skan else 1407169689Skan return NULL; 1408169689Skan} 1409169689Skan 1410169689Skanstatic void 1411169689Skanrecord_insn_name (int code, const char *name) 1412169689Skan{ 1413169689Skan static const char *last_real_name = "insn"; 1414169689Skan static int last_real_code = 0; 1415169689Skan char *new; 1416169689Skan 1417169689Skan if (insn_name_ptr_size <= code) 1418169689Skan { 1419169689Skan int new_size; 1420169689Skan new_size = (insn_name_ptr_size ? insn_name_ptr_size * 2 : 512); 1421169689Skan insn_name_ptr = xrealloc (insn_name_ptr, sizeof(char *) * new_size); 1422169689Skan memset (insn_name_ptr + insn_name_ptr_size, 0, 1423169689Skan sizeof(char *) * (new_size - insn_name_ptr_size)); 1424169689Skan insn_name_ptr_size = new_size; 1425169689Skan } 1426169689Skan 1427169689Skan if (!name || name[0] == '\0') 1428169689Skan { 1429169689Skan new = xmalloc (strlen (last_real_name) + 10); 1430169689Skan sprintf (new, "%s+%d", last_real_name, code - last_real_code); 1431169689Skan } 1432169689Skan else 1433169689Skan { 1434169689Skan last_real_name = new = xstrdup (name); 1435169689Skan last_real_code = code; 1436169689Skan } 1437169689Skan 1438169689Skan insn_name_ptr[code] = new; 1439169689Skan} 1440