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