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