1/* Generate from machine description:
2
3   - some flags HAVE_... saying which simple standard instructions are
4   available for this machine.
5   Copyright (C) 1987, 1991, 1995, 1998, 1999 Free Software Foundation, Inc.
6
7This file is part of GNU CC.
8
9GNU CC is free software; you can redistribute it and/or modify
10it under the terms of the GNU General Public License as published by
11the Free Software Foundation; either version 2, or (at your option)
12any later version.
13
14GNU CC is distributed in the hope that it will be useful,
15but WITHOUT ANY WARRANTY; without even the implied warranty of
16MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17GNU General Public License for more details.
18
19You should have received a copy of the GNU General Public License
20along with GNU CC; see the file COPYING.  If not, write to
21the Free Software Foundation, 59 Temple Place - Suite 330,
22Boston, MA 02111-1307, USA.  */
23
24
25#include "hconfig.h"
26#include "system.h"
27#include "rtl.h"
28#include "obstack.h"
29
30static struct obstack obstack;
31struct obstack *rtl_obstack = &obstack;
32
33#define obstack_chunk_alloc xmalloc
34#define obstack_chunk_free free
35
36void fatal PVPROTO ((const char *, ...))
37  ATTRIBUTE_PRINTF_1 ATTRIBUTE_NORETURN;
38void fancy_abort PROTO((void)) ATTRIBUTE_NORETURN;
39
40/* Names for patterns.  Need to allow linking with print-rtl.  */
41char **insn_name_ptr;
42
43/* Obstacks to remember normal, and call insns.  */
44static struct obstack call_obstack, normal_obstack;
45
46/* Max size of names encountered.  */
47static int max_id_len;
48
49static int num_operands PROTO((rtx));
50static void gen_proto PROTO((rtx));
51static void gen_nonproto PROTO((rtx));
52static void gen_insn PROTO((rtx));
53
54
55/* Count the number of match_operand's found.  */
56
57static int
58num_operands (x)
59     rtx x;
60{
61  int count = 0;
62  int i, j;
63  enum rtx_code code = GET_CODE (x);
64  char *format_ptr = GET_RTX_FORMAT (code);
65
66  if (code == MATCH_OPERAND)
67    return 1;
68
69  if (code == MATCH_OPERATOR || code == MATCH_PARALLEL)
70    count++;
71
72  for (i = 0; i < GET_RTX_LENGTH (code); i++)
73    {
74      switch (*format_ptr++)
75	{
76	case 'u':
77	case 'e':
78	  count += num_operands (XEXP (x, i));
79	  break;
80
81	case 'E':
82	  if (XVEC (x, i) != NULL)
83	    for (j = 0; j < XVECLEN (x, i); j++)
84	      count += num_operands (XVECEXP (x, i, j));
85
86	  break;
87	}
88    }
89
90  return count;
91}
92
93/* Print out prototype information for a function.  */
94
95static void
96gen_proto (insn)
97     rtx insn;
98{
99  int num = num_operands (insn);
100  printf ("extern rtx gen_%-*s PROTO((", max_id_len, XSTR (insn, 0));
101
102  if (num == 0)
103    printf ("void");
104  else
105    {
106      while (num-- > 1)
107	printf ("rtx, ");
108
109      printf ("rtx");
110    }
111
112  printf ("));\n");
113}
114
115/* Print out a function declaration without a prototype.  */
116
117static void
118gen_nonproto (insn)
119     rtx insn;
120{
121  printf ("extern rtx gen_%s ();\n", XSTR (insn, 0));
122}
123
124static void
125gen_insn (insn)
126     rtx insn;
127{
128  char *name = XSTR (insn, 0);
129  char *p;
130  struct obstack *obstack_ptr;
131  int len;
132
133  /* Don't mention instructions whose names are the null string
134     or begin with '*'.  They are in the machine description just
135     to be recognized.  */
136  if (name[0] == 0 || name[0] == '*')
137    return;
138
139  len = strlen (name);
140
141  if (len > max_id_len)
142    max_id_len = len;
143
144  printf ("#define HAVE_%s ", name);
145  if (strlen (XSTR (insn, 2)) == 0)
146    printf ("1\n");
147  else
148    {
149      /* Write the macro definition, putting \'s at the end of each line,
150	 if more than one.  */
151      printf ("(");
152      for (p = XSTR (insn, 2); *p; p++)
153	{
154	  if (*p == '\n')
155	    printf (" \\\n");
156	  else
157	    printf ("%c", *p);
158	}
159      printf (")\n");
160    }
161
162  /* Save the current insn, so that we can later put out appropriate
163     prototypes.  At present, most md files have the wrong number of
164     arguments for the call insns (call, call_value, call_pop,
165     call_value_pop) ignoring the extra arguments that are passed for
166     some machines, so by default, turn off the prototype.  */
167
168  obstack_ptr = (name[0] == 'c'
169		 && (!strcmp (name, "call")
170		     || !strcmp (name, "call_value")
171		     || !strcmp (name, "call_pop")
172		     || !strcmp (name, "call_value_pop")))
173    ? &call_obstack : &normal_obstack;
174
175  obstack_grow (obstack_ptr, &insn, sizeof (rtx));
176}
177
178PTR
179xmalloc (size)
180  size_t size;
181{
182  register PTR val = (PTR) malloc (size);
183
184  if (val == 0)
185    fatal ("virtual memory exhausted");
186
187  return val;
188}
189
190PTR
191xrealloc (old, size)
192  PTR old;
193  size_t size;
194{
195  register PTR ptr;
196  if (old)
197    ptr = (PTR) realloc (old, size);
198  else
199    ptr = (PTR) malloc (size);
200  if (!ptr)
201    fatal ("virtual memory exhausted");
202  return ptr;
203}
204
205void
206fatal VPROTO ((const char *format, ...))
207{
208#ifndef ANSI_PROTOTYPES
209  const char *format;
210#endif
211  va_list ap;
212
213  VA_START (ap, format);
214
215#ifndef ANSI_PROTOTYPES
216  format = va_arg (ap, const char *);
217#endif
218
219  fprintf (stderr, "genflags: ");
220  vfprintf (stderr, format, ap);
221  va_end (ap);
222  fprintf (stderr, "\n");
223  exit (FATAL_EXIT_CODE);
224}
225
226/* More 'friendly' abort that prints the line and file.
227   config.h can #define abort fancy_abort if you like that sort of thing.  */
228
229void
230fancy_abort ()
231{
232  fatal ("Internal gcc abort.");
233}
234
235int
236main (argc, argv)
237     int argc;
238     char **argv;
239{
240  rtx desc;
241  rtx dummy;
242  rtx *call_insns;
243  rtx *normal_insns;
244  rtx *insn_ptr;
245  FILE *infile;
246  register int c;
247
248  obstack_init (rtl_obstack);
249  obstack_init (&call_obstack);
250  obstack_init (&normal_obstack);
251
252  if (argc <= 1)
253    fatal ("No input file name.");
254
255  infile = fopen (argv[1], "r");
256  if (infile == 0)
257    {
258      perror (argv[1]);
259      exit (FATAL_EXIT_CODE);
260    }
261
262  init_rtl ();
263
264  printf ("/* Generated automatically by the program `genflags'\n\
265from the machine description file `md'.  */\n\n");
266
267  /* Read the machine description.  */
268
269  while (1)
270    {
271      c = read_skip_spaces (infile);
272      if (c == EOF)
273	break;
274      ungetc (c, infile);
275
276      desc = read_rtx (infile);
277      if (GET_CODE (desc) == DEFINE_INSN || GET_CODE (desc) == DEFINE_EXPAND)
278	gen_insn (desc);
279    }
280
281  /* Print out the prototypes now.  */
282  dummy = (rtx) 0;
283  obstack_grow (&call_obstack, &dummy, sizeof (rtx));
284  call_insns = (rtx *) obstack_finish (&call_obstack);
285
286  obstack_grow (&normal_obstack, &dummy, sizeof (rtx));
287  normal_insns = (rtx *) obstack_finish (&normal_obstack);
288
289  printf ("\n#ifndef NO_MD_PROTOTYPES\n");
290  for (insn_ptr = normal_insns; *insn_ptr; insn_ptr++)
291    gen_proto (*insn_ptr);
292
293  printf ("\n#ifdef MD_CALL_PROTOTYPES\n");
294  for (insn_ptr = call_insns; *insn_ptr; insn_ptr++)
295    gen_proto (*insn_ptr);
296
297  printf ("\n#else /* !MD_CALL_PROTOTYPES */\n");
298  for (insn_ptr = call_insns; *insn_ptr; insn_ptr++)
299    gen_nonproto (*insn_ptr);
300
301  printf ("#endif /* !MD_CALL_PROTOTYPES */\n");
302  printf ("\n#else  /* NO_MD_PROTOTYPES */\n");
303  for (insn_ptr = normal_insns; *insn_ptr; insn_ptr++)
304    gen_nonproto (*insn_ptr);
305
306  for (insn_ptr = call_insns; *insn_ptr; insn_ptr++)
307    gen_nonproto (*insn_ptr);
308
309  printf ("#endif  /* NO_MD_PROTOTYPES */\n");
310
311  fflush (stdout);
312  exit (ferror (stdout) != 0 ? FATAL_EXIT_CODE : SUCCESS_EXIT_CODE);
313  /* NOTREACHED */
314  return 0;
315}
316