]>
Commit | Line | Data |
---|---|---|
3439974c | 1 | /* Generate code from machine description to extract operands from insn as rtl. |
fbd26352 | 2 | Copyright (C) 1987-2019 Free Software Foundation, Inc. |
3439974c | 3 | |
f12b58b3 | 4 | This file is part of GCC. |
3439974c | 5 | |
f12b58b3 | 6 | GCC is free software; you can redistribute it and/or modify it under |
7 | the terms of the GNU General Public License as published by the Free | |
8c4c00c1 | 8 | Software Foundation; either version 3, or (at your option) any later |
f12b58b3 | 9 | version. |
3439974c | 10 | |
f12b58b3 | 11 | GCC is distributed in the hope that it will be useful, but WITHOUT ANY |
12 | WARRANTY; without even the implied warranty of MERCHANTABILITY or | |
13 | FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License | |
14 | for more details. | |
3439974c | 15 | |
16 | You should have received a copy of the GNU General Public License | |
8c4c00c1 | 17 | along with GCC; see the file COPYING3. If not see |
18 | <http://www.gnu.org/licenses/>. */ | |
3439974c | 19 | |
20 | ||
805e22b2 | 21 | #include "bconfig.h" |
5ce88198 | 22 | #include "system.h" |
805e22b2 | 23 | #include "coretypes.h" |
24 | #include "tm.h" | |
3439974c | 25 | #include "rtl.h" |
04b58880 | 26 | #include "errors.h" |
960ebfe7 | 27 | #include "read-md.h" |
c5ddd6b5 | 28 | #include "gensupport.h" |
3439974c | 29 | |
bd70aa79 | 30 | /* This structure contains all the information needed to describe one |
1a97be37 | 31 | set of extractions methods. Each method may be used by more than |
bd70aa79 | 32 | one pattern if the operands are in the same place. |
33 | ||
34 | The string for each operand describes that path to the operand and | |
35 | contains `0' through `9' when going into an expression and `a' through | |
24e6a0cd | 36 | `z' then 'A' through to 'Z' when going into a vector. We assume here that |
37 | only the first operand of an rtl expression is a vector. genrecog.c makes | |
38 | the same assumption (and uses the same representation) and it is currently | |
39 | true. */ | |
bd70aa79 | 40 | |
0a1039d0 | 41 | typedef char *locstr; |
42 | ||
bd70aa79 | 43 | struct extraction |
44 | { | |
0a1039d0 | 45 | unsigned int op_count; |
46 | unsigned int dup_count; | |
47 | locstr *oplocs; | |
48 | locstr *duplocs; | |
49 | int *dupnums; | |
bd70aa79 | 50 | struct code_ptr *insns; |
51 | struct extraction *next; | |
52 | }; | |
53 | ||
0a1039d0 | 54 | /* Holds a single insn code that uses an extraction method. */ |
bd70aa79 | 55 | struct code_ptr |
56 | { | |
57 | int insn_code; | |
58 | struct code_ptr *next; | |
59 | }; | |
60 | ||
0a1039d0 | 61 | /* All extractions needed for this machine description. */ |
bd70aa79 | 62 | static struct extraction *extractions; |
63 | ||
0a1039d0 | 64 | /* All insn codes for old-style peepholes. */ |
65 | static struct code_ptr *peepholes; | |
3439974c | 66 | |
0a1039d0 | 67 | /* This structure is used by gen_insn and walk_rtx to accumulate the |
68 | data that will be used to produce an extractions structure. */ | |
3439974c | 69 | |
3439974c | 70 | |
0a1039d0 | 71 | struct accum_extract |
72 | { | |
c97cc128 | 73 | accum_extract () : oplocs (10), duplocs (10), dupnums (10), pathstr (20) {} |
74 | ||
75 | auto_vec<locstr> oplocs; | |
76 | auto_vec<locstr> duplocs; | |
77 | auto_vec<int> dupnums; | |
78 | auto_vec<char> pathstr; | |
0a1039d0 | 79 | }; |
3439974c | 80 | |
0a1039d0 | 81 | /* Forward declarations. */ |
c04601c1 | 82 | static void walk_rtx (md_rtx_info *, rtx, struct accum_extract *); |
04b58880 | 83 | |
24e6a0cd | 84 | #define UPPER_OFFSET ('A' - ('z' - 'a' + 1)) |
85 | ||
86 | /* Convert integer OPERAND into a character - either into [a-zA-Z] for vector | |
87 | operands or [0-9] for integer operands - and push onto the end of the path | |
88 | in ACC. */ | |
89 | static void | |
90 | push_pathstr_operand (int operand, bool is_vector, | |
91 | struct accum_extract *acc) | |
92 | { | |
93 | if (is_vector && 'a' + operand > 'z') | |
94 | acc->pathstr.safe_push (operand + UPPER_OFFSET); | |
95 | else if (is_vector) | |
96 | acc->pathstr.safe_push (operand + 'a'); | |
97 | else | |
98 | acc->pathstr.safe_push (operand + '0'); | |
99 | } | |
100 | ||
3439974c | 101 | static void |
c04601c1 | 102 | gen_insn (md_rtx_info *info) |
3439974c | 103 | { |
19cb6b50 | 104 | int i; |
0a1039d0 | 105 | unsigned int op_count, dup_count, j; |
19cb6b50 | 106 | struct extraction *p; |
107 | struct code_ptr *link; | |
0a1039d0 | 108 | struct accum_extract acc; |
3439974c | 109 | |
3439974c | 110 | /* Walk the insn's pattern, remembering at all times the path |
111 | down to the walking point. */ | |
112 | ||
c04601c1 | 113 | rtx insn = info->def; |
3439974c | 114 | if (XVECLEN (insn, 1) == 1) |
c04601c1 | 115 | walk_rtx (info, XVECEXP (insn, 1, 0), &acc); |
3439974c | 116 | else |
117 | for (i = XVECLEN (insn, 1) - 1; i >= 0; i--) | |
118 | { | |
24e6a0cd | 119 | push_pathstr_operand (i, true, &acc); |
c04601c1 | 120 | walk_rtx (info, XVECEXP (insn, 1, i), &acc); |
f1f41a6c | 121 | acc.pathstr.pop (); |
3439974c | 122 | } |
3439974c | 123 | |
0a1039d0 | 124 | link = XNEW (struct code_ptr); |
c04601c1 | 125 | link->insn_code = info->index; |
bd70aa79 | 126 | |
a92771b8 | 127 | /* See if we find something that already had this extraction method. */ |
bd70aa79 | 128 | |
f1f41a6c | 129 | op_count = acc.oplocs.length (); |
130 | dup_count = acc.duplocs.length (); | |
131 | gcc_assert (dup_count == acc.dupnums.length ()); | |
0a1039d0 | 132 | |
bd70aa79 | 133 | for (p = extractions; p; p = p->next) |
3439974c | 134 | { |
bd70aa79 | 135 | if (p->op_count != op_count || p->dup_count != dup_count) |
136 | continue; | |
137 | ||
0a1039d0 | 138 | for (j = 0; j < op_count; j++) |
139 | { | |
140 | char *a = p->oplocs[j]; | |
f1f41a6c | 141 | char *b = acc.oplocs[j]; |
0a1039d0 | 142 | if (a != b && (!a || !b || strcmp (a, b))) |
143 | break; | |
144 | } | |
bd70aa79 | 145 | |
0a1039d0 | 146 | if (j != op_count) |
bd70aa79 | 147 | continue; |
148 | ||
0a1039d0 | 149 | for (j = 0; j < dup_count; j++) |
f1f41a6c | 150 | if (p->dupnums[j] != acc.dupnums[j] |
151 | || strcmp (p->duplocs[j], acc.duplocs[j])) | |
bd70aa79 | 152 | break; |
153 | ||
0a1039d0 | 154 | if (j != dup_count) |
bd70aa79 | 155 | continue; |
156 | ||
157 | /* This extraction is the same as ours. Just link us in. */ | |
158 | link->next = p->insns; | |
159 | p->insns = link; | |
c97cc128 | 160 | return; |
3439974c | 161 | } |
162 | ||
0a1039d0 | 163 | /* Otherwise, make a new extraction method. We stash the arrays |
164 | after the extraction structure in memory. */ | |
3439974c | 165 | |
65b198c2 | 166 | p = XNEWVAR (struct extraction, sizeof (struct extraction) |
0a1039d0 | 167 | + op_count*sizeof (char *) |
168 | + dup_count*sizeof (char *) | |
169 | + dup_count*sizeof (int)); | |
bd70aa79 | 170 | p->op_count = op_count; |
171 | p->dup_count = dup_count; | |
172 | p->next = extractions; | |
173 | extractions = p; | |
174 | p->insns = link; | |
175 | link->next = 0; | |
176 | ||
0a1039d0 | 177 | p->oplocs = (char **)((char *)p + sizeof (struct extraction)); |
178 | p->duplocs = p->oplocs + op_count; | |
179 | p->dupnums = (int *)(p->duplocs + dup_count); | |
bd70aa79 | 180 | |
9af5ce0c | 181 | memcpy (p->oplocs, acc.oplocs.address (), op_count * sizeof (locstr)); |
182 | memcpy (p->duplocs, acc.duplocs.address (), dup_count * sizeof (locstr)); | |
183 | memcpy (p->dupnums, acc.dupnums.address (), dup_count * sizeof (int)); | |
bd70aa79 | 184 | } |
185 | \f | |
f1f41a6c | 186 | /* Helper subroutine of walk_rtx: given a vec<locstr>, an index, and a |
0a1039d0 | 187 | string, insert the string at the index, which should either already |
188 | exist and be NULL, or not yet exist within the vector. In the latter | |
c04601c1 | 189 | case the vector is enlarged as appropriate. INFO describes the |
190 | containing define_* expression. */ | |
3439974c | 191 | static void |
c04601c1 | 192 | VEC_safe_set_locstr (md_rtx_info *info, vec<locstr> *vp, |
193 | unsigned int ix, char *str) | |
0a1039d0 | 194 | { |
f1f41a6c | 195 | if (ix < (*vp).length ()) |
0a1039d0 | 196 | { |
f1f41a6c | 197 | if ((*vp)[ix]) |
cbb955b0 | 198 | { |
c04601c1 | 199 | message_at (info->loc, "repeated operand number %d", ix); |
cbb955b0 | 200 | have_error = 1; |
201 | } | |
202 | else | |
f1f41a6c | 203 | (*vp)[ix] = str; |
0a1039d0 | 204 | } |
205 | else | |
206 | { | |
f1f41a6c | 207 | while (ix > (*vp).length ()) |
208 | vp->safe_push (NULL); | |
209 | vp->safe_push (str); | |
0a1039d0 | 210 | } |
211 | } | |
212 | ||
f1f41a6c | 213 | /* Another helper subroutine of walk_rtx: given a vec<char>, convert it |
0a1039d0 | 214 | to a NUL-terminated string in malloc memory. */ |
215 | static char * | |
f1f41a6c | 216 | VEC_char_to_string (vec<char> v) |
0a1039d0 | 217 | { |
f1f41a6c | 218 | size_t n = v.length (); |
4c36ffe6 | 219 | char *s = XNEWVEC (char, n + 1); |
f1f41a6c | 220 | memcpy (s, v.address (), n); |
0a1039d0 | 221 | s[n] = '\0'; |
222 | return s; | |
223 | } | |
224 | ||
225 | static void | |
c04601c1 | 226 | walk_rtx (md_rtx_info *info, rtx x, struct accum_extract *acc) |
3439974c | 227 | { |
19cb6b50 | 228 | RTX_CODE code; |
24e6a0cd | 229 | int i, len; |
19cb6b50 | 230 | const char *fmt; |
3439974c | 231 | |
232 | if (x == 0) | |
233 | return; | |
234 | ||
235 | code = GET_CODE (x); | |
3439974c | 236 | switch (code) |
237 | { | |
238 | case PC: | |
239 | case CC0: | |
240 | case CONST_INT: | |
241 | case SYMBOL_REF: | |
242 | return; | |
243 | ||
244 | case MATCH_OPERAND: | |
245 | case MATCH_SCRATCH: | |
c04601c1 | 246 | VEC_safe_set_locstr (info, &acc->oplocs, XINT (x, 0), |
0a1039d0 | 247 | VEC_char_to_string (acc->pathstr)); |
3439974c | 248 | break; |
249 | ||
3439974c | 250 | case MATCH_OPERATOR: |
0a1039d0 | 251 | case MATCH_PARALLEL: |
c04601c1 | 252 | VEC_safe_set_locstr (info, &acc->oplocs, XINT (x, 0), |
0a1039d0 | 253 | VEC_char_to_string (acc->pathstr)); |
bd70aa79 | 254 | |
3439974c | 255 | for (i = XVECLEN (x, 2) - 1; i >= 0; i--) |
256 | { | |
24e6a0cd | 257 | push_pathstr_operand (i, code != MATCH_OPERATOR, acc); |
c04601c1 | 258 | walk_rtx (info, XVECEXP (x, 2, i), acc); |
f1f41a6c | 259 | acc->pathstr.pop (); |
0a1039d0 | 260 | } |
3439974c | 261 | return; |
262 | ||
0a1039d0 | 263 | case MATCH_DUP: |
264 | case MATCH_PAR_DUP: | |
265 | case MATCH_OP_DUP: | |
f1f41a6c | 266 | acc->duplocs.safe_push (VEC_char_to_string (acc->pathstr)); |
267 | acc->dupnums.safe_push (XINT (x, 0)); | |
bd70aa79 | 268 | |
0a1039d0 | 269 | if (code == MATCH_DUP) |
270 | break; | |
3439974c | 271 | |
0a1039d0 | 272 | for (i = XVECLEN (x, 1) - 1; i >= 0; i--) |
273 | { | |
24e6a0cd | 274 | push_pathstr_operand (i, code != MATCH_OP_DUP, acc); |
c04601c1 | 275 | walk_rtx (info, XVECEXP (x, 1, i), acc); |
f1f41a6c | 276 | acc->pathstr.pop (); |
0a1039d0 | 277 | } |
3439974c | 278 | return; |
3ef9782d | 279 | |
280 | default: | |
281 | break; | |
3439974c | 282 | } |
283 | ||
3439974c | 284 | fmt = GET_RTX_FORMAT (code); |
285 | len = GET_RTX_LENGTH (code); | |
286 | for (i = 0; i < len; i++) | |
287 | { | |
3439974c | 288 | if (fmt[i] == 'e' || fmt[i] == 'u') |
289 | { | |
24e6a0cd | 290 | push_pathstr_operand (i, false, acc); |
c04601c1 | 291 | walk_rtx (info, XEXP (x, i), acc); |
f1f41a6c | 292 | acc->pathstr.pop (); |
3439974c | 293 | } |
294 | else if (fmt[i] == 'E') | |
295 | { | |
296 | int j; | |
297 | for (j = XVECLEN (x, i) - 1; j >= 0; j--) | |
298 | { | |
24e6a0cd | 299 | push_pathstr_operand (j, true, acc); |
c04601c1 | 300 | walk_rtx (info, XVECEXP (x, i, j), acc); |
f1f41a6c | 301 | acc->pathstr.pop (); |
3439974c | 302 | } |
303 | } | |
304 | } | |
305 | } | |
306 | ||
307 | /* Given a PATH, representing a path down the instruction's | |
308 | pattern from the root to a certain point, output code to | |
309 | evaluate to the rtx at that point. */ | |
310 | ||
311 | static void | |
1a97be37 | 312 | print_path (const char *path) |
3439974c | 313 | { |
19cb6b50 | 314 | int len = strlen (path); |
315 | int i; | |
bd70aa79 | 316 | |
c37c80b7 | 317 | if (len == 0) |
318 | { | |
319 | /* Don't emit "pat", since we may try to take the address of it, | |
320 | which isn't what is intended. */ | |
0a1039d0 | 321 | fputs ("PATTERN (insn)", stdout); |
c37c80b7 | 322 | return; |
323 | } | |
324 | ||
bd70aa79 | 325 | /* We first write out the operations (XEXP or XVECEXP) in reverse |
0a1039d0 | 326 | order, then write "pat", then the indices in forward order. */ |
bd70aa79 | 327 | |
ea0041f4 | 328 | for (i = len - 1; i >= 0 ; i--) |
3439974c | 329 | { |
24e6a0cd | 330 | if (ISLOWER (path[i]) || ISUPPER (path[i])) |
0a1039d0 | 331 | fputs ("XVECEXP (", stdout); |
332 | else if (ISDIGIT (path[i])) | |
333 | fputs ("XEXP (", stdout); | |
bd70aa79 | 334 | else |
e0a4c0c2 | 335 | gcc_unreachable (); |
3439974c | 336 | } |
1a97be37 | 337 | |
0a1039d0 | 338 | fputs ("pat", stdout); |
bd70aa79 | 339 | |
340 | for (i = 0; i < len; i++) | |
3439974c | 341 | { |
24e6a0cd | 342 | if (ISUPPER (path[i])) |
343 | printf (", 0, %d)", path[i] - UPPER_OFFSET); | |
344 | else if (ISLOWER (path[i])) | |
bd70aa79 | 345 | printf (", 0, %d)", path[i] - 'a'); |
9af5ce0c | 346 | else if (ISDIGIT (path[i])) |
bd70aa79 | 347 | printf (", %d)", path[i] - '0'); |
348 | else | |
e0a4c0c2 | 349 | gcc_unreachable (); |
3439974c | 350 | } |
351 | } | |
352 | \f | |
0a1039d0 | 353 | static void |
354 | print_header (void) | |
355 | { | |
356 | /* N.B. Code below avoids putting squiggle braces in column 1 inside | |
357 | a string, because this confuses some editors' syntax highlighting | |
358 | engines. */ | |
359 | ||
360 | puts ("\ | |
361 | /* Generated automatically by the program `genextract'\n\ | |
362 | from the machine description file `md'. */\n\ | |
363 | \n\ | |
785790dc | 364 | #define IN_TARGET_CODE 1\n\ |
0a1039d0 | 365 | #include \"config.h\"\n\ |
366 | #include \"system.h\"\n\ | |
367 | #include \"coretypes.h\"\n\ | |
368 | #include \"tm.h\"\n\ | |
369 | #include \"rtl.h\"\n\ | |
370 | #include \"insn-config.h\"\n\ | |
371 | #include \"recog.h\"\n\ | |
c18cb818 | 372 | #include \"diagnostic-core.h\"\n\ |
0a1039d0 | 373 | \n\ |
374 | /* This variable is used as the \"location\" of any missing operand\n\ | |
375 | whose numbers are skipped by a given pattern. */\n\ | |
376 | static rtx junk ATTRIBUTE_UNUSED;\n"); | |
377 | ||
378 | puts ("\ | |
379 | void\n\ | |
87004871 | 380 | insn_extract (rtx_insn *insn)\n{\n\ |
0a1039d0 | 381 | rtx *ro = recog_data.operand;\n\ |
382 | rtx **ro_loc = recog_data.operand_loc;\n\ | |
383 | rtx pat = PATTERN (insn);\n\ | |
384 | int i ATTRIBUTE_UNUSED; /* only for peepholes */\n\ | |
385 | \n\ | |
e138bdcb | 386 | if (flag_checking)\n\ |
387 | {\n\ | |
388 | memset (ro, 0xab, sizeof (*ro) * MAX_RECOG_OPERANDS);\n\ | |
389 | memset (ro_loc, 0xab, sizeof (*ro_loc) * MAX_RECOG_OPERANDS);\n\ | |
390 | }\n"); | |
0a1039d0 | 391 | |
392 | puts ("\ | |
393 | switch (INSN_CODE (insn))\n\ | |
394 | {\n\ | |
395 | default:\n\ | |
396 | /* Control reaches here if insn_extract has been called with an\n\ | |
397 | unrecognizable insn (code -1), or an insn whose INSN_CODE\n\ | |
398 | corresponds to a DEFINE_EXPAND in the machine description;\n\ | |
399 | either way, a bug. */\n\ | |
400 | if (INSN_CODE (insn) < 0)\n\ | |
401 | fatal_insn (\"unrecognizable insn:\", insn);\n\ | |
402 | else\n\ | |
403 | fatal_insn (\"insn with invalid code number:\", insn);\n"); | |
404 | } | |
947491b7 | 405 | |
3439974c | 406 | int |
16570c04 | 407 | main (int argc, const char **argv) |
3439974c | 408 | { |
0a1039d0 | 409 | unsigned int i; |
bd70aa79 | 410 | struct extraction *p; |
411 | struct code_ptr *link; | |
cd53d889 | 412 | const char *name; |
3439974c | 413 | |
04b58880 | 414 | progname = "genextract"; |
3439974c | 415 | |
77ba95d0 | 416 | if (!init_rtx_reader_args (argc, argv)) |
c5ddd6b5 | 417 | return (FATAL_EXIT_CODE); |
3439974c | 418 | |
3439974c | 419 | /* Read the machine description. */ |
420 | ||
c04601c1 | 421 | md_rtx_info info; |
422 | while (read_md_rtx (&info)) | |
423 | switch (GET_CODE (info.def)) | |
424 | { | |
425 | case DEFINE_INSN: | |
426 | gen_insn (&info); | |
427 | break; | |
bd70aa79 | 428 | |
c04601c1 | 429 | case DEFINE_PEEPHOLE: |
3439974c | 430 | { |
4c36ffe6 | 431 | struct code_ptr *link = XNEW (struct code_ptr); |
bd70aa79 | 432 | |
c04601c1 | 433 | link->insn_code = info.index; |
bd70aa79 | 434 | link->next = peepholes; |
435 | peepholes = link; | |
3439974c | 436 | } |
c04601c1 | 437 | break; |
438 | ||
439 | default: | |
440 | break; | |
bd70aa79 | 441 | } |
3439974c | 442 | |
cbb955b0 | 443 | if (have_error) |
444 | return FATAL_EXIT_CODE; | |
445 | ||
0a1039d0 | 446 | print_header (); |
447 | ||
bd70aa79 | 448 | /* Write out code to handle peepholes and the insn_codes that it should |
449 | be called for. */ | |
450 | if (peepholes) | |
3439974c | 451 | { |
bd70aa79 | 452 | for (link = peepholes; link; link = link->next) |
453 | printf (" case %d:\n", link->insn_code); | |
454 | ||
3439974c | 455 | /* The vector in the insn says how many operands it has. |
456 | And all it contains are operands. In fact, the vector was | |
edfcb0b1 | 457 | created just for the sake of this function. We need to set the |
458 | location of the operands for sake of simplifications after | |
459 | extraction, like eliminating subregs. */ | |
0a1039d0 | 460 | puts (" for (i = XVECLEN (pat, 0) - 1; i >= 0; i--)\n" |
461 | " ro[i] = *(ro_loc[i] = &XVECEXP (pat, 0, i));\n" | |
462 | " break;\n"); | |
bd70aa79 | 463 | } |
464 | ||
465 | /* Write out all the ways to extract insn operands. */ | |
466 | for (p = extractions; p; p = p->next) | |
467 | { | |
468 | for (link = p->insns; link; link = link->next) | |
cd53d889 | 469 | { |
470 | i = link->insn_code; | |
471 | name = get_insn_name (i); | |
472 | if (name) | |
473 | printf (" case %d: /* %s */\n", i, name); | |
474 | else | |
475 | printf (" case %d:\n", i); | |
476 | } | |
1a97be37 | 477 | |
bd70aa79 | 478 | for (i = 0; i < p->op_count; i++) |
479 | { | |
480 | if (p->oplocs[i] == 0) | |
481 | { | |
482 | printf (" ro[%d] = const0_rtx;\n", i); | |
2dc7706f | 483 | printf (" ro_loc[%d] = &junk;\n", i); |
bd70aa79 | 484 | } |
485 | else | |
486 | { | |
487 | printf (" ro[%d] = *(ro_loc[%d] = &", i, i); | |
488 | print_path (p->oplocs[i]); | |
0a1039d0 | 489 | puts (");"); |
bd70aa79 | 490 | } |
491 | } | |
492 | ||
493 | for (i = 0; i < p->dup_count; i++) | |
494 | { | |
ed420a25 | 495 | printf (" recog_data.dup_loc[%d] = &", i); |
bd70aa79 | 496 | print_path (p->duplocs[i]); |
0a1039d0 | 497 | puts (";"); |
ed420a25 | 498 | printf (" recog_data.dup_num[%d] = %d;\n", i, p->dupnums[i]); |
bd70aa79 | 499 | } |
500 | ||
0a1039d0 | 501 | puts (" break;\n"); |
3439974c | 502 | } |
503 | ||
0a1039d0 | 504 | puts (" }\n}"); |
3439974c | 505 | fflush (stdout); |
947491b7 | 506 | return (ferror (stdout) != 0 ? FATAL_EXIT_CODE : SUCCESS_EXIT_CODE); |
3439974c | 507 | } |