OSDN Git Service

d
[pf3gnuchains/gcc-fork.git] / gcc / genemit.c
1 /* Generate code from machine description to emit insns as rtl.
2    Copyright (C) 1987, 88, 91, 94, 95, 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
27 #ifdef HAVE_STDLIB_H
28 #include <stdlib.h>
29 #endif
30
31 static struct obstack obstack;
32 struct obstack *rtl_obstack = &obstack;
33
34 #define obstack_chunk_alloc xmalloc
35 #define obstack_chunk_free free
36
37 #ifdef NEED_DECLARATION_FREE
38 extern void free ();
39 #endif
40 extern rtx read_rtx ();
41
42 char *xmalloc ();
43 static void fatal ();
44 void fancy_abort ();
45
46 static int max_opno;
47 static int max_dup_opno;
48 static int register_constraints;
49 static int insn_code_number;
50 static int insn_index_number;
51
52 /* Data structure for recording the patterns of insns that have CLOBBERs.
53    We use this to output a function that adds these CLOBBERs to a 
54    previously-allocated PARALLEL expression.  */
55
56 struct clobber_pat
57 {
58   struct clobber_ent *insns;
59   rtx pattern;
60   int first_clobber;
61   struct clobber_pat *next;
62 } *clobber_list;
63
64 /* Records one insn that uses the clobber list.  */
65
66 struct clobber_ent
67 {
68   int code_number;              /* Counts only insns.  */
69   struct clobber_ent *next;
70 };
71
72 static void
73 max_operand_1 (x)
74      rtx x;
75 {
76   register RTX_CODE code;
77   register int i;
78   register int len;
79   register char *fmt;
80
81   if (x == 0)
82     return;
83
84   code = GET_CODE (x);
85
86   if (code == MATCH_OPERAND && XSTR (x, 2) != 0 && *XSTR (x, 2) != '\0')
87     register_constraints = 1;
88   if (code == MATCH_SCRATCH && XSTR (x, 1) != 0 && *XSTR (x, 1) != '\0')
89     register_constraints = 1;
90   if (code == MATCH_OPERAND || code == MATCH_OPERATOR
91       || code == MATCH_PARALLEL)
92     max_opno = MAX (max_opno, XINT (x, 0));
93   if (code == MATCH_DUP || code == MATCH_OP_DUP || code == MATCH_PAR_DUP)
94     max_dup_opno = MAX (max_dup_opno, XINT (x, 0));
95
96   fmt = GET_RTX_FORMAT (code);
97   len = GET_RTX_LENGTH (code);
98   for (i = 0; i < len; i++)
99     {
100       if (fmt[i] == 'e' || fmt[i] == 'u')
101         max_operand_1 (XEXP (x, i));
102       else if (fmt[i] == 'E')
103         {
104           int j;
105           for (j = 0; j < XVECLEN (x, i); j++)
106             max_operand_1 (XVECEXP (x, i, j));
107         }
108     }
109 }
110
111 static int
112 max_operand_vec (insn, arg)
113      rtx insn;
114      int arg;
115 {
116   register int len = XVECLEN (insn, arg);
117   register int i;
118
119   max_opno = -1;
120   max_dup_opno = -1;
121
122   for (i = 0; i < len; i++)
123     max_operand_1 (XVECEXP (insn, arg, i));
124
125   return max_opno + 1;
126 }
127 \f
128 static void
129 print_code (code)
130      RTX_CODE code;
131 {
132   register char *p1;
133   for (p1 = GET_RTX_NAME (code); *p1; p1++)
134     {
135       if (*p1 >= 'a' && *p1 <= 'z')
136         putchar (*p1 + 'A' - 'a');
137       else
138         putchar (*p1);
139     }
140 }
141
142 /* Print a C expression to construct an RTX just like X,
143    substituting any operand references appearing within.  */
144
145 static void
146 gen_exp (x)
147      rtx x;
148 {
149   register RTX_CODE code;
150   register int i;
151   register int len;
152   register char *fmt;
153
154   if (x == 0)
155     {
156       printf ("NULL_RTX");
157       return;
158     }
159
160   code = GET_CODE (x);
161
162   switch (code)
163     {
164     case MATCH_OPERAND:
165     case MATCH_DUP:
166       printf ("operand%d", XINT (x, 0));
167       return;
168
169     case MATCH_OP_DUP:
170       printf ("gen_rtx (GET_CODE (operand%d), GET_MODE (operand%d)",
171               XINT (x, 0), XINT (x, 0));
172       for (i = 0; i < XVECLEN (x, 1); i++)
173         {
174           printf (",\n\t\t");
175           gen_exp (XVECEXP (x, 1, i));
176         }
177       printf (")");
178       return;
179
180     case MATCH_OPERATOR:
181       printf ("gen_rtx (GET_CODE (operand%d)", XINT (x, 0));
182       printf (", %smode", GET_MODE_NAME (GET_MODE (x)));
183       for (i = 0; i < XVECLEN (x, 2); i++)
184         {
185           printf (",\n\t\t");
186           gen_exp (XVECEXP (x, 2, i));
187         }
188       printf (")");
189       return;
190
191     case MATCH_PARALLEL:
192     case MATCH_PAR_DUP:
193       printf ("operand%d", XINT (x, 0));
194       return;
195
196     case MATCH_SCRATCH:
197       printf ("gen_rtx_SCRATCH (%smode)", GET_MODE_NAME (GET_MODE (x)));
198       return;
199
200     case ADDRESS:
201       fatal ("ADDRESS expression code used in named instruction pattern");
202
203     case PC:
204       printf ("pc_rtx");
205       return;
206
207     case CC0:
208       printf ("cc0_rtx");
209       return;
210
211     case CONST_INT:
212       if (INTVAL (x) == 0)
213         printf ("const0_rtx");
214       else if (INTVAL (x) == 1)
215         printf ("const1_rtx");
216       else if (INTVAL (x) == -1)
217         printf ("constm1_rtx");
218       else if (INTVAL (x) == STORE_FLAG_VALUE)
219         printf ("const_true_rtx");
220       else
221         {
222           printf ("GEN_INT (");
223           printf (HOST_WIDE_INT_PRINT_DEC, INTVAL (x));
224           printf (")");
225         }
226       return;
227
228     case CONST_DOUBLE:
229       /* These shouldn't be written in MD files.  Instead, the appropriate
230          routines in varasm.c should be called.  */
231       abort ();
232
233     default:
234       break;
235     }
236
237   printf ("gen_rtx_");
238   print_code (code);
239   printf (" (%smode", GET_MODE_NAME (GET_MODE (x)));
240
241   fmt = GET_RTX_FORMAT (code);
242   len = GET_RTX_LENGTH (code);
243   for (i = 0; i < len; i++)
244     {
245       if (fmt[i] == '0')
246         break;
247       printf (",\n\t");
248       if (fmt[i] == 'e' || fmt[i] == 'u')
249         gen_exp (XEXP (x, i));
250       else if (fmt[i] == 'i')
251         printf ("%u", XINT (x, i));
252       else if (fmt[i] == 's')
253         printf ("\"%s\"", XSTR (x, i));
254       else if (fmt[i] == 'E')
255         {
256           int j;
257           printf ("gen_rtvec (%d", XVECLEN (x, i));
258           for (j = 0; j < XVECLEN (x, i); j++)
259             {
260               printf (",\n\t\t");
261               gen_exp (XVECEXP (x, i, j));
262             }
263           printf (")");
264         }
265       else
266         abort ();
267     }
268   printf (")");
269 }  
270 \f
271 /* Generate the `gen_...' function for a DEFINE_INSN.  */
272
273 static void
274 gen_insn (insn)
275      rtx insn;
276 {
277   int operands;
278   register int i;
279
280   /* See if the pattern for this insn ends with a group of CLOBBERs of (hard)
281      registers or MATCH_SCRATCHes.  If so, store away the information for
282      later.  */
283
284   if (XVEC (insn, 1))
285     {
286       for (i = XVECLEN (insn, 1) - 1; i > 0; i--)
287         if (GET_CODE (XVECEXP (insn, 1, i)) != CLOBBER
288             || (GET_CODE (XEXP (XVECEXP (insn, 1, i), 0)) != REG
289                 && GET_CODE (XEXP (XVECEXP (insn, 1, i), 0)) != MATCH_SCRATCH))
290           break;
291
292       if (i != XVECLEN (insn, 1) - 1)
293         {
294           register struct clobber_pat *p;
295           register struct clobber_ent *link
296             = (struct clobber_ent *) xmalloc (sizeof (struct clobber_ent));
297           register int j;
298
299           link->code_number = insn_code_number;
300
301           /* See if any previous CLOBBER_LIST entry is the same as this
302              one.  */
303
304           for (p = clobber_list; p; p = p->next)
305             {
306               if (p->first_clobber != i + 1
307                   || XVECLEN (p->pattern, 1) != XVECLEN (insn, 1))
308                 continue;
309
310               for (j = i + 1; j < XVECLEN (insn, 1); j++)
311                 {
312                   rtx old = XEXP (XVECEXP (p->pattern, 1, j), 0);
313                   rtx new = XEXP (XVECEXP (insn, 1, j), 0);
314
315                   /* OLD and NEW are the same if both are to be a SCRATCH
316                      of the same mode, 
317                      or if both are registers of the same mode and number.  */
318                   if (! (GET_MODE (old) == GET_MODE (new)
319                          && ((GET_CODE (old) == MATCH_SCRATCH
320                               && GET_CODE (new) == MATCH_SCRATCH)
321                              || (GET_CODE (old) == REG && GET_CODE (new) == REG
322                                  && REGNO (old) == REGNO (new)))))
323                     break;
324                 }
325       
326               if (j == XVECLEN (insn, 1))
327                 break;
328             }
329
330           if (p == 0)
331             {
332               p = (struct clobber_pat *) xmalloc (sizeof (struct clobber_pat));
333           
334               p->insns = 0;
335               p->pattern = insn;
336               p->first_clobber = i + 1;
337               p->next = clobber_list;
338               clobber_list = p;
339             }
340
341           link->next = p->insns;
342           p->insns = link;
343         }
344     }
345
346   /* Don't mention instructions whose names are the null string
347      or begin with '*'.  They are in the machine description just
348      to be recognized.  */
349   if (XSTR (insn, 0)[0] == 0 || XSTR (insn, 0)[0] == '*')
350     return;
351
352   /* Find out how many operands this function has,
353      and also whether any of them have register constraints.  */
354   register_constraints = 0;
355   operands = max_operand_vec (insn, 1);
356   if (max_dup_opno >= operands)
357     fatal ("match_dup operand number has no match_operand");
358
359   /* Output the function name and argument declarations.  */
360   printf ("rtx\ngen_%s (", XSTR (insn, 0));
361   for (i = 0; i < operands; i++)
362     printf (i ? ", operand%d" : "operand%d", i);
363   printf (")\n");
364   for (i = 0; i < operands; i++)
365     printf ("     rtx operand%d;\n", i);
366   printf ("{\n");
367
368   /* Output code to construct and return the rtl for the instruction body */
369
370   if (XVECLEN (insn, 1) == 1)
371     {
372       printf ("  return ");
373       gen_exp (XVECEXP (insn, 1, 0));
374       printf (";\n}\n\n");
375     }
376   else
377     {
378       printf ("  return gen_rtx_PARALLEL (VOIDmode, gen_rtvec (%d", XVECLEN (insn, 1));
379       for (i = 0; i < XVECLEN (insn, 1); i++)
380         {
381           printf (",\n\t\t");
382           gen_exp (XVECEXP (insn, 1, i));
383         }
384       printf ("));\n}\n\n");
385     }
386 }
387 \f
388 /* Generate the `gen_...' function for a DEFINE_EXPAND.  */
389
390 static void
391 gen_expand (expand)
392      rtx expand;
393 {
394   int operands;
395   register int i;
396
397   if (strlen (XSTR (expand, 0)) == 0)
398     fatal ("define_expand lacks a name");
399   if (XVEC (expand, 1) == 0)
400     fatal ("define_expand for %s lacks a pattern", XSTR (expand, 0));
401
402   /* Find out how many operands this function has,
403      and also whether any of them have register constraints.  */
404   register_constraints = 0;
405
406   operands = max_operand_vec (expand, 1);
407
408   /* Output the function name and argument declarations.  */
409   printf ("rtx\ngen_%s (", XSTR (expand, 0));
410   for (i = 0; i < operands; i++)
411     printf (i ? ", operand%d" : "operand%d", i);
412   printf (")\n");
413   for (i = 0; i < operands; i++)
414     printf ("     rtx operand%d;\n", i);
415   printf ("{\n");
416
417   /* If we don't have any C code to write, only one insn is being written,
418      and no MATCH_DUPs are present, we can just return the desired insn
419      like we do for a DEFINE_INSN.  This saves memory.  */
420   if ((XSTR (expand, 3) == 0 || *XSTR (expand, 3) == '\0')
421       && operands > max_dup_opno
422       && XVECLEN (expand, 1) == 1)
423     {
424       printf ("  return ");
425       gen_exp (XVECEXP (expand, 1, 0));
426       printf (";\n}\n\n");
427       return;
428     }
429
430   /* For each operand referred to only with MATCH_DUPs,
431      make a local variable.  */
432   for (i = operands; i <= max_dup_opno; i++)
433     printf ("  rtx operand%d;\n", i);
434   if (operands > 0 || max_dup_opno >= 0)
435     printf ("  rtx operands[%d];\n", MAX (operands, max_dup_opno + 1));
436   printf ("  rtx _val = 0;\n");
437   printf ("  start_sequence ();\n");
438
439   /* The fourth operand of DEFINE_EXPAND is some code to be executed
440      before the actual construction.
441      This code expects to refer to `operands'
442      just as the output-code in a DEFINE_INSN does,
443      but here `operands' is an automatic array.
444      So copy the operand values there before executing it.  */
445   if (XSTR (expand, 3) && *XSTR (expand, 3))
446     {
447       /* Output code to copy the arguments into `operands'.  */
448       for (i = 0; i < operands; i++)
449         printf ("  operands[%d] = operand%d;\n", i, i);
450
451       /* Output the special code to be executed before the sequence
452          is generated.  */
453       printf ("%s\n", XSTR (expand, 3));
454
455       /* Output code to copy the arguments back out of `operands'
456          (unless we aren't going to use them at all).  */
457       if (XVEC (expand, 1) != 0)
458         {
459           for (i = 0; i < operands; i++)
460             printf ("  operand%d = operands[%d];\n", i, i);
461           for (; i <= max_dup_opno; i++)
462             printf ("  operand%d = operands[%d];\n", i, i);
463         }
464     }
465
466   /* Output code to construct the rtl for the instruction bodies.
467      Use emit_insn to add them to the sequence being accumulated.
468      But don't do this if the user's code has set `no_more' nonzero.  */
469
470   for (i = 0; i < XVECLEN (expand, 1); i++)
471     {
472       rtx next = XVECEXP (expand, 1, i);
473       if ((GET_CODE (next) == SET && GET_CODE (SET_DEST (next)) == PC)
474           || (GET_CODE (next) == PARALLEL
475               && GET_CODE (XVECEXP (next, 0, 0)) == SET
476               && GET_CODE (SET_DEST (XVECEXP (next, 0, 0))) == PC)
477           || GET_CODE (next) == RETURN)
478         printf ("  emit_jump_insn (");
479       else if ((GET_CODE (next) == SET && GET_CODE (SET_SRC (next)) == CALL)
480                || GET_CODE (next) == CALL
481                || (GET_CODE (next) == PARALLEL
482                    && GET_CODE (XVECEXP (next, 0, 0)) == SET
483                    && GET_CODE (SET_SRC (XVECEXP (next, 0, 0))) == CALL)
484                || (GET_CODE (next) == PARALLEL
485                    && GET_CODE (XVECEXP (next, 0, 0)) == CALL))
486         printf ("  emit_call_insn (");
487       else if (GET_CODE (next) == CODE_LABEL)
488         printf ("  emit_label (");
489       else if (GET_CODE (next) == MATCH_OPERAND
490                || GET_CODE (next) == MATCH_OPERATOR
491                || GET_CODE (next) == MATCH_PARALLEL
492                || GET_CODE (next) == MATCH_OP_DUP
493                || GET_CODE (next) == MATCH_DUP
494                || GET_CODE (next) == PARALLEL)
495         printf ("  emit (");
496       else
497         printf ("  emit_insn (");
498       gen_exp (next);
499       printf (");\n");
500       if (GET_CODE (next) == SET && GET_CODE (SET_DEST (next)) == PC
501           && GET_CODE (SET_SRC (next)) == LABEL_REF)
502         printf ("  emit_barrier ();");
503     }
504
505   /* Call `gen_sequence' to make a SEQUENCE out of all the
506      insns emitted within this gen_... function.  */
507
508   printf (" _done:\n");
509   printf ("  _val = gen_sequence ();\n");
510   printf (" _fail:\n");
511   printf ("  end_sequence ();\n");
512   printf ("  return _val;\n}\n\n");
513 }
514
515 /* Like gen_expand, but generates a SEQUENCE.  */
516
517 static void
518 gen_split (split)
519      rtx split;
520 {
521   register int i;
522   int operands;
523
524   if (XVEC (split, 0) == 0)
525     fatal ("define_split (definition %d) lacks a pattern", insn_index_number);
526   else if (XVEC (split, 2) == 0)
527     fatal ("define_split (definition %d) lacks a replacement pattern",
528            insn_index_number);
529
530   /* Find out how many operands this function has.  */
531
532   max_operand_vec (split, 2);
533   operands = MAX (max_opno, max_dup_opno) + 1;
534
535   /* Output the function name and argument declarations.  */
536   printf ("rtx\ngen_split_%d (operands)\n     rtx *operands;\n",
537           insn_code_number);
538   printf ("{\n");
539
540   /* Declare all local variables.  */
541   for (i = 0; i < operands; i++)
542     printf ("  rtx operand%d;\n", i);
543   printf ("  rtx _val = 0;\n");
544   printf ("  start_sequence ();\n");
545
546   /* The fourth operand of DEFINE_SPLIT is some code to be executed
547      before the actual construction.  */
548
549   if (XSTR (split, 3))
550     printf ("%s\n", XSTR (split, 3));
551
552   /* Output code to copy the arguments back out of `operands'  */
553   for (i = 0; i < operands; i++)
554     printf ("  operand%d = operands[%d];\n", i, i);
555
556   /* Output code to construct the rtl for the instruction bodies.
557      Use emit_insn to add them to the sequence being accumulated.
558      But don't do this if the user's code has set `no_more' nonzero.  */
559
560   for (i = 0; i < XVECLEN (split, 2); i++)
561     {
562       rtx next = XVECEXP (split, 2, i);
563       if ((GET_CODE (next) == SET && GET_CODE (SET_DEST (next)) == PC)
564           || (GET_CODE (next) == PARALLEL
565               && GET_CODE (XVECEXP (next, 0, 0)) == SET
566               && GET_CODE (SET_DEST (XVECEXP (next, 0, 0))) == PC)
567           || GET_CODE (next) == RETURN)
568         printf ("  emit_jump_insn (");
569       else if ((GET_CODE (next) == SET && GET_CODE (SET_SRC (next)) == CALL)
570                || GET_CODE (next) == CALL
571                || (GET_CODE (next) == PARALLEL
572                    && GET_CODE (XVECEXP (next, 0, 0)) == SET
573                    && GET_CODE (SET_SRC (XVECEXP (next, 0, 0))) == CALL)
574                || (GET_CODE (next) == PARALLEL
575                    && GET_CODE (XVECEXP (next, 0, 0)) == CALL))
576         printf ("  emit_call_insn (");
577       else if (GET_CODE (next) == CODE_LABEL)
578         printf ("  emit_label (");
579       else if (GET_CODE (next) == MATCH_OPERAND
580                || GET_CODE (next) == MATCH_OPERATOR
581                || GET_CODE (next) == MATCH_PARALLEL
582                || GET_CODE (next) == MATCH_OP_DUP
583                || GET_CODE (next) == MATCH_DUP
584                || GET_CODE (next) == PARALLEL)
585         printf ("  emit (");
586       else
587         printf ("  emit_insn (");
588       gen_exp (next);
589       printf (");\n");
590       if (GET_CODE (next) == SET && GET_CODE (SET_DEST (next)) == PC
591           && GET_CODE (SET_SRC (next)) == LABEL_REF)
592         printf ("  emit_barrier ();");
593     }
594
595   /* Call `gen_sequence' to make a SEQUENCE out of all the
596      insns emitted within this gen_... function.  */
597
598   printf (" _done:\n");
599   printf ("  _val = gen_sequence ();\n");
600   printf (" _fail:\n");
601   printf ("  end_sequence ();\n");
602   printf ("  return _val;\n}\n\n");
603 }
604 \f
605 /* Write a function, `add_clobbers', that is given a PARALLEL of sufficient
606    size for the insn and an INSN_CODE, and inserts the required CLOBBERs at
607    the end of the vector.  */
608
609 static void
610 output_add_clobbers ()
611 {
612   struct clobber_pat *clobber;
613   struct clobber_ent *ent;
614   int i;
615
616   printf ("\n\nvoid\nadd_clobbers (pattern, insn_code_number)\n");
617   printf ("     rtx pattern;\n     int insn_code_number;\n");
618   printf ("{\n");
619   printf ("  int i;\n\n");
620   printf ("  switch (insn_code_number)\n");
621   printf ("    {\n");
622
623   for (clobber = clobber_list; clobber; clobber = clobber->next)
624     {
625       for (ent = clobber->insns; ent; ent = ent->next)
626         printf ("    case %d:\n", ent->code_number);
627
628       for (i = clobber->first_clobber; i < XVECLEN (clobber->pattern, 1); i++)
629         {
630           printf ("      XVECEXP (pattern, 0, %d) = ", i);
631           gen_exp (XVECEXP (clobber->pattern, 1, i));
632           printf (";\n");
633         }
634
635       printf ("      break;\n\n");
636     }
637
638   printf ("    default:\n");
639   printf ("      abort ();\n");
640   printf ("    }\n");
641   printf ("}\n");
642 }
643 \f
644 /* Write a function, init_mov_optab, that is called to set up entries
645    in mov_optab for EXTRA_CC_MODES.  */
646
647 static void
648 output_init_mov_optab ()
649 {
650 #ifdef EXTRA_CC_NAMES
651   static char *cc_names[] = { EXTRA_CC_NAMES };
652   char *p;
653   size_t i;
654
655   printf ("\nvoid\ninit_mov_optab ()\n{\n");
656
657   for (i = 0; i < sizeof cc_names / sizeof cc_names[0]; i++)
658     {
659       printf ("#ifdef HAVE_mov");
660       for (p = cc_names[i]; *p; p++)
661         printf ("%c", *p >= 'A' && *p <= 'Z' ? *p - 'A' + 'a' : *p);
662       printf ("\n");
663       printf ("  if (HAVE_mov");
664       for (p = cc_names[i]; *p; p++)
665         printf ("%c", *p >= 'A' && *p <= 'Z' ? *p - 'A' + 'a' : *p);
666       printf (")\n");
667       printf ("    mov_optab->handlers[(int) %smode].insn_code = CODE_FOR_mov",
668               cc_names[i]);
669       for (p = cc_names[i]; *p; p++)
670         printf ("%c", *p >= 'A' && *p <= 'Z' ? *p - 'A' + 'a' : *p);
671       printf (";\n#endif\n");
672     }
673
674   printf ("}\n");
675 #endif
676 }
677 \f
678 char *
679 xmalloc (size)
680      unsigned size;
681 {
682   register char *val = (char *) malloc (size);
683
684   if (val == 0)
685     fatal ("virtual memory exhausted");
686
687   return val;
688 }
689
690 char *
691 xrealloc (ptr, size)
692      char *ptr;
693      unsigned size;
694 {
695   char *result = (char *) realloc (ptr, size);
696   if (!result)
697     fatal ("virtual memory exhausted");
698   return result;
699 }
700
701 static void
702 fatal (s, a1, a2)
703      char *s;
704 {
705   fprintf (stderr, "genemit: ");
706   fprintf (stderr, s, a1, a2);
707   fprintf (stderr, "\n");
708   exit (FATAL_EXIT_CODE);
709 }
710
711 /* More 'friendly' abort that prints the line and file.
712    config.h can #define abort fancy_abort if you like that sort of thing.  */
713
714 void
715 fancy_abort ()
716 {
717   fatal ("Internal gcc abort.");
718 }
719 \f
720 int
721 main (argc, argv)
722      int argc;
723      char **argv;
724 {
725   rtx desc;
726   FILE *infile;
727   register int c;
728
729   obstack_init (rtl_obstack);
730
731   if (argc <= 1)
732     fatal ("No input file name.");
733
734   infile = fopen (argv[1], "r");
735   if (infile == 0)
736     {
737       perror (argv[1]);
738       exit (FATAL_EXIT_CODE);
739     }
740
741   init_rtl ();
742
743   /* Assign sequential codes to all entries in the machine description
744      in parallel with the tables in insn-output.c.  */
745
746   insn_code_number = 0;
747   insn_index_number = 0;
748
749   printf ("/* Generated automatically by the program `genemit'\n\
750 from the machine description file `md'.  */\n\n");
751
752   printf ("#include \"config.h\"\n");
753   printf ("#include <stdio.h>\n");
754   printf ("#include \"rtl.h\"\n");
755   printf ("#include \"expr.h\"\n");
756   printf ("#include \"real.h\"\n");
757   printf ("#include \"flags.h\"\n");
758   printf ("#include \"output.h\"\n");
759   printf ("#include \"insn-config.h\"\n\n");
760   printf ("#include \"insn-flags.h\"\n\n");
761   printf ("#include \"insn-codes.h\"\n\n");
762   printf ("extern char *insn_operand_constraint[][MAX_RECOG_OPERANDS];\n\n");
763   printf ("extern rtx recog_operand[];\n");
764   printf ("#define operands emit_operand\n\n");
765   printf ("#define FAIL goto _fail\n\n");
766   printf ("#define DONE goto _done\n\n");
767
768   /* Read the machine description.  */
769
770   while (1)
771     {
772       c = read_skip_spaces (infile);
773       if (c == EOF)
774         break;
775       ungetc (c, infile);
776
777       desc = read_rtx (infile);
778       if (GET_CODE (desc) == DEFINE_INSN)
779         {
780           gen_insn (desc);
781           ++insn_code_number;
782         }
783       if (GET_CODE (desc) == DEFINE_EXPAND)
784         {
785           gen_expand (desc);
786           ++insn_code_number;
787         }
788       if (GET_CODE (desc) == DEFINE_SPLIT)
789         {
790           gen_split (desc);
791           ++insn_code_number;
792         }
793       if (GET_CODE (desc) == DEFINE_PEEPHOLE)
794         {
795           ++insn_code_number;
796         }
797       ++insn_index_number;
798     }
799
800   /* Write out the routine to add CLOBBERs to a pattern.  */
801   output_add_clobbers ();
802
803   /* Write the routine to initialize mov_optab for the EXTRA_CC_MODES.  */
804   output_init_mov_optab ();
805
806   fflush (stdout);
807   exit (ferror (stdout) != 0 ? FATAL_EXIT_CODE : SUCCESS_EXIT_CODE);
808   /* NOTREACHED */
809   return 0;
810 }