]> gcc.gnu.org Git - gcc.git/blob - gcc/genextract.c
Find the links to directories by finding each link and testing it with test.
[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 duplocs[dup_count] = copystr (path);
221 dupnums[dup_count] = XINT (x, 0);
222 dup_count++;
223 break;
224
225 case MATCH_OPERATOR:
226 oplocs[XINT (x, 0)] = copystr (path);
227 op_count = MAX (op_count, XINT (x, 0) + 1);
228
229 newpath = (char *) alloca (depth + 2);
230 strcpy (newpath, path);
231 newpath[depth + 1] = 0;
232
233 for (i = XVECLEN (x, 2) - 1; i >= 0; i--)
234 {
235 newpath[depth] = '0' + i;
236 walk_rtx (XVECEXP (x, 2, i), newpath);
237 }
238 return;
239
240 case MATCH_PARALLEL:
241 oplocs[XINT (x, 0)] = copystr (path);
242 op_count = MAX (op_count, XINT (x, 0) + 1);
243
244 newpath = (char *) alloca (depth + 2);
245 strcpy (newpath, path);
246 newpath[depth + 1] = 0;
247
248 for (i = XVECLEN (x, 2) - 1; i >= 0; i--)
249 {
250 newpath[depth] = 'a' + i;
251 walk_rtx (XVECEXP (x, 2, i), newpath);
252 }
253 return;
254
255 case ADDRESS:
256 walk_rtx (XEXP (x, 0), path);
257 return;
258 }
259
260 newpath = (char *) alloca (depth + 2);
261 strcpy (newpath, path);
262 newpath[depth + 1] = 0;
263
264 fmt = GET_RTX_FORMAT (code);
265 len = GET_RTX_LENGTH (code);
266 for (i = 0; i < len; i++)
267 {
268 if (fmt[i] == 'e' || fmt[i] == 'u')
269 {
270 newpath[depth] = '0' + i;
271 walk_rtx (XEXP (x, i), newpath);
272 }
273 else if (fmt[i] == 'E')
274 {
275 int j;
276 for (j = XVECLEN (x, i) - 1; j >= 0; j--)
277 {
278 newpath[depth] = 'a' + j;
279 walk_rtx (XVECEXP (x, i, j), newpath);
280 }
281 }
282 }
283 }
284
285 /* Given a PATH, representing a path down the instruction's
286 pattern from the root to a certain point, output code to
287 evaluate to the rtx at that point. */
288
289 static void
290 print_path (path)
291 char *path;
292 {
293 register int len = strlen (path);
294 register int i;
295
296 /* We first write out the operations (XEXP or XVECEXP) in reverse
297 order, then write "insn", then the indices in forward order. */
298
299 for (i = len - 1; i >=0 ; i--)
300 {
301 if (path[i] >= 'a' && path[i] <= 'z')
302 printf ("XVECEXP (");
303 else if (path[i] >= '0' && path[i] <= '9')
304 printf ("XEXP (");
305 else
306 abort ();
307 }
308
309 printf ("pat");
310
311 for (i = 0; i < len; i++)
312 {
313 if (path[i] >= 'a' && path[i] <= 'z')
314 printf (", 0, %d)", path[i] - 'a');
315 else if (path[i] >= '0' && path[i] <= '9')
316 printf (", %d)", path[i] - '0');
317 else
318 abort ();
319 }
320 }
321 \f
322 char *
323 xmalloc (size)
324 unsigned size;
325 {
326 register char *val = (char *) malloc (size);
327
328 if (val == 0)
329 fatal ("virtual memory exhausted");
330 return val;
331 }
332
333 char *
334 xrealloc (ptr, size)
335 char *ptr;
336 unsigned size;
337 {
338 char *result = (char *) realloc (ptr, size);
339 if (!result)
340 fatal ("virtual memory exhausted");
341 return result;
342 }
343
344 static void
345 fatal (s, a1, a2)
346 char *s;
347 {
348 fprintf (stderr, "genextract: ");
349 fprintf (stderr, s, a1, a2);
350 fprintf (stderr, "\n");
351 exit (FATAL_EXIT_CODE);
352 }
353
354 /* More 'friendly' abort that prints the line and file.
355 config.h can #define abort fancy_abort if you like that sort of thing. */
356
357 void
358 fancy_abort ()
359 {
360 fatal ("Internal gcc abort.");
361 }
362
363 static char *
364 copystr (s1)
365 char *s1;
366 {
367 register char *tem;
368
369 if (s1 == 0)
370 return 0;
371
372 tem = (char *) xmalloc (strlen (s1) + 1);
373 strcpy (tem, s1);
374
375 return tem;
376 }
377
378 static void
379 mybzero (b, length)
380 register char *b;
381 register unsigned length;
382 {
383 while (length-- > 0)
384 *b++ = 0;
385 }
386 \f
387 int
388 main (argc, argv)
389 int argc;
390 char **argv;
391 {
392 rtx desc;
393 FILE *infile;
394 register int c, i;
395 struct extraction *p;
396 struct code_ptr *link;
397
398 obstack_init (rtl_obstack);
399
400 if (argc <= 1)
401 fatal ("No input file name.");
402
403 infile = fopen (argv[1], "r");
404 if (infile == 0)
405 {
406 perror (argv[1]);
407 exit (FATAL_EXIT_CODE);
408 }
409
410 init_rtl ();
411
412 /* Assign sequential codes to all entries in the machine description
413 in parallel with the tables in insn-output.c. */
414
415 insn_code_number = 0;
416
417 printf ("/* Generated automatically by the program `genextract'\n\
418 from the machine description file `md'. */\n\n");
419
420 printf ("#include \"config.h\"\n");
421 printf ("#include \"rtl.h\"\n\n");
422
423 /* This variable exists only so it can be the "location"
424 of any missing operand whose numbers are skipped by a given pattern. */
425 printf ("static rtx junk;\n");
426
427 printf ("extern rtx recog_operand[];\n");
428 printf ("extern rtx *recog_operand_loc[];\n");
429 printf ("extern rtx *recog_dup_loc[];\n");
430 printf ("extern char recog_dup_num[];\n");
431 printf ("extern\n#ifdef __GNUC__\nvolatile\n#endif\n");
432 printf ("void fatal_insn_not_found ();\n\n");
433
434 printf ("void\ninsn_extract (insn)\n");
435 printf (" rtx insn;\n");
436 printf ("{\n");
437 printf (" register rtx *ro = recog_operand;\n");
438 printf (" register rtx **ro_loc = recog_operand_loc;\n");
439 printf (" rtx pat = PATTERN (insn);\n");
440 printf (" switch (INSN_CODE (insn))\n");
441 printf (" {\n");
442 printf (" case -1:\n");
443 printf (" fatal_insn_not_found (insn);\n\n");
444
445 /* Read the machine description. */
446
447 while (1)
448 {
449 c = read_skip_spaces (infile);
450 if (c == EOF)
451 break;
452 ungetc (c, infile);
453
454 desc = read_rtx (infile);
455 if (GET_CODE (desc) == DEFINE_INSN)
456 {
457 gen_insn (desc);
458 ++insn_code_number;
459 }
460
461 else if (GET_CODE (desc) == DEFINE_PEEPHOLE)
462 {
463 struct code_ptr *link
464 = (struct code_ptr *) xmalloc (sizeof (struct code_ptr));
465
466 link->insn_code = insn_code_number;
467 link->next = peepholes;
468 peepholes = link;
469 ++insn_code_number;
470 }
471
472 else if (GET_CODE (desc) == DEFINE_EXPAND
473 || GET_CODE (desc) == DEFINE_SPLIT)
474 ++insn_code_number;
475 }
476
477 /* Write out code to handle peepholes and the insn_codes that it should
478 be called for. */
479 if (peepholes)
480 {
481 for (link = peepholes; link; link = link->next)
482 printf (" case %d:\n", link->insn_code);
483
484 /* The vector in the insn says how many operands it has.
485 And all it contains are operands. In fact, the vector was
486 created just for the sake of this function. */
487 printf ("#if __GNUC__ > 1 && !defined (bcopy)\n");
488 printf ("#define bcopy(FROM,TO,COUNT) __builtin_memcpy(TO,FROM,COUNT)\n");
489 printf ("#endif\n");
490 printf (" bcopy (&XVECEXP (pat, 0, 0), ro,\n");
491 printf (" sizeof (rtx) * XVECLEN (pat, 0));\n");
492 printf (" break;\n\n");
493 }
494
495 /* Write out all the ways to extract insn operands. */
496 for (p = extractions; p; p = p->next)
497 {
498 for (link = p->insns; link; link = link->next)
499 printf (" case %d:\n", link->insn_code);
500
501 for (i = 0; i < p->op_count; i++)
502 {
503 if (p->oplocs[i] == 0)
504 {
505 printf (" ro[%d] = const0_rtx;\n", i);
506 printf (" ro_loc[%d] = &junk;\n", i, i);
507 }
508 else
509 {
510 printf (" ro[%d] = *(ro_loc[%d] = &", i, i);
511 print_path (p->oplocs[i]);
512 printf (");\n");
513 }
514 }
515
516 for (i = 0; i < p->dup_count; i++)
517 {
518 printf (" recog_dup_loc[%d] = &", i);
519 print_path (p->duplocs[i]);
520 printf (";\n");
521 printf (" recog_dup_num[%d] = %d;\n", i, p->dupnums[i]);
522 }
523
524 printf (" break;\n\n");
525 }
526
527 /* This should never be reached. Note that we would also reach this abort
528 if we tried to extract something whose INSN_CODE was a DEFINE_EXPAND or
529 DEFINE_SPLIT, but that is correct. */
530 printf (" default:\n abort ();\n");
531
532 printf (" }\n}\n");
533
534 fflush (stdout);
535 exit (ferror (stdout) != 0 ? FATAL_EXIT_CODE : SUCCESS_EXIT_CODE);
536 /* NOTREACHED */
537 return 0;
538 }
This page took 0.05967 seconds and 5 git commands to generate.