xref: /netbsd/external/gpl3/gcc/dist/gcc/genextract.c (revision dd083157)
1c3d31fe1Smrg /* Generate code from machine description to extract operands from insn as rtl.
2*dd083157Smrg    Copyright (C) 1987-2020 Free Software Foundation, Inc.
3c3d31fe1Smrg 
4c3d31fe1Smrg This file is part of GCC.
5c3d31fe1Smrg 
6c3d31fe1Smrg GCC is free software; you can redistribute it and/or modify it under
7c3d31fe1Smrg the terms of the GNU General Public License as published by the Free
8c3d31fe1Smrg Software Foundation; either version 3, or (at your option) any later
9c3d31fe1Smrg version.
10c3d31fe1Smrg 
11c3d31fe1Smrg GCC is distributed in the hope that it will be useful, but WITHOUT ANY
12c3d31fe1Smrg WARRANTY; without even the implied warranty of MERCHANTABILITY or
13c3d31fe1Smrg FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
14c3d31fe1Smrg for more details.
15c3d31fe1Smrg 
16c3d31fe1Smrg You should have received a copy of the GNU General Public License
17c3d31fe1Smrg along with GCC; see the file COPYING3.  If not see
18c3d31fe1Smrg <http://www.gnu.org/licenses/>.  */
19c3d31fe1Smrg 
20c3d31fe1Smrg 
21c3d31fe1Smrg #include "bconfig.h"
22c3d31fe1Smrg #include "system.h"
23c3d31fe1Smrg #include "coretypes.h"
24c3d31fe1Smrg #include "tm.h"
25c3d31fe1Smrg #include "rtl.h"
26c3d31fe1Smrg #include "errors.h"
27af526226Smrg #include "read-md.h"
28c3d31fe1Smrg #include "gensupport.h"
29c3d31fe1Smrg 
30c3d31fe1Smrg /* This structure contains all the information needed to describe one
31c3d31fe1Smrg    set of extractions methods.  Each method may be used by more than
32c3d31fe1Smrg    one pattern if the operands are in the same place.
33c3d31fe1Smrg 
34c3d31fe1Smrg    The string for each operand describes that path to the operand and
35c3d31fe1Smrg    contains `0' through `9' when going into an expression and `a' through
363903d7f3Smrg    `z' then 'A' through to 'Z' when going into a vector.  We assume here that
373903d7f3Smrg    only the first operand of an rtl expression is a vector.  genrecog.c makes
383903d7f3Smrg    the same assumption (and uses the same representation) and it is currently
393903d7f3Smrg    true.  */
40c3d31fe1Smrg 
41c3d31fe1Smrg typedef char *locstr;
42c3d31fe1Smrg 
43c3d31fe1Smrg struct extraction
44c3d31fe1Smrg {
45c3d31fe1Smrg   unsigned int op_count;
46c3d31fe1Smrg   unsigned int dup_count;
47c3d31fe1Smrg   locstr *oplocs;
48c3d31fe1Smrg   locstr *duplocs;
49c3d31fe1Smrg   int *dupnums;
50c3d31fe1Smrg   struct code_ptr *insns;
51c3d31fe1Smrg   struct extraction *next;
52c3d31fe1Smrg };
53c3d31fe1Smrg 
54c3d31fe1Smrg /* Holds a single insn code that uses an extraction method.  */
55c3d31fe1Smrg struct code_ptr
56c3d31fe1Smrg {
57c3d31fe1Smrg   int insn_code;
58c3d31fe1Smrg   struct code_ptr *next;
59c3d31fe1Smrg };
60c3d31fe1Smrg 
61c3d31fe1Smrg /* All extractions needed for this machine description.  */
62c3d31fe1Smrg static struct extraction *extractions;
63c3d31fe1Smrg 
64c3d31fe1Smrg /* All insn codes for old-style peepholes.  */
65c3d31fe1Smrg static struct code_ptr *peepholes;
66c3d31fe1Smrg 
67c3d31fe1Smrg /* This structure is used by gen_insn and walk_rtx to accumulate the
68c3d31fe1Smrg    data that will be used to produce an extractions structure.  */
69c3d31fe1Smrg 
70c3d31fe1Smrg 
71*dd083157Smrg class accum_extract
72c3d31fe1Smrg {
73*dd083157Smrg public:
accum_extract()746a5c9aabSmrg   accum_extract () : oplocs (10), duplocs (10), dupnums (10), pathstr (20) {}
756a5c9aabSmrg 
766a5c9aabSmrg   auto_vec<locstr> oplocs;
776a5c9aabSmrg   auto_vec<locstr> duplocs;
786a5c9aabSmrg   auto_vec<int> dupnums;
796a5c9aabSmrg   auto_vec<char> pathstr;
80c3d31fe1Smrg };
81c3d31fe1Smrg 
82c3d31fe1Smrg /* Forward declarations.  */
83*dd083157Smrg static void walk_rtx (md_rtx_info *, rtx, class accum_extract *);
84c3d31fe1Smrg 
853903d7f3Smrg #define UPPER_OFFSET ('A' - ('z' - 'a' + 1))
863903d7f3Smrg 
873903d7f3Smrg /* Convert integer OPERAND into a character - either into [a-zA-Z] for vector
883903d7f3Smrg    operands or [0-9] for integer operands - and push onto the end of the path
893903d7f3Smrg    in ACC.  */
903903d7f3Smrg static void
push_pathstr_operand(int operand,bool is_vector,class accum_extract * acc)913903d7f3Smrg push_pathstr_operand (int operand, bool is_vector,
92*dd083157Smrg 		     class accum_extract *acc)
933903d7f3Smrg {
943903d7f3Smrg   if (is_vector && 'a' + operand > 'z')
953903d7f3Smrg     acc->pathstr.safe_push (operand + UPPER_OFFSET);
963903d7f3Smrg   else if (is_vector)
973903d7f3Smrg     acc->pathstr.safe_push (operand + 'a');
983903d7f3Smrg   else
993903d7f3Smrg     acc->pathstr.safe_push (operand + '0');
1003903d7f3Smrg }
1013903d7f3Smrg 
102c3d31fe1Smrg static void
gen_insn(md_rtx_info * info)10363aace61Smrg gen_insn (md_rtx_info *info)
104c3d31fe1Smrg {
105c3d31fe1Smrg   int i;
106c3d31fe1Smrg   unsigned int op_count, dup_count, j;
107c3d31fe1Smrg   struct extraction *p;
108c3d31fe1Smrg   struct code_ptr *link;
109*dd083157Smrg   class accum_extract acc;
110c3d31fe1Smrg 
111c3d31fe1Smrg   /* Walk the insn's pattern, remembering at all times the path
112c3d31fe1Smrg      down to the walking point.  */
113c3d31fe1Smrg 
11463aace61Smrg   rtx insn = info->def;
115c3d31fe1Smrg   if (XVECLEN (insn, 1) == 1)
11663aace61Smrg     walk_rtx (info, XVECEXP (insn, 1, 0), &acc);
117c3d31fe1Smrg   else
118c3d31fe1Smrg     for (i = XVECLEN (insn, 1) - 1; i >= 0; i--)
119c3d31fe1Smrg       {
1203903d7f3Smrg 	push_pathstr_operand (i, true, &acc);
12163aace61Smrg 	walk_rtx (info, XVECEXP (insn, 1, i), &acc);
122af526226Smrg 	acc.pathstr.pop ();
123c3d31fe1Smrg       }
124c3d31fe1Smrg 
125c3d31fe1Smrg   link = XNEW (struct code_ptr);
12663aace61Smrg   link->insn_code = info->index;
127c3d31fe1Smrg 
128c3d31fe1Smrg   /* See if we find something that already had this extraction method.  */
129c3d31fe1Smrg 
130af526226Smrg   op_count = acc.oplocs.length ();
131af526226Smrg   dup_count = acc.duplocs.length ();
132af526226Smrg   gcc_assert (dup_count == acc.dupnums.length ());
133c3d31fe1Smrg 
134c3d31fe1Smrg   for (p = extractions; p; p = p->next)
135c3d31fe1Smrg     {
136c3d31fe1Smrg       if (p->op_count != op_count || p->dup_count != dup_count)
137c3d31fe1Smrg 	continue;
138c3d31fe1Smrg 
139c3d31fe1Smrg       for (j = 0; j < op_count; j++)
140c3d31fe1Smrg 	{
141c3d31fe1Smrg 	  char *a = p->oplocs[j];
142af526226Smrg 	  char *b = acc.oplocs[j];
143c3d31fe1Smrg 	  if (a != b && (!a || !b || strcmp (a, b)))
144c3d31fe1Smrg 	    break;
145c3d31fe1Smrg 	}
146c3d31fe1Smrg 
147c3d31fe1Smrg       if (j != op_count)
148c3d31fe1Smrg 	continue;
149c3d31fe1Smrg 
150c3d31fe1Smrg       for (j = 0; j < dup_count; j++)
151af526226Smrg 	if (p->dupnums[j] != acc.dupnums[j]
152af526226Smrg 	    || strcmp (p->duplocs[j], acc.duplocs[j]))
153c3d31fe1Smrg 	  break;
154c3d31fe1Smrg 
155c3d31fe1Smrg       if (j != dup_count)
156c3d31fe1Smrg 	continue;
157c3d31fe1Smrg 
158c3d31fe1Smrg       /* This extraction is the same as ours.  Just link us in.  */
159c3d31fe1Smrg       link->next = p->insns;
160c3d31fe1Smrg       p->insns = link;
1616a5c9aabSmrg       return;
162c3d31fe1Smrg     }
163c3d31fe1Smrg 
164c3d31fe1Smrg   /* Otherwise, make a new extraction method.  We stash the arrays
165c3d31fe1Smrg      after the extraction structure in memory.  */
166c3d31fe1Smrg 
167c3d31fe1Smrg   p = XNEWVAR (struct extraction, sizeof (struct extraction)
168c3d31fe1Smrg 	       + op_count*sizeof (char *)
169c3d31fe1Smrg 	       + dup_count*sizeof (char *)
170c3d31fe1Smrg 	       + dup_count*sizeof (int));
171c3d31fe1Smrg   p->op_count = op_count;
172c3d31fe1Smrg   p->dup_count = dup_count;
173c3d31fe1Smrg   p->next = extractions;
174c3d31fe1Smrg   extractions = p;
175c3d31fe1Smrg   p->insns = link;
176c3d31fe1Smrg   link->next = 0;
177c3d31fe1Smrg 
178c3d31fe1Smrg   p->oplocs = (char **)((char *)p + sizeof (struct extraction));
179c3d31fe1Smrg   p->duplocs = p->oplocs + op_count;
180c3d31fe1Smrg   p->dupnums = (int *)(p->duplocs + dup_count);
181c3d31fe1Smrg 
182af526226Smrg   memcpy (p->oplocs, acc.oplocs.address (), op_count * sizeof (locstr));
183af526226Smrg   memcpy (p->duplocs, acc.duplocs.address (), dup_count * sizeof (locstr));
184af526226Smrg   memcpy (p->dupnums, acc.dupnums.address (), dup_count * sizeof (int));
185c3d31fe1Smrg }
186c3d31fe1Smrg 
187af526226Smrg /* Helper subroutine of walk_rtx: given a vec<locstr>, an index, and a
188c3d31fe1Smrg    string, insert the string at the index, which should either already
189c3d31fe1Smrg    exist and be NULL, or not yet exist within the vector.  In the latter
19063aace61Smrg    case the vector is enlarged as appropriate.  INFO describes the
19163aace61Smrg    containing define_* expression.  */
192c3d31fe1Smrg static void
VEC_safe_set_locstr(md_rtx_info * info,vec<locstr> * vp,unsigned int ix,char * str)19363aace61Smrg VEC_safe_set_locstr (md_rtx_info *info, vec<locstr> *vp,
19463aace61Smrg 		     unsigned int ix, char *str)
195c3d31fe1Smrg {
196af526226Smrg   if (ix < (*vp).length ())
197c3d31fe1Smrg     {
198af526226Smrg       if ((*vp)[ix])
199c3d31fe1Smrg 	{
20063aace61Smrg 	  message_at (info->loc, "repeated operand number %d", ix);
201c3d31fe1Smrg 	  have_error = 1;
202c3d31fe1Smrg 	}
203c3d31fe1Smrg       else
204af526226Smrg         (*vp)[ix] = str;
205c3d31fe1Smrg     }
206c3d31fe1Smrg   else
207c3d31fe1Smrg     {
208af526226Smrg       while (ix > (*vp).length ())
209af526226Smrg 	vp->safe_push (NULL);
210af526226Smrg       vp->safe_push (str);
211c3d31fe1Smrg     }
212c3d31fe1Smrg }
213c3d31fe1Smrg 
214af526226Smrg /* Another helper subroutine of walk_rtx: given a vec<char>, convert it
215c3d31fe1Smrg    to a NUL-terminated string in malloc memory.  */
216c3d31fe1Smrg static char *
VEC_char_to_string(vec<char> v)217af526226Smrg VEC_char_to_string (vec<char> v)
218c3d31fe1Smrg {
219af526226Smrg   size_t n = v.length ();
220c3d31fe1Smrg   char *s = XNEWVEC (char, n + 1);
221af526226Smrg   memcpy (s, v.address (), n);
222c3d31fe1Smrg   s[n] = '\0';
223c3d31fe1Smrg   return s;
224c3d31fe1Smrg }
225c3d31fe1Smrg 
226c3d31fe1Smrg static void
walk_rtx(md_rtx_info * info,rtx x,class accum_extract * acc)227*dd083157Smrg walk_rtx (md_rtx_info *info, rtx x, class accum_extract *acc)
228c3d31fe1Smrg {
229c3d31fe1Smrg   RTX_CODE code;
2303903d7f3Smrg   int i, len;
231c3d31fe1Smrg   const char *fmt;
232c3d31fe1Smrg 
233c3d31fe1Smrg   if (x == 0)
234c3d31fe1Smrg     return;
235c3d31fe1Smrg 
236c3d31fe1Smrg   code = GET_CODE (x);
237c3d31fe1Smrg   switch (code)
238c3d31fe1Smrg     {
239c3d31fe1Smrg     case PC:
240c3d31fe1Smrg     case CC0:
241c3d31fe1Smrg     case CONST_INT:
242c3d31fe1Smrg     case SYMBOL_REF:
243c3d31fe1Smrg       return;
244c3d31fe1Smrg 
245c3d31fe1Smrg     case MATCH_OPERAND:
246c3d31fe1Smrg     case MATCH_SCRATCH:
24763aace61Smrg       VEC_safe_set_locstr (info, &acc->oplocs, XINT (x, 0),
248c3d31fe1Smrg 			   VEC_char_to_string (acc->pathstr));
249c3d31fe1Smrg       break;
250c3d31fe1Smrg 
251c3d31fe1Smrg     case MATCH_OPERATOR:
252c3d31fe1Smrg     case MATCH_PARALLEL:
25363aace61Smrg       VEC_safe_set_locstr (info, &acc->oplocs, XINT (x, 0),
254c3d31fe1Smrg 			   VEC_char_to_string (acc->pathstr));
255c3d31fe1Smrg 
256c3d31fe1Smrg       for (i = XVECLEN (x, 2) - 1; i >= 0; i--)
257c3d31fe1Smrg 	{
2583903d7f3Smrg 	  push_pathstr_operand (i, code != MATCH_OPERATOR, acc);
25963aace61Smrg 	  walk_rtx (info, XVECEXP (x, 2, i), acc);
260af526226Smrg 	  acc->pathstr.pop ();
261c3d31fe1Smrg         }
262c3d31fe1Smrg       return;
263c3d31fe1Smrg 
264c3d31fe1Smrg     case MATCH_DUP:
265c3d31fe1Smrg     case MATCH_PAR_DUP:
266c3d31fe1Smrg     case MATCH_OP_DUP:
267af526226Smrg       acc->duplocs.safe_push (VEC_char_to_string (acc->pathstr));
268af526226Smrg       acc->dupnums.safe_push (XINT (x, 0));
269c3d31fe1Smrg 
270c3d31fe1Smrg       if (code == MATCH_DUP)
271c3d31fe1Smrg 	break;
272c3d31fe1Smrg 
273c3d31fe1Smrg       for (i = XVECLEN (x, 1) - 1; i >= 0; i--)
274c3d31fe1Smrg         {
2753903d7f3Smrg 	  push_pathstr_operand (i, code != MATCH_OP_DUP, acc);
27663aace61Smrg 	  walk_rtx (info, XVECEXP (x, 1, i), acc);
277af526226Smrg 	  acc->pathstr.pop ();
278c3d31fe1Smrg         }
279c3d31fe1Smrg       return;
280c3d31fe1Smrg 
281c3d31fe1Smrg     default:
282c3d31fe1Smrg       break;
283c3d31fe1Smrg     }
284c3d31fe1Smrg 
285c3d31fe1Smrg   fmt = GET_RTX_FORMAT (code);
286c3d31fe1Smrg   len = GET_RTX_LENGTH (code);
287c3d31fe1Smrg   for (i = 0; i < len; i++)
288c3d31fe1Smrg     {
289c3d31fe1Smrg       if (fmt[i] == 'e' || fmt[i] == 'u')
290c3d31fe1Smrg 	{
2913903d7f3Smrg 	  push_pathstr_operand (i, false, acc);
29263aace61Smrg 	  walk_rtx (info, XEXP (x, i), acc);
293af526226Smrg 	  acc->pathstr.pop ();
294c3d31fe1Smrg 	}
295c3d31fe1Smrg       else if (fmt[i] == 'E')
296c3d31fe1Smrg 	{
297c3d31fe1Smrg 	  int j;
298c3d31fe1Smrg 	  for (j = XVECLEN (x, i) - 1; j >= 0; j--)
299c3d31fe1Smrg 	    {
3003903d7f3Smrg 	      push_pathstr_operand (j, true, acc);
30163aace61Smrg 	      walk_rtx (info, XVECEXP (x, i, j), acc);
302af526226Smrg 	      acc->pathstr.pop ();
303c3d31fe1Smrg 	    }
304c3d31fe1Smrg 	}
305c3d31fe1Smrg     }
306c3d31fe1Smrg }
307c3d31fe1Smrg 
308c3d31fe1Smrg /* Given a PATH, representing a path down the instruction's
309c3d31fe1Smrg    pattern from the root to a certain point, output code to
310c3d31fe1Smrg    evaluate to the rtx at that point.  */
311c3d31fe1Smrg 
312c3d31fe1Smrg static void
print_path(const char * path)313c3d31fe1Smrg print_path (const char *path)
314c3d31fe1Smrg {
315c3d31fe1Smrg   int len = strlen (path);
316c3d31fe1Smrg   int i;
317c3d31fe1Smrg 
318c3d31fe1Smrg   if (len == 0)
319c3d31fe1Smrg     {
320c3d31fe1Smrg       /* Don't emit "pat", since we may try to take the address of it,
321c3d31fe1Smrg 	 which isn't what is intended.  */
322c3d31fe1Smrg       fputs ("PATTERN (insn)", stdout);
323c3d31fe1Smrg       return;
324c3d31fe1Smrg     }
325c3d31fe1Smrg 
326c3d31fe1Smrg   /* We first write out the operations (XEXP or XVECEXP) in reverse
327c3d31fe1Smrg      order, then write "pat", then the indices in forward order.  */
328c3d31fe1Smrg 
329c3d31fe1Smrg   for (i = len - 1; i >= 0 ; i--)
330c3d31fe1Smrg     {
3313903d7f3Smrg       if (ISLOWER (path[i]) || ISUPPER (path[i]))
332c3d31fe1Smrg 	fputs ("XVECEXP (", stdout);
333c3d31fe1Smrg       else if (ISDIGIT (path[i]))
334c3d31fe1Smrg 	fputs ("XEXP (", stdout);
335c3d31fe1Smrg       else
336c3d31fe1Smrg 	gcc_unreachable ();
337c3d31fe1Smrg     }
338c3d31fe1Smrg 
339c3d31fe1Smrg   fputs ("pat", stdout);
340c3d31fe1Smrg 
341c3d31fe1Smrg   for (i = 0; i < len; i++)
342c3d31fe1Smrg     {
3433903d7f3Smrg       if (ISUPPER (path[i]))
3443903d7f3Smrg 	printf (", 0, %d)", path[i] - UPPER_OFFSET);
3453903d7f3Smrg       else if (ISLOWER (path[i]))
346c3d31fe1Smrg 	printf (", 0, %d)", path[i] - 'a');
347c3d31fe1Smrg       else if (ISDIGIT (path[i]))
348c3d31fe1Smrg 	printf (", %d)", path[i] - '0');
349c3d31fe1Smrg       else
350c3d31fe1Smrg 	gcc_unreachable ();
351c3d31fe1Smrg     }
352c3d31fe1Smrg }
353c3d31fe1Smrg 
354c3d31fe1Smrg static void
print_header(void)355c3d31fe1Smrg print_header (void)
356c3d31fe1Smrg {
357c3d31fe1Smrg   /* N.B. Code below avoids putting squiggle braces in column 1 inside
358c3d31fe1Smrg      a string, because this confuses some editors' syntax highlighting
359c3d31fe1Smrg      engines.  */
360c3d31fe1Smrg 
361c3d31fe1Smrg   puts ("\
362c3d31fe1Smrg /* Generated automatically by the program `genextract'\n\
363c3d31fe1Smrg    from the machine description file `md'.  */\n\
364c3d31fe1Smrg \n\
3653903d7f3Smrg #define IN_TARGET_CODE 1\n\
366c3d31fe1Smrg #include \"config.h\"\n\
367c3d31fe1Smrg #include \"system.h\"\n\
368c3d31fe1Smrg #include \"coretypes.h\"\n\
369c3d31fe1Smrg #include \"tm.h\"\n\
370c3d31fe1Smrg #include \"rtl.h\"\n\
371c3d31fe1Smrg #include \"insn-config.h\"\n\
372c3d31fe1Smrg #include \"recog.h\"\n\
373af526226Smrg #include \"diagnostic-core.h\"\n\
374c3d31fe1Smrg \n\
375c3d31fe1Smrg /* This variable is used as the \"location\" of any missing operand\n\
376c3d31fe1Smrg    whose numbers are skipped by a given pattern.  */\n\
377c3d31fe1Smrg static rtx junk ATTRIBUTE_UNUSED;\n");
378c3d31fe1Smrg 
379c3d31fe1Smrg   puts ("\
380c3d31fe1Smrg void\n\
3815ef59e75Smrg insn_extract (rtx_insn *insn)\n{\n\
382c3d31fe1Smrg   rtx *ro = recog_data.operand;\n\
383c3d31fe1Smrg   rtx **ro_loc = recog_data.operand_loc;\n\
384c3d31fe1Smrg   rtx pat = PATTERN (insn);\n\
385c3d31fe1Smrg   int i ATTRIBUTE_UNUSED; /* only for peepholes */\n\
386c3d31fe1Smrg \n\
38763aace61Smrg   if (flag_checking)\n\
38863aace61Smrg     {\n\
389c3d31fe1Smrg       memset (ro, 0xab, sizeof (*ro) * MAX_RECOG_OPERANDS);\n\
390c3d31fe1Smrg       memset (ro_loc, 0xab, sizeof (*ro_loc) * MAX_RECOG_OPERANDS);\n\
39163aace61Smrg     }\n");
392c3d31fe1Smrg 
393c3d31fe1Smrg   puts ("\
394c3d31fe1Smrg   switch (INSN_CODE (insn))\n\
395c3d31fe1Smrg     {\n\
396c3d31fe1Smrg     default:\n\
397c3d31fe1Smrg       /* Control reaches here if insn_extract has been called with an\n\
398c3d31fe1Smrg          unrecognizable insn (code -1), or an insn whose INSN_CODE\n\
399c3d31fe1Smrg          corresponds to a DEFINE_EXPAND in the machine description;\n\
400c3d31fe1Smrg          either way, a bug.  */\n\
401c3d31fe1Smrg       if (INSN_CODE (insn) < 0)\n\
402c3d31fe1Smrg         fatal_insn (\"unrecognizable insn:\", insn);\n\
403c3d31fe1Smrg       else\n\
404c3d31fe1Smrg         fatal_insn (\"insn with invalid code number:\", insn);\n");
405c3d31fe1Smrg }
406c3d31fe1Smrg 
407c3d31fe1Smrg int
main(int argc,const char ** argv)4086a5c9aabSmrg main (int argc, const char **argv)
409c3d31fe1Smrg {
410c3d31fe1Smrg   unsigned int i;
411c3d31fe1Smrg   struct extraction *p;
412c3d31fe1Smrg   struct code_ptr *link;
413c3d31fe1Smrg   const char *name;
414c3d31fe1Smrg 
415c3d31fe1Smrg   progname = "genextract";
416c3d31fe1Smrg 
417af526226Smrg   if (!init_rtx_reader_args (argc, argv))
418c3d31fe1Smrg     return (FATAL_EXIT_CODE);
419c3d31fe1Smrg 
420c3d31fe1Smrg   /* Read the machine description.  */
421c3d31fe1Smrg 
42263aace61Smrg   md_rtx_info info;
42363aace61Smrg   while (read_md_rtx (&info))
42463aace61Smrg     switch (GET_CODE (info.def))
425c3d31fe1Smrg       {
42663aace61Smrg       case DEFINE_INSN:
42763aace61Smrg 	gen_insn (&info);
42863aace61Smrg 	break;
429c3d31fe1Smrg 
43063aace61Smrg       case DEFINE_PEEPHOLE:
431c3d31fe1Smrg 	{
432c3d31fe1Smrg 	  struct code_ptr *link = XNEW (struct code_ptr);
433c3d31fe1Smrg 
43463aace61Smrg 	  link->insn_code = info.index;
435c3d31fe1Smrg 	  link->next = peepholes;
436c3d31fe1Smrg 	  peepholes = link;
437c3d31fe1Smrg 	}
43863aace61Smrg 	break;
43963aace61Smrg 
44063aace61Smrg       default:
44163aace61Smrg 	break;
442c3d31fe1Smrg     }
443c3d31fe1Smrg 
444c3d31fe1Smrg   if (have_error)
445c3d31fe1Smrg     return FATAL_EXIT_CODE;
446c3d31fe1Smrg 
447c3d31fe1Smrg   print_header ();
448c3d31fe1Smrg 
449c3d31fe1Smrg   /* Write out code to handle peepholes and the insn_codes that it should
450c3d31fe1Smrg      be called for.  */
451c3d31fe1Smrg   if (peepholes)
452c3d31fe1Smrg     {
453c3d31fe1Smrg       for (link = peepholes; link; link = link->next)
454c3d31fe1Smrg 	printf ("    case %d:\n", link->insn_code);
455c3d31fe1Smrg 
456c3d31fe1Smrg       /* The vector in the insn says how many operands it has.
457c3d31fe1Smrg 	 And all it contains are operands.  In fact, the vector was
458c3d31fe1Smrg 	 created just for the sake of this function.  We need to set the
459c3d31fe1Smrg 	 location of the operands for sake of simplifications after
460c3d31fe1Smrg 	 extraction, like eliminating subregs.  */
461c3d31fe1Smrg       puts ("      for (i = XVECLEN (pat, 0) - 1; i >= 0; i--)\n"
462c3d31fe1Smrg 	    "          ro[i] = *(ro_loc[i] = &XVECEXP (pat, 0, i));\n"
463c3d31fe1Smrg 	    "      break;\n");
464c3d31fe1Smrg     }
465c3d31fe1Smrg 
466c3d31fe1Smrg   /* Write out all the ways to extract insn operands.  */
467c3d31fe1Smrg   for (p = extractions; p; p = p->next)
468c3d31fe1Smrg     {
469c3d31fe1Smrg       for (link = p->insns; link; link = link->next)
470c3d31fe1Smrg 	{
471c3d31fe1Smrg 	  i = link->insn_code;
472c3d31fe1Smrg 	  name = get_insn_name (i);
473c3d31fe1Smrg 	  if (name)
474c3d31fe1Smrg 	    printf ("    case %d:  /* %s */\n", i, name);
475c3d31fe1Smrg 	  else
476c3d31fe1Smrg 	    printf ("    case %d:\n", i);
477c3d31fe1Smrg 	}
478c3d31fe1Smrg 
479c3d31fe1Smrg       for (i = 0; i < p->op_count; i++)
480c3d31fe1Smrg 	{
481c3d31fe1Smrg 	  if (p->oplocs[i] == 0)
482c3d31fe1Smrg 	    {
483c3d31fe1Smrg 	      printf ("      ro[%d] = const0_rtx;\n", i);
484c3d31fe1Smrg 	      printf ("      ro_loc[%d] = &junk;\n", i);
485c3d31fe1Smrg 	    }
486c3d31fe1Smrg 	  else
487c3d31fe1Smrg 	    {
488c3d31fe1Smrg 	      printf ("      ro[%d] = *(ro_loc[%d] = &", i, i);
489c3d31fe1Smrg 	      print_path (p->oplocs[i]);
490c3d31fe1Smrg 	      puts (");");
491c3d31fe1Smrg 	    }
492c3d31fe1Smrg 	}
493c3d31fe1Smrg 
494c3d31fe1Smrg       for (i = 0; i < p->dup_count; i++)
495c3d31fe1Smrg 	{
496c3d31fe1Smrg 	  printf ("      recog_data.dup_loc[%d] = &", i);
497c3d31fe1Smrg 	  print_path (p->duplocs[i]);
498c3d31fe1Smrg 	  puts (";");
499c3d31fe1Smrg 	  printf ("      recog_data.dup_num[%d] = %d;\n", i, p->dupnums[i]);
500c3d31fe1Smrg 	}
501c3d31fe1Smrg 
502c3d31fe1Smrg       puts ("      break;\n");
503c3d31fe1Smrg     }
504c3d31fe1Smrg 
505c3d31fe1Smrg   puts ("    }\n}");
506c3d31fe1Smrg   fflush (stdout);
507c3d31fe1Smrg   return (ferror (stdout) != 0 ? FATAL_EXIT_CODE : SUCCESS_EXIT_CODE);
508c3d31fe1Smrg }
509