]> git.ipfire.org Git - thirdparty/gcc.git/blob - gcc/genextract.c
Cutover various gen*.c files to using system.h:
[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 walk_rtx PROTO ((rtx, char *));
99 static void print_path PROTO ((char *));
100 char *xmalloc PROTO ((unsigned));
101 char *xrealloc PROTO ((char *, unsigned));
102 static void fatal ();
103 static char *copystr PROTO ((char *));
104 static void mybzero ();
105 void fancy_abort PROTO ((void));
106 \f
107 static void
108 gen_insn (insn)
109 rtx insn;
110 {
111 register int i;
112 register struct extraction *p;
113 register struct code_ptr *link;
114
115 op_count = 0;
116 dup_count = 0;
117
118 /* No operands seen so far in this pattern. */
119 mybzero (oplocs, sizeof oplocs);
120
121 /* Walk the insn's pattern, remembering at all times the path
122 down to the walking point. */
123
124 if (XVECLEN (insn, 1) == 1)
125 walk_rtx (XVECEXP (insn, 1, 0), "");
126 else
127 for (i = XVECLEN (insn, 1) - 1; i >= 0; i--)
128 {
129 char *path = (char *) alloca (2);
130
131 path[0] = 'a' + i;
132 path[1] = 0;
133
134 walk_rtx (XVECEXP (insn, 1, i), path);
135 }
136
137 link = (struct code_ptr *) xmalloc (sizeof (struct code_ptr));
138 link->insn_code = insn_code_number;
139
140 /* See if we find something that already had this extraction method. */
141
142 for (p = extractions; p; p = p->next)
143 {
144 if (p->op_count != op_count || p->dup_count != dup_count)
145 continue;
146
147 for (i = 0; i < op_count; i++)
148 if (p->oplocs[i] != oplocs[i]
149 && ! (p->oplocs[i] != 0 && oplocs[i] != 0
150 && ! strcmp (p->oplocs[i], oplocs[i])))
151 break;
152
153 if (i != op_count)
154 continue;
155
156 for (i = 0; i < dup_count; i++)
157 if (p->dupnums[i] != dupnums[i]
158 || strcmp (p->duplocs[i], duplocs[i]))
159 break;
160
161 if (i != dup_count)
162 continue;
163
164 /* This extraction is the same as ours. Just link us in. */
165 link->next = p->insns;
166 p->insns = link;
167 return;
168 }
169
170 /* Otherwise, make a new extraction method. */
171
172 p = (struct extraction *) xmalloc (sizeof (struct extraction));
173 p->op_count = op_count;
174 p->dup_count = dup_count;
175 p->next = extractions;
176 extractions = p;
177 p->insns = link;
178 link->next = 0;
179
180 for (i = 0; i < op_count; i++)
181 p->oplocs[i] = oplocs[i];
182
183 for (i = 0; i < dup_count; i++)
184 p->dupnums[i] = dupnums[i], p->duplocs[i] = duplocs[i];
185 }
186 \f
187 static void
188 walk_rtx (x, path)
189 rtx x;
190 char *path;
191 {
192 register RTX_CODE code;
193 register int i;
194 register int len;
195 register char *fmt;
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_PAR_DUP:
220 duplocs[dup_count] = copystr (path);
221 dupnums[dup_count] = XINT (x, 0);
222 dup_count++;
223 break;
224
225 case MATCH_OP_DUP:
226 duplocs[dup_count] = copystr (path);
227 dupnums[dup_count] = XINT (x, 0);
228 dup_count++;
229
230 newpath = (char *) alloca (depth + 2);
231 strcpy (newpath, path);
232 newpath[depth + 1] = 0;
233
234 for (i = XVECLEN (x, 1) - 1; i >= 0; i--)
235 {
236 newpath[depth] = '0' + i;
237 walk_rtx (XVECEXP (x, 1, i), newpath);
238 }
239 return;
240
241 case MATCH_OPERATOR:
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] = '0' + i;
252 walk_rtx (XVECEXP (x, 2, i), newpath);
253 }
254 return;
255
256 case MATCH_PARALLEL:
257 oplocs[XINT (x, 0)] = copystr (path);
258 op_count = MAX (op_count, XINT (x, 0) + 1);
259
260 newpath = (char *) alloca (depth + 2);
261 strcpy (newpath, path);
262 newpath[depth + 1] = 0;
263
264 for (i = XVECLEN (x, 2) - 1; i >= 0; i--)
265 {
266 newpath[depth] = 'a' + i;
267 walk_rtx (XVECEXP (x, 2, i), newpath);
268 }
269 return;
270
271 case ADDRESS:
272 walk_rtx (XEXP (x, 0), path);
273 return;
274
275 default:
276 break;
277 }
278
279 newpath = (char *) alloca (depth + 2);
280 strcpy (newpath, path);
281 newpath[depth + 1] = 0;
282
283 fmt = GET_RTX_FORMAT (code);
284 len = GET_RTX_LENGTH (code);
285 for (i = 0; i < len; i++)
286 {
287 if (fmt[i] == 'e' || fmt[i] == 'u')
288 {
289 newpath[depth] = '0' + i;
290 walk_rtx (XEXP (x, i), newpath);
291 }
292 else if (fmt[i] == 'E')
293 {
294 int j;
295 for (j = XVECLEN (x, i) - 1; j >= 0; j--)
296 {
297 newpath[depth] = 'a' + j;
298 walk_rtx (XVECEXP (x, i, j), newpath);
299 }
300 }
301 }
302 }
303
304 /* Given a PATH, representing a path down the instruction's
305 pattern from the root to a certain point, output code to
306 evaluate to the rtx at that point. */
307
308 static void
309 print_path (path)
310 char *path;
311 {
312 register int len = strlen (path);
313 register int i;
314
315 /* We first write out the operations (XEXP or XVECEXP) in reverse
316 order, then write "insn", then the indices in forward order. */
317
318 for (i = len - 1; i >=0 ; i--)
319 {
320 if (path[i] >= 'a' && path[i] <= 'z')
321 printf ("XVECEXP (");
322 else if (path[i] >= '0' && path[i] <= '9')
323 printf ("XEXP (");
324 else
325 abort ();
326 }
327
328 printf ("pat");
329
330 for (i = 0; i < len; i++)
331 {
332 if (path[i] >= 'a' && path[i] <= 'z')
333 printf (", 0, %d)", path[i] - 'a');
334 else if (path[i] >= '0' && path[i] <= '9')
335 printf (", %d)", path[i] - '0');
336 else
337 abort ();
338 }
339 }
340 \f
341 char *
342 xmalloc (size)
343 unsigned size;
344 {
345 register char *val = (char *) malloc (size);
346
347 if (val == 0)
348 fatal ("virtual memory exhausted");
349 return val;
350 }
351
352 char *
353 xrealloc (ptr, size)
354 char *ptr;
355 unsigned size;
356 {
357 char *result = (char *) realloc (ptr, size);
358 if (!result)
359 fatal ("virtual memory exhausted");
360 return result;
361 }
362
363 static void
364 fatal (s, a1, a2)
365 char *s;
366 {
367 fprintf (stderr, "genextract: ");
368 fprintf (stderr, s, a1, a2);
369 fprintf (stderr, "\n");
370 exit (FATAL_EXIT_CODE);
371 }
372
373 /* More 'friendly' abort that prints the line and file.
374 config.h can #define abort fancy_abort if you like that sort of thing. */
375
376 void
377 fancy_abort ()
378 {
379 fatal ("Internal gcc abort.");
380 }
381
382 static char *
383 copystr (s1)
384 char *s1;
385 {
386 register char *tem;
387
388 if (s1 == 0)
389 return 0;
390
391 tem = (char *) xmalloc (strlen (s1) + 1);
392 strcpy (tem, s1);
393
394 return tem;
395 }
396
397 static void
398 mybzero (b, length)
399 register char *b;
400 register unsigned length;
401 {
402 while (length-- > 0)
403 *b++ = 0;
404 }
405 \f
406 int
407 main (argc, argv)
408 int argc;
409 char **argv;
410 {
411 rtx desc;
412 FILE *infile;
413 register int c, i;
414 struct extraction *p;
415 struct code_ptr *link;
416
417 obstack_init (rtl_obstack);
418
419 if (argc <= 1)
420 fatal ("No input file name.");
421
422 infile = fopen (argv[1], "r");
423 if (infile == 0)
424 {
425 perror (argv[1]);
426 exit (FATAL_EXIT_CODE);
427 }
428
429 init_rtl ();
430
431 /* Assign sequential codes to all entries in the machine description
432 in parallel with the tables in insn-output.c. */
433
434 insn_code_number = 0;
435
436 printf ("/* Generated automatically by the program `genextract'\n\
437 from the machine description file `md'. */\n\n");
438
439 printf ("#include \"config.h\"\n");
440 printf ("#include <stdio.h>\n");
441 printf ("#include \"rtl.h\"\n\n");
442
443 /* This variable exists only so it can be the "location"
444 of any missing operand whose numbers are skipped by a given pattern. */
445 printf ("static rtx junk;\n");
446
447 printf ("extern rtx recog_operand[];\n");
448 printf ("extern rtx *recog_operand_loc[];\n");
449 printf ("extern rtx *recog_dup_loc[];\n");
450 printf ("extern char recog_dup_num[];\n");
451
452 printf ("void\ninsn_extract (insn)\n");
453 printf (" rtx insn;\n");
454 printf ("{\n");
455 printf (" register rtx *ro = recog_operand;\n");
456 printf (" register rtx **ro_loc = recog_operand_loc;\n");
457 printf (" rtx pat = PATTERN (insn);\n");
458 printf (" int i;\n\n");
459 printf (" switch (INSN_CODE (insn))\n");
460 printf (" {\n");
461 printf (" case -1:\n");
462 printf (" fatal_insn_not_found (insn);\n\n");
463
464 /* Read the machine description. */
465
466 while (1)
467 {
468 c = read_skip_spaces (infile);
469 if (c == EOF)
470 break;
471 ungetc (c, infile);
472
473 desc = read_rtx (infile);
474 if (GET_CODE (desc) == DEFINE_INSN)
475 {
476 gen_insn (desc);
477 ++insn_code_number;
478 }
479
480 else if (GET_CODE (desc) == DEFINE_PEEPHOLE)
481 {
482 struct code_ptr *link
483 = (struct code_ptr *) xmalloc (sizeof (struct code_ptr));
484
485 link->insn_code = insn_code_number;
486 link->next = peepholes;
487 peepholes = link;
488 ++insn_code_number;
489 }
490
491 else if (GET_CODE (desc) == DEFINE_EXPAND
492 || GET_CODE (desc) == DEFINE_SPLIT)
493 ++insn_code_number;
494 }
495
496 /* Write out code to handle peepholes and the insn_codes that it should
497 be called for. */
498 if (peepholes)
499 {
500 for (link = peepholes; link; link = link->next)
501 printf (" case %d:\n", link->insn_code);
502
503 /* The vector in the insn says how many operands it has.
504 And all it contains are operands. In fact, the vector was
505 created just for the sake of this function. */
506 printf (" for (i = XVECLEN (pat, 0) - 1; i >= 0; i--)\n");
507 printf (" ro[i] = XVECEXP (pat, 0, i);\n");
508 printf (" break;\n\n");
509 }
510
511 /* Write out all the ways to extract insn operands. */
512 for (p = extractions; p; p = p->next)
513 {
514 for (link = p->insns; link; link = link->next)
515 printf (" case %d:\n", link->insn_code);
516
517 for (i = 0; i < p->op_count; i++)
518 {
519 if (p->oplocs[i] == 0)
520 {
521 printf (" ro[%d] = const0_rtx;\n", i);
522 printf (" ro_loc[%d] = &junk;\n", i);
523 }
524 else
525 {
526 printf (" ro[%d] = *(ro_loc[%d] = &", i, i);
527 print_path (p->oplocs[i]);
528 printf (");\n");
529 }
530 }
531
532 for (i = 0; i < p->dup_count; i++)
533 {
534 printf (" recog_dup_loc[%d] = &", i);
535 print_path (p->duplocs[i]);
536 printf (";\n");
537 printf (" recog_dup_num[%d] = %d;\n", i, p->dupnums[i]);
538 }
539
540 printf (" break;\n\n");
541 }
542
543 /* This should never be reached. Note that we would also reach this abort
544 if we tried to extract something whose INSN_CODE was a DEFINE_EXPAND or
545 DEFINE_SPLIT, but that is correct. */
546 printf (" default:\n abort ();\n");
547
548 printf (" }\n}\n");
549
550 fflush (stdout);
551 exit (ferror (stdout) != 0 ? FATAL_EXIT_CODE : SUCCESS_EXIT_CODE);
552 /* NOTREACHED */
553 return 0;
554 }