|
|
1.1 root 1: /* Generate code from machine description to extract operands from insn as rtl.
2: Copyright (C) 1987, 1991, 1992, 1993 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 "hconfig.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: /* Names for patterns. Need to allow linking with print-rtl. */
37: char **insn_name_ptr;
38:
39: /* This structure contains all the information needed to describe one
40: set of extractions methods. Each method may be used by more than
41: one pattern if the operands are in the same place.
42:
43: The string for each operand describes that path to the operand and
44: contains `0' through `9' when going into an expression and `a' through
45: `z' when going into a vector. We assume here that only the first operand
46: of an rtl expression is a vector. genrecog.c makes the same assumption
47: (and uses the same representation) and it is currently true. */
48:
49: struct extraction
50: {
51: int op_count;
52: char *oplocs[MAX_RECOG_OPERANDS];
53: int dup_count;
54: char *duplocs[MAX_DUP_OPERANDS];
55: int dupnums[MAX_DUP_OPERANDS];
56: struct code_ptr *insns;
57: struct extraction *next;
58: };
59:
60: /* Holds a single insn code that use an extraction method. */
61:
62: struct code_ptr
63: {
64: int insn_code;
65: struct code_ptr *next;
66: };
67:
68: static struct extraction *extractions;
69:
70: /* Number instruction patterns handled, starting at 0 for first one. */
71:
72: static int insn_code_number;
73:
74: /* Records the large operand number in this insn. */
75:
76: static int op_count;
77:
78: /* Records the location of any operands using the string format described
79: above. */
80:
81: static char *oplocs[MAX_RECOG_OPERANDS];
82:
83: /* Number the occurrences of MATCH_DUP in each instruction,
84: starting at 0 for the first occurrence. */
85:
86: static int dup_count;
87:
88: /* Records the location of any MATCH_DUP operands. */
89:
90: static char *duplocs[MAX_DUP_OPERANDS];
91:
92: /* Record the operand number of any MATCH_DUPs. */
93:
94: static int dupnums[MAX_DUP_OPERANDS];
95:
96: /* Record the list of insn_codes for peepholes. */
97:
98: static struct code_ptr *peepholes;
99:
100: static void walk_rtx ();
101: static void print_path ();
102: char *xmalloc ();
103: char *xrealloc ();
104: static void fatal ();
105: static char *copystr ();
106: static void mybzero ();
107: void fancy_abort ();
108:
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:
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: register struct code_ptr *link;
199: int depth = strlen (path);
200: char *newpath;
201:
202: if (x == 0)
203: return;
204:
205: code = GET_CODE (x);
206:
207: switch (code)
208: {
209: case PC:
210: case CC0:
211: case CONST_INT:
212: case SYMBOL_REF:
213: return;
214:
215: case MATCH_OPERAND:
216: case MATCH_SCRATCH:
217: oplocs[XINT (x, 0)] = copystr (path);
218: op_count = MAX (op_count, XINT (x, 0) + 1);
219: break;
220:
221: case MATCH_DUP:
222: case MATCH_PAR_DUP:
223: duplocs[dup_count] = copystr (path);
224: dupnums[dup_count] = XINT (x, 0);
225: dup_count++;
226: break;
227:
228: case MATCH_OP_DUP:
229: duplocs[dup_count] = copystr (path);
230: dupnums[dup_count] = XINT (x, 0);
231: dup_count++;
232:
233: newpath = (char *) alloca (depth + 2);
234: strcpy (newpath, path);
235: newpath[depth + 1] = 0;
236:
237: for (i = XVECLEN (x, 1) - 1; i >= 0; i--)
238: {
239: newpath[depth] = '0' + i;
240: walk_rtx (XVECEXP (x, 1, i), newpath);
241: }
242: return;
243:
244: case MATCH_OPERATOR:
245: oplocs[XINT (x, 0)] = copystr (path);
246: op_count = MAX (op_count, XINT (x, 0) + 1);
247:
248: newpath = (char *) alloca (depth + 2);
249: strcpy (newpath, path);
250: newpath[depth + 1] = 0;
251:
252: for (i = XVECLEN (x, 2) - 1; i >= 0; i--)
253: {
254: newpath[depth] = '0' + i;
255: walk_rtx (XVECEXP (x, 2, i), newpath);
256: }
257: return;
258:
259: case MATCH_PARALLEL:
260: oplocs[XINT (x, 0)] = copystr (path);
261: op_count = MAX (op_count, XINT (x, 0) + 1);
262:
263: newpath = (char *) alloca (depth + 2);
264: strcpy (newpath, path);
265: newpath[depth + 1] = 0;
266:
267: for (i = XVECLEN (x, 2) - 1; i >= 0; i--)
268: {
269: newpath[depth] = 'a' + i;
270: walk_rtx (XVECEXP (x, 2, i), newpath);
271: }
272: return;
273:
274: case ADDRESS:
275: walk_rtx (XEXP (x, 0), path);
276: return;
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:
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:
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 \"rtl.h\"\n\n");
441:
442: /* This variable exists only so it can be the "location"
443: of any missing operand whose numbers are skipped by a given pattern. */
444: printf ("static rtx junk;\n");
445:
446: printf ("extern rtx recog_operand[];\n");
447: printf ("extern rtx *recog_operand_loc[];\n");
448: printf ("extern rtx *recog_dup_loc[];\n");
449: printf ("extern char recog_dup_num[];\n");
450: printf ("extern\n#ifdef __GNUC__\n__volatile__\n#endif\n");
451: printf ("void fatal_insn_not_found ();\n\n");
452:
453: printf ("void\ninsn_extract (insn)\n");
454: printf (" rtx insn;\n");
455: printf ("{\n");
456: printf (" register rtx *ro = recog_operand;\n");
457: printf (" register rtx **ro_loc = recog_operand_loc;\n");
458: printf (" rtx pat = PATTERN (insn);\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 ("#if __GNUC__ > 1 && !defined (bcopy)\n");
507: printf ("#define bcopy(FROM,TO,COUNT) __builtin_memcpy(TO,FROM,COUNT)\n");
508: printf ("#endif\n");
509: printf (" bcopy (&XVECEXP (pat, 0, 0), ro,\n");
510: printf (" sizeof (rtx) * XVECLEN (pat, 0));\n");
511: printf (" break;\n\n");
512: }
513:
514: /* Write out all the ways to extract insn operands. */
515: for (p = extractions; p; p = p->next)
516: {
517: for (link = p->insns; link; link = link->next)
518: printf (" case %d:\n", link->insn_code);
519:
520: for (i = 0; i < p->op_count; i++)
521: {
522: if (p->oplocs[i] == 0)
523: {
524: printf (" ro[%d] = const0_rtx;\n", i);
525: printf (" ro_loc[%d] = &junk;\n", i);
526: }
527: else
528: {
529: printf (" ro[%d] = *(ro_loc[%d] = &", i, i);
530: print_path (p->oplocs[i]);
531: printf (");\n");
532: }
533: }
534:
535: for (i = 0; i < p->dup_count; i++)
536: {
537: printf (" recog_dup_loc[%d] = &", i);
538: print_path (p->duplocs[i]);
539: printf (";\n");
540: printf (" recog_dup_num[%d] = %d;\n", i, p->dupnums[i]);
541: }
542:
543: printf (" break;\n\n");
544: }
545:
546: /* This should never be reached. Note that we would also reach this abort
547: if we tried to extract something whose INSN_CODE was a DEFINE_EXPAND or
548: DEFINE_SPLIT, but that is correct. */
549: printf (" default:\n abort ();\n");
550:
551: printf (" }\n}\n");
552:
553: fflush (stdout);
554: exit (ferror (stdout) != 0 ? FATAL_EXIT_CODE : SUCCESS_EXIT_CODE);
555: /* NOTREACHED */
556: return 0;
557: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.