]> git.ipfire.org Git - thirdparty/gcc.git/blob - gcc/genextract.c
Update Copyright years for files modified in 2011 and/or 2012.
[thirdparty/gcc.git] / gcc / genextract.c
1 /* Generate code from machine description to extract operands from insn as rtl.
2 Copyright (C) 1987, 1991, 1992, 1993, 1997, 1998, 1999, 2000, 2003,
3 2004, 2005, 2007, 2008, 2009, 2010, 2012
4 Free Software Foundation, Inc.
5
6 This file is part of GCC.
7
8 GCC is free software; you can redistribute it and/or modify it under
9 the terms of the GNU General Public License as published by the Free
10 Software Foundation; either version 3, or (at your option) any later
11 version.
12
13 GCC is distributed in the hope that it will be useful, but WITHOUT ANY
14 WARRANTY; without even the implied warranty of MERCHANTABILITY or
15 FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
16 for more details.
17
18 You should have received a copy of the GNU General Public License
19 along with GCC; see the file COPYING3. If not see
20 <http://www.gnu.org/licenses/>. */
21
22
23 #include "bconfig.h"
24 #include "system.h"
25 #include "coretypes.h"
26 #include "tm.h"
27 #include "rtl.h"
28 #include "errors.h"
29 #include "read-md.h"
30 #include "gensupport.h"
31 #include "vec.h"
32
33 /* This structure contains all the information needed to describe one
34 set of extractions methods. Each method may be used by more than
35 one pattern if the operands are in the same place.
36
37 The string for each operand describes that path to the operand and
38 contains `0' through `9' when going into an expression and `a' through
39 `z' when going into a vector. We assume here that only the first operand
40 of an rtl expression is a vector. genrecog.c makes the same assumption
41 (and uses the same representation) and it is currently true. */
42
43 typedef char *locstr;
44
45 struct extraction
46 {
47 unsigned int op_count;
48 unsigned int dup_count;
49 locstr *oplocs;
50 locstr *duplocs;
51 int *dupnums;
52 struct code_ptr *insns;
53 struct extraction *next;
54 };
55
56 /* Holds a single insn code that uses an extraction method. */
57 struct code_ptr
58 {
59 int insn_code;
60 struct code_ptr *next;
61 };
62
63 /* All extractions needed for this machine description. */
64 static struct extraction *extractions;
65
66 /* All insn codes for old-style peepholes. */
67 static struct code_ptr *peepholes;
68
69 /* This structure is used by gen_insn and walk_rtx to accumulate the
70 data that will be used to produce an extractions structure. */
71
72
73 struct accum_extract
74 {
75 vec<locstr> oplocs;
76 vec<locstr> duplocs;
77 vec<int> dupnums;
78 vec<char> pathstr;
79 };
80
81 int line_no;
82
83 /* Forward declarations. */
84 static void walk_rtx (rtx, struct accum_extract *);
85
86 static void
87 gen_insn (rtx insn, int insn_code_number)
88 {
89 int i;
90 unsigned int op_count, dup_count, j;
91 struct extraction *p;
92 struct code_ptr *link;
93 struct accum_extract acc;
94
95 acc.oplocs.create (10);
96 acc.duplocs.create (10);
97 acc.dupnums.create (10);
98 acc.pathstr.create (20);
99
100 /* Walk the insn's pattern, remembering at all times the path
101 down to the walking point. */
102
103 if (XVECLEN (insn, 1) == 1)
104 walk_rtx (XVECEXP (insn, 1, 0), &acc);
105 else
106 for (i = XVECLEN (insn, 1) - 1; i >= 0; i--)
107 {
108 acc.pathstr.safe_push ('a' + i);
109 walk_rtx (XVECEXP (insn, 1, i), &acc);
110 acc.pathstr.pop ();
111 }
112
113 link = XNEW (struct code_ptr);
114 link->insn_code = insn_code_number;
115
116 /* See if we find something that already had this extraction method. */
117
118 op_count = acc.oplocs.length ();
119 dup_count = acc.duplocs.length ();
120 gcc_assert (dup_count == acc.dupnums.length ());
121
122 for (p = extractions; p; p = p->next)
123 {
124 if (p->op_count != op_count || p->dup_count != dup_count)
125 continue;
126
127 for (j = 0; j < op_count; j++)
128 {
129 char *a = p->oplocs[j];
130 char *b = acc.oplocs[j];
131 if (a != b && (!a || !b || strcmp (a, b)))
132 break;
133 }
134
135 if (j != op_count)
136 continue;
137
138 for (j = 0; j < dup_count; j++)
139 if (p->dupnums[j] != acc.dupnums[j]
140 || strcmp (p->duplocs[j], acc.duplocs[j]))
141 break;
142
143 if (j != dup_count)
144 continue;
145
146 /* This extraction is the same as ours. Just link us in. */
147 link->next = p->insns;
148 p->insns = link;
149 goto done;
150 }
151
152 /* Otherwise, make a new extraction method. We stash the arrays
153 after the extraction structure in memory. */
154
155 p = XNEWVAR (struct extraction, sizeof (struct extraction)
156 + op_count*sizeof (char *)
157 + dup_count*sizeof (char *)
158 + dup_count*sizeof (int));
159 p->op_count = op_count;
160 p->dup_count = dup_count;
161 p->next = extractions;
162 extractions = p;
163 p->insns = link;
164 link->next = 0;
165
166 p->oplocs = (char **)((char *)p + sizeof (struct extraction));
167 p->duplocs = p->oplocs + op_count;
168 p->dupnums = (int *)(p->duplocs + dup_count);
169
170 memcpy(p->oplocs, acc.oplocs.address(), op_count*sizeof(locstr));
171 memcpy(p->duplocs, acc.duplocs.address(), dup_count*sizeof(locstr));
172 memcpy(p->dupnums, acc.dupnums.address(), dup_count*sizeof(int));
173
174 done:
175 acc.oplocs.release ();
176 acc.duplocs.release ();
177 acc.dupnums.release ();
178 acc.pathstr.release ();
179 }
180 \f
181 /* Helper subroutine of walk_rtx: given a vec<locstr>, an index, and a
182 string, insert the string at the index, which should either already
183 exist and be NULL, or not yet exist within the vector. In the latter
184 case the vector is enlarged as appropriate. */
185 static void
186 VEC_safe_set_locstr (vec<locstr> *vp, unsigned int ix, char *str)
187 {
188 if (ix < (*vp).length ())
189 {
190 if ((*vp)[ix])
191 {
192 message_with_line (line_no, "repeated operand number %d", ix);
193 have_error = 1;
194 }
195 else
196 (*vp)[ix] = str;
197 }
198 else
199 {
200 while (ix > (*vp).length ())
201 vp->safe_push (NULL);
202 vp->safe_push (str);
203 }
204 }
205
206 /* Another helper subroutine of walk_rtx: given a vec<char>, convert it
207 to a NUL-terminated string in malloc memory. */
208 static char *
209 VEC_char_to_string (vec<char> v)
210 {
211 size_t n = v.length ();
212 char *s = XNEWVEC (char, n + 1);
213 memcpy (s, v.address (), n);
214 s[n] = '\0';
215 return s;
216 }
217
218 static void
219 walk_rtx (rtx x, struct accum_extract *acc)
220 {
221 RTX_CODE code;
222 int i, len, base;
223 const char *fmt;
224
225 if (x == 0)
226 return;
227
228 code = GET_CODE (x);
229 switch (code)
230 {
231 case PC:
232 case CC0:
233 case CONST_INT:
234 case SYMBOL_REF:
235 return;
236
237 case MATCH_OPERAND:
238 case MATCH_SCRATCH:
239 VEC_safe_set_locstr (&acc->oplocs, XINT (x, 0),
240 VEC_char_to_string (acc->pathstr));
241 break;
242
243 case MATCH_OPERATOR:
244 case MATCH_PARALLEL:
245 VEC_safe_set_locstr (&acc->oplocs, XINT (x, 0),
246 VEC_char_to_string (acc->pathstr));
247
248 base = (code == MATCH_OPERATOR ? '0' : 'a');
249 for (i = XVECLEN (x, 2) - 1; i >= 0; i--)
250 {
251 acc->pathstr.safe_push (base + i);
252 walk_rtx (XVECEXP (x, 2, i), acc);
253 acc->pathstr.pop ();
254 }
255 return;
256
257 case MATCH_DUP:
258 case MATCH_PAR_DUP:
259 case MATCH_OP_DUP:
260 acc->duplocs.safe_push (VEC_char_to_string (acc->pathstr));
261 acc->dupnums.safe_push (XINT (x, 0));
262
263 if (code == MATCH_DUP)
264 break;
265
266 base = (code == MATCH_OP_DUP ? '0' : 'a');
267 for (i = XVECLEN (x, 1) - 1; i >= 0; i--)
268 {
269 acc->pathstr.safe_push (base + i);
270 walk_rtx (XVECEXP (x, 1, i), acc);
271 acc->pathstr.pop ();
272 }
273 return;
274
275 default:
276 break;
277 }
278
279 fmt = GET_RTX_FORMAT (code);
280 len = GET_RTX_LENGTH (code);
281 for (i = 0; i < len; i++)
282 {
283 if (fmt[i] == 'e' || fmt[i] == 'u')
284 {
285 acc->pathstr.safe_push ('0' + i);
286 walk_rtx (XEXP (x, i), acc);
287 acc->pathstr.pop ();
288 }
289 else if (fmt[i] == 'E')
290 {
291 int j;
292 for (j = XVECLEN (x, i) - 1; j >= 0; j--)
293 {
294 acc->pathstr.safe_push ('a' + j);
295 walk_rtx (XVECEXP (x, i, j), acc);
296 acc->pathstr.pop ();
297 }
298 }
299 }
300 }
301
302 /* Given a PATH, representing a path down the instruction's
303 pattern from the root to a certain point, output code to
304 evaluate to the rtx at that point. */
305
306 static void
307 print_path (const char *path)
308 {
309 int len = strlen (path);
310 int i;
311
312 if (len == 0)
313 {
314 /* Don't emit "pat", since we may try to take the address of it,
315 which isn't what is intended. */
316 fputs ("PATTERN (insn)", stdout);
317 return;
318 }
319
320 /* We first write out the operations (XEXP or XVECEXP) in reverse
321 order, then write "pat", then the indices in forward order. */
322
323 for (i = len - 1; i >= 0 ; i--)
324 {
325 if (ISLOWER (path[i]))
326 fputs ("XVECEXP (", stdout);
327 else if (ISDIGIT (path[i]))
328 fputs ("XEXP (", stdout);
329 else
330 gcc_unreachable ();
331 }
332
333 fputs ("pat", stdout);
334
335 for (i = 0; i < len; i++)
336 {
337 if (ISLOWER (path[i]))
338 printf (", 0, %d)", path[i] - 'a');
339 else if (ISDIGIT(path[i]))
340 printf (", %d)", path[i] - '0');
341 else
342 gcc_unreachable ();
343 }
344 }
345 \f
346 static void
347 print_header (void)
348 {
349 /* N.B. Code below avoids putting squiggle braces in column 1 inside
350 a string, because this confuses some editors' syntax highlighting
351 engines. */
352
353 puts ("\
354 /* Generated automatically by the program `genextract'\n\
355 from the machine description file `md'. */\n\
356 \n\
357 #include \"config.h\"\n\
358 #include \"system.h\"\n\
359 #include \"coretypes.h\"\n\
360 #include \"tm.h\"\n\
361 #include \"rtl.h\"\n\
362 #include \"insn-config.h\"\n\
363 #include \"recog.h\"\n\
364 #include \"diagnostic-core.h\"\n\
365 \n\
366 /* This variable is used as the \"location\" of any missing operand\n\
367 whose numbers are skipped by a given pattern. */\n\
368 static rtx junk ATTRIBUTE_UNUSED;\n");
369
370 puts ("\
371 void\n\
372 insn_extract (rtx insn)\n{\n\
373 rtx *ro = recog_data.operand;\n\
374 rtx **ro_loc = recog_data.operand_loc;\n\
375 rtx pat = PATTERN (insn);\n\
376 int i ATTRIBUTE_UNUSED; /* only for peepholes */\n\
377 \n\
378 #ifdef ENABLE_CHECKING\n\
379 memset (ro, 0xab, sizeof (*ro) * MAX_RECOG_OPERANDS);\n\
380 memset (ro_loc, 0xab, sizeof (*ro_loc) * MAX_RECOG_OPERANDS);\n\
381 #endif\n");
382
383 puts ("\
384 switch (INSN_CODE (insn))\n\
385 {\n\
386 default:\n\
387 /* Control reaches here if insn_extract has been called with an\n\
388 unrecognizable insn (code -1), or an insn whose INSN_CODE\n\
389 corresponds to a DEFINE_EXPAND in the machine description;\n\
390 either way, a bug. */\n\
391 if (INSN_CODE (insn) < 0)\n\
392 fatal_insn (\"unrecognizable insn:\", insn);\n\
393 else\n\
394 fatal_insn (\"insn with invalid code number:\", insn);\n");
395 }
396
397 int
398 main (int argc, char **argv)
399 {
400 rtx desc;
401 unsigned int i;
402 struct extraction *p;
403 struct code_ptr *link;
404 const char *name;
405 int insn_code_number;
406
407 progname = "genextract";
408
409 if (!init_rtx_reader_args (argc, argv))
410 return (FATAL_EXIT_CODE);
411
412 /* Read the machine description. */
413
414 while ((desc = read_md_rtx (&line_no, &insn_code_number)) != NULL)
415 {
416 if (GET_CODE (desc) == DEFINE_INSN)
417 gen_insn (desc, insn_code_number);
418
419 else if (GET_CODE (desc) == DEFINE_PEEPHOLE)
420 {
421 struct code_ptr *link = XNEW (struct code_ptr);
422
423 link->insn_code = insn_code_number;
424 link->next = peepholes;
425 peepholes = link;
426 }
427 }
428
429 if (have_error)
430 return FATAL_EXIT_CODE;
431
432 print_header ();
433
434 /* Write out code to handle peepholes and the insn_codes that it should
435 be called for. */
436 if (peepholes)
437 {
438 for (link = peepholes; link; link = link->next)
439 printf (" case %d:\n", link->insn_code);
440
441 /* The vector in the insn says how many operands it has.
442 And all it contains are operands. In fact, the vector was
443 created just for the sake of this function. We need to set the
444 location of the operands for sake of simplifications after
445 extraction, like eliminating subregs. */
446 puts (" for (i = XVECLEN (pat, 0) - 1; i >= 0; i--)\n"
447 " ro[i] = *(ro_loc[i] = &XVECEXP (pat, 0, i));\n"
448 " break;\n");
449 }
450
451 /* Write out all the ways to extract insn operands. */
452 for (p = extractions; p; p = p->next)
453 {
454 for (link = p->insns; link; link = link->next)
455 {
456 i = link->insn_code;
457 name = get_insn_name (i);
458 if (name)
459 printf (" case %d: /* %s */\n", i, name);
460 else
461 printf (" case %d:\n", i);
462 }
463
464 for (i = 0; i < p->op_count; i++)
465 {
466 if (p->oplocs[i] == 0)
467 {
468 printf (" ro[%d] = const0_rtx;\n", i);
469 printf (" ro_loc[%d] = &junk;\n", i);
470 }
471 else
472 {
473 printf (" ro[%d] = *(ro_loc[%d] = &", i, i);
474 print_path (p->oplocs[i]);
475 puts (");");
476 }
477 }
478
479 for (i = 0; i < p->dup_count; i++)
480 {
481 printf (" recog_data.dup_loc[%d] = &", i);
482 print_path (p->duplocs[i]);
483 puts (";");
484 printf (" recog_data.dup_num[%d] = %d;\n", i, p->dupnums[i]);
485 }
486
487 puts (" break;\n");
488 }
489
490 puts (" }\n}");
491 fflush (stdout);
492 return (ferror (stdout) != 0 ? FATAL_EXIT_CODE : SUCCESS_EXIT_CODE);
493 }