OSDN Git Service

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