genflags.c revision 90075
1/* Generate from machine description:
2   - some flags HAVE_... saying which simple standard instructions are
3   available for this machine.
4   Copyright (C) 1987, 1991, 1995, 1998,
5   1999, 2000 Free Software Foundation, Inc.
6
7This file is part of GCC.
8
9GCC is free software; you can redistribute it and/or modify it under
10the terms of the GNU General Public License as published by the Free
11Software Foundation; either version 2, or (at your option) any later
12version.
13
14GCC is distributed in the hope that it will be useful, but WITHOUT ANY
15WARRANTY; without even the implied warranty of MERCHANTABILITY or
16FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
17for more details.
18
19You should have received a copy of the GNU General Public License
20along with GCC; see the file COPYING.  If not, write to the Free
21Software Foundation, 59 Temple Place - Suite 330, Boston, MA
2202111-1307, USA.  */
23
24
25#include "hconfig.h"
26#include "system.h"
27#include "rtl.h"
28#include "obstack.h"
29#include "errors.h"
30#include "gensupport.h"
31
32
33#define obstack_chunk_alloc xmalloc
34#define obstack_chunk_free free
35
36/* Obstack to remember insns with.  */
37static struct obstack obstack;
38
39/* Max size of names encountered.  */
40static int max_id_len;
41
42/* Max operand encountered in a scan over some insn.  */
43static int max_opno;
44
45static void max_operand_1	PARAMS ((rtx));
46static int num_operands		PARAMS ((rtx));
47static void gen_proto		PARAMS ((rtx));
48static void gen_macro		PARAMS ((const char *, int, int));
49static void gen_insn		PARAMS ((rtx));
50
51/* Count the number of match_operand's found.  */
52
53static void
54max_operand_1 (x)
55     rtx x;
56{
57  RTX_CODE code;
58  int i;
59  int len;
60  const char *fmt;
61
62  if (x == 0)
63    return;
64
65  code = GET_CODE (x);
66
67  if (code == MATCH_OPERAND || code == MATCH_OPERATOR
68      || code == MATCH_PARALLEL)
69    max_opno = MAX (max_opno, XINT (x, 0));
70
71  fmt = GET_RTX_FORMAT (code);
72  len = GET_RTX_LENGTH (code);
73  for (i = 0; i < len; i++)
74    {
75      if (fmt[i] == 'e' || fmt[i] == 'u')
76	max_operand_1 (XEXP (x, i));
77      else if (fmt[i] == 'E')
78	{
79	  int j;
80	  for (j = 0; j < XVECLEN (x, i); j++)
81	    max_operand_1 (XVECEXP (x, i, j));
82	}
83    }
84}
85
86static int
87num_operands (insn)
88     rtx insn;
89{
90  int len = XVECLEN (insn, 1);
91  int i;
92
93  max_opno = -1;
94
95  for (i = 0; i < len; i++)
96    max_operand_1 (XVECEXP (insn, 1, i));
97
98  return max_opno + 1;
99}
100
101/* Print out a wrapper macro for a function which corrects the number
102   of arguments it takes.  Any missing arguments are assumed to be at
103   the end.  */
104static void
105gen_macro (name, real, expect)
106     const char *name;
107     int real, expect;
108{
109  int i;
110
111  if (real > expect)
112    abort ();
113  if (real == 0)
114    abort ();
115
116  /* #define GEN_CALL(A, B, C, D) gen_call((A), (B)) */
117  fputs ("#define GEN_", stdout);
118  for (i = 0; name[i]; i++)
119    putchar (TOUPPER (name[i]));
120
121  putchar('(');
122  for (i = 0; i < expect - 1; i++)
123    printf ("%c, ", i + 'A');
124  printf ("%c) gen_%s (", i + 'A', name);
125
126  for (i = 0; i < real - 1; i++)
127    printf ("(%c), ", i + 'A');
128  printf ("(%c))\n", i + 'A');
129}
130
131/* Print out prototype information for a function.  */
132
133static void
134gen_proto (insn)
135     rtx insn;
136{
137  int num = num_operands (insn);
138  const char *name = XSTR (insn, 0);
139
140  /* Many md files don't refer to the last two operands passed to the
141     call patterns.  This means their generator functions will be two
142     arguments too short.  Instead of changing every md file to touch
143     those operands, we wrap the prototypes in macros that take the
144     correct number of arguments.  */
145  if (name[0] == 'c' || name[0] == 's')
146    {
147      if (!strcmp (name, "call")
148	  || !strcmp (name, "call_pop")
149	  || !strcmp (name, "sibcall")
150	  || !strcmp (name, "sibcall_pop"))
151	gen_macro (name, num, 4);
152      else if (!strcmp (name, "call_value")
153	       || !strcmp (name, "call_value_pop")
154	       || !strcmp (name, "sibcall_value")
155	       || !strcmp (name, "sibcall_value_pop"))
156	gen_macro (name, num, 5);
157    }
158
159  printf ("extern struct rtx_def *gen_%-*s PARAMS ((", max_id_len, name);
160
161  if (num == 0)
162    printf ("void");
163  else
164    {
165      while (num-- > 1)
166	printf ("struct rtx_def *, ");
167
168      printf ("struct rtx_def *");
169    }
170
171  printf ("));\n");
172
173}
174
175static void
176gen_insn (insn)
177     rtx insn;
178{
179  const char *name = XSTR (insn, 0);
180  const char *p;
181  int len;
182
183  /* Don't mention instructions whose names are the null string
184     or begin with '*'.  They are in the machine description just
185     to be recognized.  */
186  if (name[0] == 0 || name[0] == '*')
187    return;
188
189  len = strlen (name);
190
191  if (len > max_id_len)
192    max_id_len = len;
193
194  printf ("#define HAVE_%s ", name);
195  if (strlen (XSTR (insn, 2)) == 0)
196    printf ("1\n");
197  else
198    {
199      /* Write the macro definition, putting \'s at the end of each line,
200	 if more than one.  */
201      printf ("(");
202      for (p = XSTR (insn, 2); *p; p++)
203	{
204	  if (*p == '\n')
205	    printf (" \\\n");
206	  else
207	    printf ("%c", *p);
208	}
209      printf (")\n");
210    }
211
212  obstack_grow (&obstack, &insn, sizeof (rtx));
213}
214
215extern int main PARAMS ((int, char **));
216
217int
218main (argc, argv)
219     int argc;
220     char **argv;
221{
222  rtx desc;
223  rtx dummy;
224  rtx *insns;
225  rtx *insn_ptr;
226
227  progname = "genflags";
228  obstack_init (&obstack);
229
230  if (argc <= 1)
231    fatal ("no input file name");
232
233  if (init_md_reader_args (argc, argv) != SUCCESS_EXIT_CODE)
234    return (FATAL_EXIT_CODE);
235
236  puts ("/* Generated automatically by the program `genflags'");
237  puts ("   from the machine description file `md'.  */\n");
238  puts ("#ifndef GCC_INSN_FLAGS_H");
239  puts ("#define GCC_INSN_FLAGS_H\n");
240
241  /* Read the machine description.  */
242
243  while (1)
244    {
245      int line_no, insn_code_number = 0;
246
247      desc = read_md_rtx (&line_no, &insn_code_number);
248      if (desc == NULL)
249	break;
250      if (GET_CODE (desc) == DEFINE_INSN || GET_CODE (desc) == DEFINE_EXPAND)
251	gen_insn (desc);
252    }
253
254  /* Print out the prototypes now.  */
255  dummy = (rtx) 0;
256  obstack_grow (&obstack, &dummy, sizeof (rtx));
257  insns = (rtx *) obstack_finish (&obstack);
258
259  printf ("struct rtx_def;\n");
260  for (insn_ptr = insns; *insn_ptr; insn_ptr++)
261    gen_proto (*insn_ptr);
262
263  puts("\n#endif /* GCC_INSN_FLAGS_H */");
264
265  if (ferror (stdout) || fflush (stdout) || fclose (stdout))
266    return FATAL_EXIT_CODE;
267
268  return SUCCESS_EXIT_CODE;
269}
270
271/* Define this so we can link with print-rtl.o to get debug_rtx function.  */
272const char *
273get_insn_name (code)
274     int code ATTRIBUTE_UNUSED;
275{
276  return NULL;
277}
278