OSDN Git Service

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