123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492 |
- /* Generate code from machine description to extract operands from insn as rtl.
- Copyright (C) 1987-2015 Free Software Foundation, Inc.
- This file is part of GCC.
- GCC is free software; you can redistribute it and/or modify it under
- the terms of the GNU General Public License as published by the Free
- Software Foundation; either version 3, or (at your option) any later
- version.
- GCC is distributed in the hope that it will be useful, but WITHOUT ANY
- WARRANTY; without even the implied warranty of MERCHANTABILITY or
- FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
- for more details.
- You should have received a copy of the GNU General Public License
- along with GCC; see the file COPYING3. If not see
- <http://www.gnu.org/licenses/>. */
- #include "bconfig.h"
- #include "system.h"
- #include "coretypes.h"
- #include "tm.h"
- #include "rtl.h"
- #include "errors.h"
- #include "read-md.h"
- #include "gensupport.h"
- #include "vec.h"
- /* This structure contains all the information needed to describe one
- set of extractions methods. Each method may be used by more than
- one pattern if the operands are in the same place.
- The string for each operand describes that path to the operand and
- contains `0' through `9' when going into an expression and `a' through
- `z' when going into a vector. We assume here that only the first operand
- of an rtl expression is a vector. genrecog.c makes the same assumption
- (and uses the same representation) and it is currently true. */
- typedef char *locstr;
- struct extraction
- {
- unsigned int op_count;
- unsigned int dup_count;
- locstr *oplocs;
- locstr *duplocs;
- int *dupnums;
- struct code_ptr *insns;
- struct extraction *next;
- };
- /* Holds a single insn code that uses an extraction method. */
- struct code_ptr
- {
- int insn_code;
- struct code_ptr *next;
- };
- /* All extractions needed for this machine description. */
- static struct extraction *extractions;
- /* All insn codes for old-style peepholes. */
- static struct code_ptr *peepholes;
- /* This structure is used by gen_insn and walk_rtx to accumulate the
- data that will be used to produce an extractions structure. */
- struct accum_extract
- {
- vec<locstr> oplocs;
- vec<locstr> duplocs;
- vec<int> dupnums;
- vec<char> pathstr;
- };
- int line_no;
- /* Forward declarations. */
- static void walk_rtx (rtx, struct accum_extract *);
- static void
- gen_insn (rtx insn, int insn_code_number)
- {
- int i;
- unsigned int op_count, dup_count, j;
- struct extraction *p;
- struct code_ptr *link;
- struct accum_extract acc;
- acc.oplocs.create (10);
- acc.duplocs.create (10);
- acc.dupnums.create (10);
- acc.pathstr.create (20);
- /* Walk the insn's pattern, remembering at all times the path
- down to the walking point. */
- if (XVECLEN (insn, 1) == 1)
- walk_rtx (XVECEXP (insn, 1, 0), &acc);
- else
- for (i = XVECLEN (insn, 1) - 1; i >= 0; i--)
- {
- acc.pathstr.safe_push ('a' + i);
- walk_rtx (XVECEXP (insn, 1, i), &acc);
- acc.pathstr.pop ();
- }
- link = XNEW (struct code_ptr);
- link->insn_code = insn_code_number;
- /* See if we find something that already had this extraction method. */
- op_count = acc.oplocs.length ();
- dup_count = acc.duplocs.length ();
- gcc_assert (dup_count == acc.dupnums.length ());
- for (p = extractions; p; p = p->next)
- {
- if (p->op_count != op_count || p->dup_count != dup_count)
- continue;
- for (j = 0; j < op_count; j++)
- {
- char *a = p->oplocs[j];
- char *b = acc.oplocs[j];
- if (a != b && (!a || !b || strcmp (a, b)))
- break;
- }
- if (j != op_count)
- continue;
- for (j = 0; j < dup_count; j++)
- if (p->dupnums[j] != acc.dupnums[j]
- || strcmp (p->duplocs[j], acc.duplocs[j]))
- break;
- if (j != dup_count)
- continue;
- /* This extraction is the same as ours. Just link us in. */
- link->next = p->insns;
- p->insns = link;
- goto done;
- }
- /* Otherwise, make a new extraction method. We stash the arrays
- after the extraction structure in memory. */
- p = XNEWVAR (struct extraction, sizeof (struct extraction)
- + op_count*sizeof (char *)
- + dup_count*sizeof (char *)
- + dup_count*sizeof (int));
- p->op_count = op_count;
- p->dup_count = dup_count;
- p->next = extractions;
- extractions = p;
- p->insns = link;
- link->next = 0;
- p->oplocs = (char **)((char *)p + sizeof (struct extraction));
- p->duplocs = p->oplocs + op_count;
- p->dupnums = (int *)(p->duplocs + dup_count);
- memcpy (p->oplocs, acc.oplocs.address (), op_count * sizeof (locstr));
- memcpy (p->duplocs, acc.duplocs.address (), dup_count * sizeof (locstr));
- memcpy (p->dupnums, acc.dupnums.address (), dup_count * sizeof (int));
- done:
- acc.oplocs.release ();
- acc.duplocs.release ();
- acc.dupnums.release ();
- acc.pathstr.release ();
- }
- /* Helper subroutine of walk_rtx: given a vec<locstr>, an index, and a
- string, insert the string at the index, which should either already
- exist and be NULL, or not yet exist within the vector. In the latter
- case the vector is enlarged as appropriate. */
- static void
- VEC_safe_set_locstr (vec<locstr> *vp, unsigned int ix, char *str)
- {
- if (ix < (*vp).length ())
- {
- if ((*vp)[ix])
- {
- message_with_line (line_no, "repeated operand number %d", ix);
- have_error = 1;
- }
- else
- (*vp)[ix] = str;
- }
- else
- {
- while (ix > (*vp).length ())
- vp->safe_push (NULL);
- vp->safe_push (str);
- }
- }
- /* Another helper subroutine of walk_rtx: given a vec<char>, convert it
- to a NUL-terminated string in malloc memory. */
- static char *
- VEC_char_to_string (vec<char> v)
- {
- size_t n = v.length ();
- char *s = XNEWVEC (char, n + 1);
- memcpy (s, v.address (), n);
- s[n] = '\0';
- return s;
- }
- static void
- walk_rtx (rtx x, struct accum_extract *acc)
- {
- RTX_CODE code;
- int i, len, base;
- const char *fmt;
- if (x == 0)
- return;
- code = GET_CODE (x);
- switch (code)
- {
- case PC:
- case CC0:
- case CONST_INT:
- case SYMBOL_REF:
- return;
- case MATCH_OPERAND:
- case MATCH_SCRATCH:
- VEC_safe_set_locstr (&acc->oplocs, XINT (x, 0),
- VEC_char_to_string (acc->pathstr));
- break;
- case MATCH_OPERATOR:
- case MATCH_PARALLEL:
- VEC_safe_set_locstr (&acc->oplocs, XINT (x, 0),
- VEC_char_to_string (acc->pathstr));
- base = (code == MATCH_OPERATOR ? '0' : 'a');
- for (i = XVECLEN (x, 2) - 1; i >= 0; i--)
- {
- acc->pathstr.safe_push (base + i);
- walk_rtx (XVECEXP (x, 2, i), acc);
- acc->pathstr.pop ();
- }
- return;
- case MATCH_DUP:
- case MATCH_PAR_DUP:
- case MATCH_OP_DUP:
- acc->duplocs.safe_push (VEC_char_to_string (acc->pathstr));
- acc->dupnums.safe_push (XINT (x, 0));
- if (code == MATCH_DUP)
- break;
- base = (code == MATCH_OP_DUP ? '0' : 'a');
- for (i = XVECLEN (x, 1) - 1; i >= 0; i--)
- {
- acc->pathstr.safe_push (base + i);
- walk_rtx (XVECEXP (x, 1, i), acc);
- acc->pathstr.pop ();
- }
- return;
- default:
- break;
- }
- fmt = GET_RTX_FORMAT (code);
- len = GET_RTX_LENGTH (code);
- for (i = 0; i < len; i++)
- {
- if (fmt[i] == 'e' || fmt[i] == 'u')
- {
- acc->pathstr.safe_push ('0' + i);
- walk_rtx (XEXP (x, i), acc);
- acc->pathstr.pop ();
- }
- else if (fmt[i] == 'E')
- {
- int j;
- for (j = XVECLEN (x, i) - 1; j >= 0; j--)
- {
- acc->pathstr.safe_push ('a' + j);
- walk_rtx (XVECEXP (x, i, j), acc);
- acc->pathstr.pop ();
- }
- }
- }
- }
- /* Given a PATH, representing a path down the instruction's
- pattern from the root to a certain point, output code to
- evaluate to the rtx at that point. */
- static void
- print_path (const char *path)
- {
- int len = strlen (path);
- int i;
- if (len == 0)
- {
- /* Don't emit "pat", since we may try to take the address of it,
- which isn't what is intended. */
- fputs ("PATTERN (insn)", stdout);
- return;
- }
- /* We first write out the operations (XEXP or XVECEXP) in reverse
- order, then write "pat", then the indices in forward order. */
- for (i = len - 1; i >= 0 ; i--)
- {
- if (ISLOWER (path[i]))
- fputs ("XVECEXP (", stdout);
- else if (ISDIGIT (path[i]))
- fputs ("XEXP (", stdout);
- else
- gcc_unreachable ();
- }
- fputs ("pat", stdout);
- for (i = 0; i < len; i++)
- {
- if (ISLOWER (path[i]))
- printf (", 0, %d)", path[i] - 'a');
- else if (ISDIGIT (path[i]))
- printf (", %d)", path[i] - '0');
- else
- gcc_unreachable ();
- }
- }
- static void
- print_header (void)
- {
- /* N.B. Code below avoids putting squiggle braces in column 1 inside
- a string, because this confuses some editors' syntax highlighting
- engines. */
- puts ("\
- /* Generated automatically by the program `genextract'\n\
- from the machine description file `md'. */\n\
- \n\
- #include \"config.h\"\n\
- #include \"system.h\"\n\
- #include \"coretypes.h\"\n\
- #include \"tm.h\"\n\
- #include \"rtl.h\"\n\
- #include \"insn-config.h\"\n\
- #include \"recog.h\"\n\
- #include \"diagnostic-core.h\"\n\
- \n\
- /* This variable is used as the \"location\" of any missing operand\n\
- whose numbers are skipped by a given pattern. */\n\
- static rtx junk ATTRIBUTE_UNUSED;\n");
- puts ("\
- void\n\
- insn_extract (rtx_insn *insn)\n{\n\
- rtx *ro = recog_data.operand;\n\
- rtx **ro_loc = recog_data.operand_loc;\n\
- rtx pat = PATTERN (insn);\n\
- int i ATTRIBUTE_UNUSED; /* only for peepholes */\n\
- \n\
- #ifdef ENABLE_CHECKING\n\
- memset (ro, 0xab, sizeof (*ro) * MAX_RECOG_OPERANDS);\n\
- memset (ro_loc, 0xab, sizeof (*ro_loc) * MAX_RECOG_OPERANDS);\n\
- #endif\n");
- puts ("\
- switch (INSN_CODE (insn))\n\
- {\n\
- default:\n\
- /* Control reaches here if insn_extract has been called with an\n\
- unrecognizable insn (code -1), or an insn whose INSN_CODE\n\
- corresponds to a DEFINE_EXPAND in the machine description;\n\
- either way, a bug. */\n\
- if (INSN_CODE (insn) < 0)\n\
- fatal_insn (\"unrecognizable insn:\", insn);\n\
- else\n\
- fatal_insn (\"insn with invalid code number:\", insn);\n");
- }
- int
- main (int argc, char **argv)
- {
- rtx desc;
- unsigned int i;
- struct extraction *p;
- struct code_ptr *link;
- const char *name;
- int insn_code_number;
- progname = "genextract";
- if (!init_rtx_reader_args (argc, argv))
- return (FATAL_EXIT_CODE);
- /* Read the machine description. */
- while ((desc = read_md_rtx (&line_no, &insn_code_number)) != NULL)
- {
- if (GET_CODE (desc) == DEFINE_INSN)
- gen_insn (desc, insn_code_number);
- else if (GET_CODE (desc) == DEFINE_PEEPHOLE)
- {
- struct code_ptr *link = XNEW (struct code_ptr);
- link->insn_code = insn_code_number;
- link->next = peepholes;
- peepholes = link;
- }
- }
- if (have_error)
- return FATAL_EXIT_CODE;
- print_header ();
- /* Write out code to handle peepholes and the insn_codes that it should
- be called for. */
- if (peepholes)
- {
- for (link = peepholes; link; link = link->next)
- printf (" case %d:\n", link->insn_code);
- /* The vector in the insn says how many operands it has.
- And all it contains are operands. In fact, the vector was
- created just for the sake of this function. We need to set the
- location of the operands for sake of simplifications after
- extraction, like eliminating subregs. */
- puts (" for (i = XVECLEN (pat, 0) - 1; i >= 0; i--)\n"
- " ro[i] = *(ro_loc[i] = &XVECEXP (pat, 0, i));\n"
- " break;\n");
- }
- /* Write out all the ways to extract insn operands. */
- for (p = extractions; p; p = p->next)
- {
- for (link = p->insns; link; link = link->next)
- {
- i = link->insn_code;
- name = get_insn_name (i);
- if (name)
- printf (" case %d: /* %s */\n", i, name);
- else
- printf (" case %d:\n", i);
- }
- for (i = 0; i < p->op_count; i++)
- {
- if (p->oplocs[i] == 0)
- {
- printf (" ro[%d] = const0_rtx;\n", i);
- printf (" ro_loc[%d] = &junk;\n", i);
- }
- else
- {
- printf (" ro[%d] = *(ro_loc[%d] = &", i, i);
- print_path (p->oplocs[i]);
- puts (");");
- }
- }
- for (i = 0; i < p->dup_count; i++)
- {
- printf (" recog_data.dup_loc[%d] = &", i);
- print_path (p->duplocs[i]);
- puts (";");
- printf (" recog_data.dup_num[%d] = %d;\n", i, p->dupnums[i]);
- }
- puts (" break;\n");
- }
- puts (" }\n}");
- fflush (stdout);
- return (ferror (stdout) != 0 ? FATAL_EXIT_CODE : SUCCESS_EXIT_CODE);
- }
|