]> git.ipfire.org Git - thirdparty/gcc.git/blob - gcc/genextract.c
Makefile.in (insn-extract.o): Fix dependencies.
[thirdparty/gcc.git] / gcc / genextract.c
1 /* Generate code from machine description to extract operands from insn as rtl.
2 Copyright (C) 1987, 91, 92, 93, 97, 1998 Free Software Foundation, Inc.
3
4 This file is part of GNU CC.
5
6 GNU CC is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 2, or (at your option)
9 any later version.
10
11 GNU CC is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 GNU General Public License for more details.
15
16 You should have received a copy of the GNU General Public License
17 along with GNU CC; see the file COPYING. If not, write to
18 the Free Software Foundation, 59 Temple Place - Suite 330,
19 Boston, MA 02111-1307, USA. */
20
21
22 #include "hconfig.h"
23 #include "system.h"
24 #include "rtl.h"
25 #include "obstack.h"
26 #include "insn-config.h"
27
28 static struct obstack obstack;
29 struct obstack *rtl_obstack = &obstack;
30
31 #define obstack_chunk_alloc xmalloc
32 #define obstack_chunk_free free
33
34 /* Names for patterns. Need to allow linking with print-rtl. */
35 char **insn_name_ptr;
36
37 /* This structure contains all the information needed to describe one
38 set of extractions methods. Each method may be used by more than
39 one pattern if the operands are in the same place.
40
41 The string for each operand describes that path to the operand and
42 contains `0' through `9' when going into an expression and `a' through
43 `z' when going into a vector. We assume here that only the first operand
44 of an rtl expression is a vector. genrecog.c makes the same assumption
45 (and uses the same representation) and it is currently true. */
46
47 struct extraction
48 {
49 int op_count;
50 char *oplocs[MAX_RECOG_OPERANDS];
51 int dup_count;
52 char *duplocs[MAX_DUP_OPERANDS];
53 int dupnums[MAX_DUP_OPERANDS];
54 struct code_ptr *insns;
55 struct extraction *next;
56 };
57
58 /* Holds a single insn code that use an extraction method. */
59
60 struct code_ptr
61 {
62 int insn_code;
63 struct code_ptr *next;
64 };
65
66 static struct extraction *extractions;
67
68 /* Number instruction patterns handled, starting at 0 for first one. */
69
70 static int insn_code_number;
71
72 /* Records the large operand number in this insn. */
73
74 static int op_count;
75
76 /* Records the location of any operands using the string format described
77 above. */
78
79 static char *oplocs[MAX_RECOG_OPERANDS];
80
81 /* Number the occurrences of MATCH_DUP in each instruction,
82 starting at 0 for the first occurrence. */
83
84 static int dup_count;
85
86 /* Records the location of any MATCH_DUP operands. */
87
88 static char *duplocs[MAX_DUP_OPERANDS];
89
90 /* Record the operand number of any MATCH_DUPs. */
91
92 static int dupnums[MAX_DUP_OPERANDS];
93
94 /* Record the list of insn_codes for peepholes. */
95
96 static struct code_ptr *peepholes;
97
98 static void gen_insn PROTO ((rtx));
99 static void walk_rtx PROTO ((rtx, char *));
100 static void print_path PROTO ((char *));
101 char *xmalloc PROTO ((unsigned));
102 char *xrealloc PROTO ((char *, unsigned));
103 static void fatal PVPROTO ((char *, ...))
104 ATTRIBUTE_PRINTF_1 ATTRIBUTE_NORETURN;
105 static char *copystr PROTO ((char *));
106 static void mybzero ();
107 void fancy_abort PROTO ((void)) ATTRIBUTE_NORETURN;
108 \f
109 static void
110 gen_insn (insn)
111 rtx insn;
112 {
113 register int i;
114 register struct extraction *p;
115 register struct code_ptr *link;
116
117 op_count = 0;
118 dup_count = 0;
119
120 /* No operands seen so far in this pattern. */
121 mybzero (oplocs, sizeof oplocs);
122
123 /* Walk the insn's pattern, remembering at all times the path
124 down to the walking point. */
125
126 if (XVECLEN (insn, 1) == 1)
127 walk_rtx (XVECEXP (insn, 1, 0), "");
128 else
129 for (i = XVECLEN (insn, 1) - 1; i >= 0; i--)
130 {
131 char *path = (char *) alloca (2);
132
133 path[0] = 'a' + i;
134 path[1] = 0;
135
136 walk_rtx (XVECEXP (insn, 1, i), path);
137 }
138
139 link = (struct code_ptr *) xmalloc (sizeof (struct code_ptr));
140 link->insn_code = insn_code_number;
141
142 /* See if we find something that already had this extraction method. */
143
144 for (p = extractions; p; p = p->next)
145 {
146 if (p->op_count != op_count || p->dup_count != dup_count)
147 continue;
148
149 for (i = 0; i < op_count; i++)
150 if (p->oplocs[i] != oplocs[i]
151 && ! (p->oplocs[i] != 0 && oplocs[i] != 0
152 && ! strcmp (p->oplocs[i], oplocs[i])))
153 break;
154
155 if (i != op_count)
156 continue;
157
158 for (i = 0; i < dup_count; i++)
159 if (p->dupnums[i] != dupnums[i]
160 || strcmp (p->duplocs[i], duplocs[i]))
161 break;
162
163 if (i != dup_count)
164 continue;
165
166 /* This extraction is the same as ours. Just link us in. */
167 link->next = p->insns;
168 p->insns = link;
169 return;
170 }
171
172 /* Otherwise, make a new extraction method. */
173
174 p = (struct extraction *) xmalloc (sizeof (struct extraction));
175 p->op_count = op_count;
176 p->dup_count = dup_count;
177 p->next = extractions;
178 extractions = p;
179 p->insns = link;
180 link->next = 0;
181
182 for (i = 0; i < op_count; i++)
183 p->oplocs[i] = oplocs[i];
184
185 for (i = 0; i < dup_count; i++)
186 p->dupnums[i] = dupnums[i], p->duplocs[i] = duplocs[i];
187 }
188 \f
189 static void
190 walk_rtx (x, path)
191 rtx x;
192 char *path;
193 {
194 register RTX_CODE code;
195 register int i;
196 register int len;
197 register char *fmt;
198 int depth = strlen (path);
199 char *newpath;
200
201 if (x == 0)
202 return;
203
204 code = GET_CODE (x);
205
206 switch (code)
207 {
208 case PC:
209 case CC0:
210 case CONST_INT:
211 case SYMBOL_REF:
212 return;
213
214 case MATCH_OPERAND:
215 case MATCH_SCRATCH:
216 oplocs[XINT (x, 0)] = copystr (path);
217 op_count = MAX (op_count, XINT (x, 0) + 1);
218 break;
219
220 case MATCH_DUP:
221 case MATCH_PAR_DUP:
222 duplocs[dup_count] = copystr (path);
223 dupnums[dup_count] = XINT (x, 0);
224 dup_count++;
225 break;
226
227 case MATCH_OP_DUP:
228 duplocs[dup_count] = copystr (path);
229 dupnums[dup_count] = XINT (x, 0);
230 dup_count++;
231
232 newpath = (char *) alloca (depth + 2);
233 strcpy (newpath, path);
234 newpath[depth + 1] = 0;
235
236 for (i = XVECLEN (x, 1) - 1; i >= 0; i--)
237 {
238 newpath[depth] = '0' + i;
239 walk_rtx (XVECEXP (x, 1, i), newpath);
240 }
241 return;
242
243 case MATCH_OPERATOR:
244 oplocs[XINT (x, 0)] = copystr (path);
245 op_count = MAX (op_count, XINT (x, 0) + 1);
246
247 newpath = (char *) alloca (depth + 2);
248 strcpy (newpath, path);
249 newpath[depth + 1] = 0;
250
251 for (i = XVECLEN (x, 2) - 1; i >= 0; i--)
252 {
253 newpath[depth] = '0' + i;
254 walk_rtx (XVECEXP (x, 2, i), newpath);
255 }
256 return;
257
258 case MATCH_PARALLEL:
259 oplocs[XINT (x, 0)] = copystr (path);
260 op_count = MAX (op_count, XINT (x, 0) + 1);
261
262 newpath = (char *) alloca (depth + 2);
263 strcpy (newpath, path);
264 newpath[depth + 1] = 0;
265
266 for (i = XVECLEN (x, 2) - 1; i >= 0; i--)
267 {
268 newpath[depth] = 'a' + i;
269 walk_rtx (XVECEXP (x, 2, i), newpath);
270 }
271 return;
272
273 case ADDRESS:
274 walk_rtx (XEXP (x, 0), path);
275 return;
276
277 default:
278 break;
279 }
280
281 newpath = (char *) alloca (depth + 2);
282 strcpy (newpath, path);
283 newpath[depth + 1] = 0;
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 {
291 newpath[depth] = '0' + i;
292 walk_rtx (XEXP (x, i), newpath);
293 }
294 else if (fmt[i] == 'E')
295 {
296 int j;
297 for (j = XVECLEN (x, i) - 1; j >= 0; j--)
298 {
299 newpath[depth] = 'a' + j;
300 walk_rtx (XVECEXP (x, i, j), newpath);
301 }
302 }
303 }
304 }
305
306 /* Given a PATH, representing a path down the instruction's
307 pattern from the root to a certain point, output code to
308 evaluate to the rtx at that point. */
309
310 static void
311 print_path (path)
312 char *path;
313 {
314 register int len = strlen (path);
315 register int i;
316
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. */
321 printf("PATTERN (insn)");
322 return;
323 }
324
325 /* We first write out the operations (XEXP or XVECEXP) in reverse
326 order, then write "insn", then the indices in forward order. */
327
328 for (i = len - 1; i >=0 ; i--)
329 {
330 if (path[i] >= 'a' && path[i] <= 'z')
331 printf ("XVECEXP (");
332 else if (path[i] >= '0' && path[i] <= '9')
333 printf ("XEXP (");
334 else
335 abort ();
336 }
337
338 printf ("pat");
339
340 for (i = 0; i < len; i++)
341 {
342 if (path[i] >= 'a' && path[i] <= 'z')
343 printf (", 0, %d)", path[i] - 'a');
344 else if (path[i] >= '0' && path[i] <= '9')
345 printf (", %d)", path[i] - '0');
346 else
347 abort ();
348 }
349 }
350 \f
351 char *
352 xmalloc (size)
353 unsigned size;
354 {
355 register char *val = (char *) malloc (size);
356
357 if (val == 0)
358 fatal ("virtual memory exhausted");
359 return val;
360 }
361
362 char *
363 xrealloc (ptr, size)
364 char *ptr;
365 unsigned size;
366 {
367 char *result = (char *) realloc (ptr, size);
368 if (!result)
369 fatal ("virtual memory exhausted");
370 return result;
371 }
372
373 static void
374 fatal VPROTO ((char *format, ...))
375 {
376 #ifndef __STDC__
377 char *format;
378 #endif
379 va_list ap;
380
381 VA_START (ap, format);
382
383 #ifndef __STDC__
384 format = va_arg (ap, char *);
385 #endif
386
387 fprintf (stderr, "genextract: ");
388 vfprintf (stderr, format, ap);
389 va_end (ap);
390 fprintf (stderr, "\n");
391 exit (FATAL_EXIT_CODE);
392 }
393
394 /* More 'friendly' abort that prints the line and file.
395 config.h can #define abort fancy_abort if you like that sort of thing. */
396
397 void
398 fancy_abort ()
399 {
400 fatal ("Internal gcc abort.");
401 }
402
403 static char *
404 copystr (s1)
405 char *s1;
406 {
407 register char *tem;
408
409 if (s1 == 0)
410 return 0;
411
412 tem = (char *) xmalloc (strlen (s1) + 1);
413 strcpy (tem, s1);
414
415 return tem;
416 }
417
418 static void
419 mybzero (b, length)
420 register char *b;
421 register unsigned length;
422 {
423 while (length-- > 0)
424 *b++ = 0;
425 }
426 \f
427 int
428 main (argc, argv)
429 int argc;
430 char **argv;
431 {
432 rtx desc;
433 FILE *infile;
434 register int c, i;
435 struct extraction *p;
436 struct code_ptr *link;
437
438 obstack_init (rtl_obstack);
439
440 if (argc <= 1)
441 fatal ("No input file name.");
442
443 infile = fopen (argv[1], "r");
444 if (infile == 0)
445 {
446 perror (argv[1]);
447 exit (FATAL_EXIT_CODE);
448 }
449
450 init_rtl ();
451
452 /* Assign sequential codes to all entries in the machine description
453 in parallel with the tables in insn-output.c. */
454
455 insn_code_number = 0;
456
457 printf ("/* Generated automatically by the program `genextract'\n\
458 from the machine description file `md'. */\n\n");
459
460 printf ("#include \"config.h\"\n");
461 printf ("#include \"system.h\"\n");
462 printf ("#include \"rtl.h\"\n");
463 printf ("#include \"insn-config.h\"\n");
464 printf ("#include \"recog.h\"\n");
465 printf ("#include \"toplev.h\"\n\n");
466
467 /* This variable exists only so it can be the "location"
468 of any missing operand whose numbers are skipped by a given pattern. */
469 printf ("static rtx junk ATTRIBUTE_UNUSED;\n");
470
471 printf ("void\ninsn_extract (insn)\n");
472 printf (" rtx insn;\n");
473 printf ("{\n");
474 printf (" register rtx *ro = recog_operand;\n");
475 printf (" register rtx **ro_loc = recog_operand_loc;\n");
476 printf (" rtx pat = PATTERN (insn);\n");
477 printf (" int i ATTRIBUTE_UNUSED;\n\n");
478 printf (" switch (INSN_CODE (insn))\n");
479 printf (" {\n");
480 printf (" case -1:\n");
481 printf (" fatal_insn_not_found (insn);\n\n");
482
483 /* Read the machine description. */
484
485 while (1)
486 {
487 c = read_skip_spaces (infile);
488 if (c == EOF)
489 break;
490 ungetc (c, infile);
491
492 desc = read_rtx (infile);
493 if (GET_CODE (desc) == DEFINE_INSN)
494 {
495 gen_insn (desc);
496 ++insn_code_number;
497 }
498
499 else if (GET_CODE (desc) == DEFINE_PEEPHOLE)
500 {
501 struct code_ptr *link
502 = (struct code_ptr *) xmalloc (sizeof (struct code_ptr));
503
504 link->insn_code = insn_code_number;
505 link->next = peepholes;
506 peepholes = link;
507 ++insn_code_number;
508 }
509
510 else if (GET_CODE (desc) == DEFINE_EXPAND
511 || GET_CODE (desc) == DEFINE_SPLIT)
512 ++insn_code_number;
513 }
514
515 /* Write out code to handle peepholes and the insn_codes that it should
516 be called for. */
517 if (peepholes)
518 {
519 for (link = peepholes; link; link = link->next)
520 printf (" case %d:\n", link->insn_code);
521
522 /* The vector in the insn says how many operands it has.
523 And all it contains are operands. In fact, the vector was
524 created just for the sake of this function. */
525 printf (" for (i = XVECLEN (pat, 0) - 1; i >= 0; i--)\n");
526 printf (" ro[i] = XVECEXP (pat, 0, i);\n");
527 printf (" break;\n\n");
528 }
529
530 /* Write out all the ways to extract insn operands. */
531 for (p = extractions; p; p = p->next)
532 {
533 for (link = p->insns; link; link = link->next)
534 printf (" case %d:\n", link->insn_code);
535
536 for (i = 0; i < p->op_count; i++)
537 {
538 if (p->oplocs[i] == 0)
539 {
540 printf (" ro[%d] = const0_rtx;\n", i);
541 printf (" ro_loc[%d] = &junk;\n", i);
542 }
543 else
544 {
545 printf (" ro[%d] = *(ro_loc[%d] = &", i, i);
546 print_path (p->oplocs[i]);
547 printf (");\n");
548 }
549 }
550
551 for (i = 0; i < p->dup_count; i++)
552 {
553 printf (" recog_dup_loc[%d] = &", i);
554 print_path (p->duplocs[i]);
555 printf (";\n");
556 printf (" recog_dup_num[%d] = %d;\n", i, p->dupnums[i]);
557 }
558
559 printf (" break;\n\n");
560 }
561
562 /* This should never be reached. Note that we would also reach this abort
563 if we tried to extract something whose INSN_CODE was a DEFINE_EXPAND or
564 DEFINE_SPLIT, but that is correct. */
565 printf (" default:\n abort ();\n");
566
567 printf (" }\n}\n");
568
569 fflush (stdout);
570 exit (ferror (stdout) != 0 ? FATAL_EXIT_CODE : SUCCESS_EXIT_CODE);
571 /* NOTREACHED */
572 return 0;
573 }