118334Speter/* Generate code from machine description to extract operands from insn as rtl. 2169689Skan Copyright (C) 1987, 1991, 1992, 1993, 1997, 1998, 1999, 2000, 2003, 3169689Skan 2004, 2005 4132718Skan Free Software Foundation, Inc. 518334Speter 690075SobrienThis file is part of GCC. 718334Speter 890075SobrienGCC is free software; you can redistribute it and/or modify it under 990075Sobrienthe terms of the GNU General Public License as published by the Free 1090075SobrienSoftware Foundation; either version 2, or (at your option) any later 1190075Sobrienversion. 1218334Speter 1390075SobrienGCC is distributed in the hope that it will be useful, but WITHOUT ANY 1490075SobrienWARRANTY; without even the implied warranty of MERCHANTABILITY or 1590075SobrienFITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 1690075Sobrienfor more details. 1718334Speter 1818334SpeterYou should have received a copy of the GNU General Public License 1990075Sobrienalong with GCC; see the file COPYING. If not, write to the Free 20169689SkanSoftware Foundation, 51 Franklin Street, Fifth Floor, Boston, MA 21169689Skan02110-1301, USA. */ 2218334Speter 2318334Speter 24132718Skan#include "bconfig.h" 2550397Sobrien#include "system.h" 26132718Skan#include "coretypes.h" 27132718Skan#include "tm.h" 2818334Speter#include "rtl.h" 2990075Sobrien#include "errors.h" 3090075Sobrien#include "gensupport.h" 31169689Skan#include "vec.h" 32169689Skan#include "vecprim.h" 3318334Speter 3418334Speter/* This structure contains all the information needed to describe one 35132718Skan set of extractions methods. Each method may be used by more than 3618334Speter one pattern if the operands are in the same place. 3718334Speter 3818334Speter The string for each operand describes that path to the operand and 3918334Speter contains `0' through `9' when going into an expression and `a' through 4018334Speter `z' when going into a vector. We assume here that only the first operand 4118334Speter of an rtl expression is a vector. genrecog.c makes the same assumption 4218334Speter (and uses the same representation) and it is currently true. */ 4318334Speter 44169689Skantypedef char *locstr; 45169689Skan 4618334Speterstruct extraction 4718334Speter{ 48169689Skan unsigned int op_count; 49169689Skan unsigned int dup_count; 50169689Skan locstr *oplocs; 51169689Skan locstr *duplocs; 52169689Skan int *dupnums; 5318334Speter struct code_ptr *insns; 5418334Speter struct extraction *next; 5518334Speter}; 5618334Speter 57169689Skan/* Holds a single insn code that uses an extraction method. */ 5818334Speterstruct code_ptr 5918334Speter{ 6018334Speter int insn_code; 6118334Speter struct code_ptr *next; 6218334Speter}; 6318334Speter 64169689Skan/* All extractions needed for this machine description. */ 6518334Speterstatic struct extraction *extractions; 6618334Speter 67169689Skan/* All insn codes for old-style peepholes. */ 68169689Skanstatic struct code_ptr *peepholes; 6990075Sobrien 70169689Skan/* This structure is used by gen_insn and walk_rtx to accumulate the 71169689Skan data that will be used to produce an extractions structure. */ 7218334Speter 73169689SkanDEF_VEC_P(locstr); 74169689SkanDEF_VEC_ALLOC_P(locstr,heap); 7518334Speter 76169689Skanstruct accum_extract 77169689Skan{ 78169689Skan VEC(locstr,heap) *oplocs; 79169689Skan VEC(locstr,heap) *duplocs; 80169689Skan VEC(int,heap) *dupnums; 81169689Skan VEC(char,heap) *pathstr; 82169689Skan}; 8318334Speter 84169689Skan/* Forward declarations. */ 85169689Skanstatic void walk_rtx (rtx, struct accum_extract *); 8618334Speter 8718334Speterstatic void 88169689Skangen_insn (rtx insn, int insn_code_number) 8918334Speter{ 9090075Sobrien int i; 91169689Skan unsigned int op_count, dup_count, j; 9290075Sobrien struct extraction *p; 9390075Sobrien struct code_ptr *link; 94169689Skan struct accum_extract acc; 9518334Speter 96169689Skan acc.oplocs = VEC_alloc (locstr,heap, 10); 97169689Skan acc.duplocs = VEC_alloc (locstr,heap, 10); 98169689Skan acc.dupnums = VEC_alloc (int,heap, 10); 99169689Skan acc.pathstr = VEC_alloc (char,heap, 20); 10018334Speter 10118334Speter /* Walk the insn's pattern, remembering at all times the path 10218334Speter down to the walking point. */ 10318334Speter 10418334Speter if (XVECLEN (insn, 1) == 1) 105169689Skan walk_rtx (XVECEXP (insn, 1, 0), &acc); 10618334Speter else 10718334Speter for (i = XVECLEN (insn, 1) - 1; i >= 0; i--) 10818334Speter { 109169689Skan VEC_safe_push (char,heap, acc.pathstr, 'a' + i); 110169689Skan walk_rtx (XVECEXP (insn, 1, i), &acc); 111169689Skan VEC_pop (char, acc.pathstr); 11218334Speter } 11318334Speter 114169689Skan link = XNEW (struct code_ptr); 11518334Speter link->insn_code = insn_code_number; 11618334Speter 11750397Sobrien /* See if we find something that already had this extraction method. */ 11818334Speter 119169689Skan op_count = VEC_length (locstr, acc.oplocs); 120169689Skan dup_count = VEC_length (locstr, acc.duplocs); 121169689Skan gcc_assert (dup_count == VEC_length (int, acc.dupnums)); 122169689Skan 12318334Speter for (p = extractions; p; p = p->next) 12418334Speter { 12518334Speter if (p->op_count != op_count || p->dup_count != dup_count) 12618334Speter continue; 12718334Speter 128169689Skan for (j = 0; j < op_count; j++) 129169689Skan { 130169689Skan char *a = p->oplocs[j]; 131169689Skan char *b = VEC_index (locstr, acc.oplocs, j); 132169689Skan if (a != b && (!a || !b || strcmp (a, b))) 133169689Skan break; 134169689Skan } 13518334Speter 136169689Skan if (j != op_count) 13718334Speter continue; 13818334Speter 139169689Skan for (j = 0; j < dup_count; j++) 140169689Skan if (p->dupnums[j] != VEC_index (int, acc.dupnums, j) 141169689Skan || strcmp (p->duplocs[j], VEC_index (locstr, acc.duplocs, j))) 14218334Speter break; 14318334Speter 144169689Skan if (j != dup_count) 14518334Speter continue; 14618334Speter 14718334Speter /* This extraction is the same as ours. Just link us in. */ 14818334Speter link->next = p->insns; 14918334Speter p->insns = link; 150169689Skan goto done; 15118334Speter } 15218334Speter 153169689Skan /* Otherwise, make a new extraction method. We stash the arrays 154169689Skan after the extraction structure in memory. */ 15518334Speter 156169689Skan p = xmalloc (sizeof (struct extraction) 157169689Skan + op_count*sizeof (char *) 158169689Skan + dup_count*sizeof (char *) 159169689Skan + dup_count*sizeof (int)); 16018334Speter p->op_count = op_count; 16118334Speter p->dup_count = dup_count; 16218334Speter p->next = extractions; 16318334Speter extractions = p; 16418334Speter p->insns = link; 16518334Speter link->next = 0; 16618334Speter 167169689Skan p->oplocs = (char **)((char *)p + sizeof (struct extraction)); 168169689Skan p->duplocs = p->oplocs + op_count; 169169689Skan p->dupnums = (int *)(p->duplocs + dup_count); 17018334Speter 171169689Skan memcpy(p->oplocs, VEC_address(locstr,acc.oplocs), op_count*sizeof(locstr)); 172169689Skan memcpy(p->duplocs, VEC_address(locstr,acc.duplocs), dup_count*sizeof(locstr)); 173169689Skan memcpy(p->dupnums, VEC_address(int, acc.dupnums), dup_count*sizeof(int)); 174169689Skan 175169689Skan done: 176169689Skan VEC_free (locstr,heap, acc.oplocs); 177169689Skan VEC_free (locstr,heap, acc.duplocs); 178169689Skan VEC_free (int,heap, acc.dupnums); 179169689Skan VEC_free (char,heap, acc.pathstr); 18018334Speter} 18118334Speter 182169689Skan/* Helper subroutine of walk_rtx: given a VEC(locstr), an index, and a 183169689Skan string, insert the string at the index, which should either already 184169689Skan exist and be NULL, or not yet exist within the vector. In the latter 185169689Skan case the vector is enlarged as appropriate. */ 18618334Speterstatic void 187169689SkanVEC_safe_set_locstr (VEC(locstr,heap) **vp, unsigned int ix, char *str) 18818334Speter{ 189169689Skan if (ix < VEC_length (locstr, *vp)) 190169689Skan { 191169689Skan gcc_assert (VEC_index (locstr, *vp, ix) == 0); 192169689Skan VEC_replace (locstr, *vp, ix, str); 193169689Skan } 194169689Skan else 195169689Skan { 196169689Skan while (ix > VEC_length (locstr, *vp)) 197169689Skan VEC_safe_push (locstr, heap, *vp, 0); 198169689Skan VEC_safe_push (locstr, heap, *vp, str); 199169689Skan } 200169689Skan} 201169689Skan 202169689Skan/* Another helper subroutine of walk_rtx: given a VEC(char), convert it 203169689Skan to a NUL-terminated string in malloc memory. */ 204169689Skanstatic char * 205169689SkanVEC_char_to_string (VEC(char,heap) *v) 206169689Skan{ 207169689Skan size_t n = VEC_length (char, v); 208169689Skan char *s = XNEWVEC (char, n + 1); 209169689Skan memcpy (s, VEC_address (char, v), n); 210169689Skan s[n] = '\0'; 211169689Skan return s; 212169689Skan} 213169689Skan 214169689Skanstatic void 215169689Skanwalk_rtx (rtx x, struct accum_extract *acc) 216169689Skan{ 21790075Sobrien RTX_CODE code; 218169689Skan int i, len, base; 21990075Sobrien const char *fmt; 22018334Speter 22118334Speter if (x == 0) 22218334Speter return; 22318334Speter 22418334Speter code = GET_CODE (x); 22518334Speter switch (code) 22618334Speter { 22718334Speter case PC: 22818334Speter case CC0: 22918334Speter case CONST_INT: 23018334Speter case SYMBOL_REF: 23118334Speter return; 23218334Speter 23318334Speter case MATCH_OPERAND: 23418334Speter case MATCH_SCRATCH: 235169689Skan VEC_safe_set_locstr (&acc->oplocs, XINT (x, 0), 236169689Skan VEC_char_to_string (acc->pathstr)); 23718334Speter break; 23818334Speter 239169689Skan case MATCH_OPERATOR: 240169689Skan case MATCH_PARALLEL: 241169689Skan VEC_safe_set_locstr (&acc->oplocs, XINT (x, 0), 242169689Skan VEC_char_to_string (acc->pathstr)); 243169689Skan 244169689Skan base = (code == MATCH_OPERATOR ? '0' : 'a'); 245169689Skan for (i = XVECLEN (x, 2) - 1; i >= 0; i--) 246169689Skan { 247169689Skan VEC_safe_push (char,heap, acc->pathstr, base + i); 248169689Skan walk_rtx (XVECEXP (x, 2, i), acc); 249169689Skan VEC_pop (char, acc->pathstr); 250169689Skan } 251169689Skan return; 252169689Skan 25318334Speter case MATCH_DUP: 25496263Sobrien case MATCH_PAR_DUP: 25518334Speter case MATCH_OP_DUP: 256169689Skan VEC_safe_push (locstr,heap, acc->duplocs, 257169689Skan VEC_char_to_string (acc->pathstr)); 258169689Skan VEC_safe_push (int,heap, acc->dupnums, XINT (x, 0)); 259132718Skan 260169689Skan if (code == MATCH_DUP) 261169689Skan break; 262132718Skan 263169689Skan base = (code == MATCH_OP_DUP ? '0' : 'a'); 26418334Speter for (i = XVECLEN (x, 1) - 1; i >= 0; i--) 26518334Speter { 266169689Skan VEC_safe_push (char,heap, acc->pathstr, base + i); 267169689Skan walk_rtx (XVECEXP (x, 1, i), acc); 268169689Skan VEC_pop (char, acc->pathstr); 26918334Speter } 27018334Speter return; 271132718Skan 27250397Sobrien default: 27350397Sobrien break; 27418334Speter } 27518334Speter 27618334Speter fmt = GET_RTX_FORMAT (code); 27718334Speter len = GET_RTX_LENGTH (code); 27818334Speter for (i = 0; i < len; i++) 27918334Speter { 28018334Speter if (fmt[i] == 'e' || fmt[i] == 'u') 28118334Speter { 282169689Skan VEC_safe_push (char,heap, acc->pathstr, '0' + i); 283169689Skan walk_rtx (XEXP (x, i), acc); 284169689Skan VEC_pop (char, acc->pathstr); 28518334Speter } 28618334Speter else if (fmt[i] == 'E') 28718334Speter { 28818334Speter int j; 28918334Speter for (j = XVECLEN (x, i) - 1; j >= 0; j--) 29018334Speter { 291169689Skan VEC_safe_push (char,heap, acc->pathstr, 'a' + j); 292169689Skan walk_rtx (XVECEXP (x, i, j), acc); 293169689Skan VEC_pop (char, acc->pathstr); 29418334Speter } 29518334Speter } 29618334Speter } 29718334Speter} 29818334Speter 29918334Speter/* Given a PATH, representing a path down the instruction's 30018334Speter pattern from the root to a certain point, output code to 30118334Speter evaluate to the rtx at that point. */ 30218334Speter 30318334Speterstatic void 304132718Skanprint_path (const char *path) 30518334Speter{ 30690075Sobrien int len = strlen (path); 30790075Sobrien int i; 30818334Speter 30950397Sobrien if (len == 0) 31050397Sobrien { 31150397Sobrien /* Don't emit "pat", since we may try to take the address of it, 31250397Sobrien which isn't what is intended. */ 313169689Skan fputs ("PATTERN (insn)", stdout); 31450397Sobrien return; 31550397Sobrien } 31650397Sobrien 31718334Speter /* We first write out the operations (XEXP or XVECEXP) in reverse 318169689Skan order, then write "pat", then the indices in forward order. */ 31918334Speter 320132718Skan for (i = len - 1; i >= 0 ; i--) 32118334Speter { 322169689Skan if (ISLOWER (path[i])) 323169689Skan fputs ("XVECEXP (", stdout); 324169689Skan else if (ISDIGIT (path[i])) 325169689Skan fputs ("XEXP (", stdout); 32618334Speter else 327169689Skan gcc_unreachable (); 32818334Speter } 329132718Skan 330169689Skan fputs ("pat", stdout); 33118334Speter 33218334Speter for (i = 0; i < len; i++) 33318334Speter { 334169689Skan if (ISLOWER (path[i])) 33518334Speter printf (", 0, %d)", path[i] - 'a'); 33690075Sobrien else if (ISDIGIT(path[i])) 33718334Speter printf (", %d)", path[i] - '0'); 33818334Speter else 339169689Skan gcc_unreachable (); 34018334Speter } 34118334Speter} 34218334Speter 343169689Skanstatic void 344169689Skanprint_header (void) 345169689Skan{ 346169689Skan /* N.B. Code below avoids putting squiggle braces in column 1 inside 347169689Skan a string, because this confuses some editors' syntax highlighting 348169689Skan engines. */ 34918334Speter 350169689Skan puts ("\ 351169689Skan/* Generated automatically by the program `genextract'\n\ 352169689Skan from the machine description file `md'. */\n\ 353169689Skan\n\ 354169689Skan#include \"config.h\"\n\ 355169689Skan#include \"system.h\"\n\ 356169689Skan#include \"coretypes.h\"\n\ 357169689Skan#include \"tm.h\"\n\ 358169689Skan#include \"rtl.h\"\n\ 359169689Skan#include \"insn-config.h\"\n\ 360169689Skan#include \"recog.h\"\n\ 361169689Skan#include \"toplev.h\"\n\ 362169689Skan\n\ 363169689Skan/* This variable is used as the \"location\" of any missing operand\n\ 364169689Skan whose numbers are skipped by a given pattern. */\n\ 365169689Skanstatic rtx junk ATTRIBUTE_UNUSED;\n"); 366169689Skan 367169689Skan puts ("\ 368169689Skanvoid\n\ 369169689Skaninsn_extract (rtx insn)\n{\n\ 370169689Skan rtx *ro = recog_data.operand;\n\ 371169689Skan rtx **ro_loc = recog_data.operand_loc;\n\ 372169689Skan rtx pat = PATTERN (insn);\n\ 373169689Skan int i ATTRIBUTE_UNUSED; /* only for peepholes */\n\ 374169689Skan\n\ 375169689Skan#ifdef ENABLE_CHECKING\n\ 376169689Skan memset (ro, 0xab, sizeof (*ro) * MAX_RECOG_OPERANDS);\n\ 377169689Skan memset (ro_loc, 0xab, sizeof (*ro_loc) * MAX_RECOG_OPERANDS);\n\ 378169689Skan#endif\n"); 379169689Skan 380169689Skan puts ("\ 381169689Skan switch (INSN_CODE (insn))\n\ 382169689Skan {\n\ 383169689Skan default:\n\ 384169689Skan /* Control reaches here if insn_extract has been called with an\n\ 385169689Skan unrecognizable insn (code -1), or an insn whose INSN_CODE\n\ 386169689Skan corresponds to a DEFINE_EXPAND in the machine description;\n\ 387169689Skan either way, a bug. */\n\ 388169689Skan if (INSN_CODE (insn) < 0)\n\ 389169689Skan fatal_insn (\"unrecognizable insn:\", insn);\n\ 390169689Skan else\n\ 391169689Skan fatal_insn (\"insn with invalid code number:\", insn);\n"); 392169689Skan} 393169689Skan 39418334Speterint 395132718Skanmain (int argc, char **argv) 39618334Speter{ 39718334Speter rtx desc; 398169689Skan unsigned int i; 39918334Speter struct extraction *p; 40018334Speter struct code_ptr *link; 40190075Sobrien const char *name; 402169689Skan int insn_code_number; 403169689Skan int line_no; 40418334Speter 40590075Sobrien progname = "genextract"; 40618334Speter 40790075Sobrien if (init_md_reader_args (argc, argv) != SUCCESS_EXIT_CODE) 40890075Sobrien return (FATAL_EXIT_CODE); 40918334Speter 41018334Speter /* Read the machine description. */ 41118334Speter 412169689Skan while ((desc = read_md_rtx (&line_no, &insn_code_number)) != NULL) 41318334Speter { 41490075Sobrien if (GET_CODE (desc) == DEFINE_INSN) 415169689Skan gen_insn (desc, insn_code_number); 41618334Speter 41718334Speter else if (GET_CODE (desc) == DEFINE_PEEPHOLE) 41818334Speter { 419169689Skan struct code_ptr *link = XNEW (struct code_ptr); 42018334Speter 42118334Speter link->insn_code = insn_code_number; 42218334Speter link->next = peepholes; 42318334Speter peepholes = link; 42418334Speter } 42518334Speter } 42618334Speter 427169689Skan print_header (); 428169689Skan 42918334Speter /* Write out code to handle peepholes and the insn_codes that it should 43018334Speter be called for. */ 43118334Speter if (peepholes) 43218334Speter { 43318334Speter for (link = peepholes; link; link = link->next) 43418334Speter printf (" case %d:\n", link->insn_code); 43518334Speter 43618334Speter /* The vector in the insn says how many operands it has. 43718334Speter And all it contains are operands. In fact, the vector was 43890075Sobrien created just for the sake of this function. We need to set the 43990075Sobrien location of the operands for sake of simplifications after 44090075Sobrien extraction, like eliminating subregs. */ 441169689Skan puts (" for (i = XVECLEN (pat, 0) - 1; i >= 0; i--)\n" 442169689Skan " ro[i] = *(ro_loc[i] = &XVECEXP (pat, 0, i));\n" 443169689Skan " break;\n"); 44418334Speter } 44518334Speter 44618334Speter /* Write out all the ways to extract insn operands. */ 44718334Speter for (p = extractions; p; p = p->next) 44818334Speter { 44918334Speter for (link = p->insns; link; link = link->next) 45090075Sobrien { 45190075Sobrien i = link->insn_code; 45290075Sobrien name = get_insn_name (i); 45390075Sobrien if (name) 45490075Sobrien printf (" case %d: /* %s */\n", i, name); 45590075Sobrien else 45690075Sobrien printf (" case %d:\n", i); 45790075Sobrien } 458132718Skan 45918334Speter for (i = 0; i < p->op_count; i++) 46018334Speter { 46118334Speter if (p->oplocs[i] == 0) 46218334Speter { 46318334Speter printf (" ro[%d] = const0_rtx;\n", i); 46418334Speter printf (" ro_loc[%d] = &junk;\n", i); 46518334Speter } 46618334Speter else 46718334Speter { 46818334Speter printf (" ro[%d] = *(ro_loc[%d] = &", i, i); 46918334Speter print_path (p->oplocs[i]); 470169689Skan puts (");"); 47118334Speter } 47218334Speter } 47318334Speter 47418334Speter for (i = 0; i < p->dup_count; i++) 47518334Speter { 47690075Sobrien printf (" recog_data.dup_loc[%d] = &", i); 47718334Speter print_path (p->duplocs[i]); 478169689Skan puts (";"); 47990075Sobrien printf (" recog_data.dup_num[%d] = %d;\n", i, p->dupnums[i]); 48018334Speter } 48118334Speter 482169689Skan puts (" break;\n"); 48318334Speter } 48418334Speter 485169689Skan puts (" }\n}"); 48618334Speter fflush (stdout); 48790075Sobrien return (ferror (stdout) != 0 ? FATAL_EXIT_CODE : SUCCESS_EXIT_CODE); 48818334Speter} 489