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