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