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