0
|
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
|
|
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 "gensupport.h"
|
|
30 #include "vec.h"
|
|
31 #include "vecprim.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 DEF_VEC_P(locstr);
|
|
73 DEF_VEC_ALLOC_P(locstr,heap);
|
|
74
|
|
75 struct accum_extract
|
|
76 {
|
|
77 VEC(locstr,heap) *oplocs;
|
|
78 VEC(locstr,heap) *duplocs;
|
|
79 VEC(int,heap) *dupnums;
|
|
80 VEC(char,heap) *pathstr;
|
|
81 };
|
|
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 = VEC_alloc (locstr,heap, 10);
|
|
96 acc.duplocs = VEC_alloc (locstr,heap, 10);
|
|
97 acc.dupnums = VEC_alloc (int,heap, 10);
|
|
98 acc.pathstr = VEC_alloc (char,heap, 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 VEC_safe_push (char,heap, acc.pathstr, 'a' + i);
|
|
109 walk_rtx (XVECEXP (insn, 1, i), &acc);
|
|
110 VEC_pop (char, acc.pathstr);
|
|
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 = VEC_length (locstr, acc.oplocs);
|
|
119 dup_count = VEC_length (locstr, acc.duplocs);
|
|
120 gcc_assert (dup_count == VEC_length (int, acc.dupnums));
|
|
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 = VEC_index (locstr, 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] != VEC_index (int, acc.dupnums, j)
|
|
140 || strcmp (p->duplocs[j], VEC_index (locstr, 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, VEC_address(locstr,acc.oplocs), op_count*sizeof(locstr));
|
|
171 memcpy(p->duplocs, VEC_address(locstr,acc.duplocs), dup_count*sizeof(locstr));
|
|
172 memcpy(p->dupnums, VEC_address(int, acc.dupnums), dup_count*sizeof(int));
|
|
173
|
|
174 done:
|
|
175 VEC_free (locstr,heap, acc.oplocs);
|
|
176 VEC_free (locstr,heap, acc.duplocs);
|
|
177 VEC_free (int,heap, acc.dupnums);
|
|
178 VEC_free (char,heap, acc.pathstr);
|
|
179 }
|
|
180
|
|
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,heap) **vp, unsigned int ix, char *str)
|
|
187 {
|
|
188 if (ix < VEC_length (locstr, *vp))
|
|
189 {
|
|
190 gcc_assert (VEC_index (locstr, *vp, ix) == 0);
|
|
191 VEC_replace (locstr, *vp, ix, str);
|
|
192 }
|
|
193 else
|
|
194 {
|
|
195 while (ix > VEC_length (locstr, *vp))
|
|
196 VEC_safe_push (locstr, heap, *vp, 0);
|
|
197 VEC_safe_push (locstr, heap, *vp, str);
|
|
198 }
|
|
199 }
|
|
200
|
|
201 /* Another helper subroutine of walk_rtx: given a VEC(char), convert it
|
|
202 to a NUL-terminated string in malloc memory. */
|
|
203 static char *
|
|
204 VEC_char_to_string (VEC(char,heap) *v)
|
|
205 {
|
|
206 size_t n = VEC_length (char, v);
|
|
207 char *s = XNEWVEC (char, n + 1);
|
|
208 memcpy (s, VEC_address (char, v), n);
|
|
209 s[n] = '\0';
|
|
210 return s;
|
|
211 }
|
|
212
|
|
213 static void
|
|
214 walk_rtx (rtx x, struct accum_extract *acc)
|
|
215 {
|
|
216 RTX_CODE code;
|
|
217 int i, len, base;
|
|
218 const char *fmt;
|
|
219
|
|
220 if (x == 0)
|
|
221 return;
|
|
222
|
|
223 code = GET_CODE (x);
|
|
224 switch (code)
|
|
225 {
|
|
226 case PC:
|
|
227 case CC0:
|
|
228 case CONST_INT:
|
|
229 case SYMBOL_REF:
|
|
230 return;
|
|
231
|
|
232 case MATCH_OPERAND:
|
|
233 case MATCH_SCRATCH:
|
|
234 VEC_safe_set_locstr (&acc->oplocs, XINT (x, 0),
|
|
235 VEC_char_to_string (acc->pathstr));
|
|
236 break;
|
|
237
|
|
238 case MATCH_OPERATOR:
|
|
239 case MATCH_PARALLEL:
|
|
240 VEC_safe_set_locstr (&acc->oplocs, XINT (x, 0),
|
|
241 VEC_char_to_string (acc->pathstr));
|
|
242
|
|
243 base = (code == MATCH_OPERATOR ? '0' : 'a');
|
|
244 for (i = XVECLEN (x, 2) - 1; i >= 0; i--)
|
|
245 {
|
|
246 VEC_safe_push (char,heap, acc->pathstr, base + i);
|
|
247 walk_rtx (XVECEXP (x, 2, i), acc);
|
|
248 VEC_pop (char, acc->pathstr);
|
|
249 }
|
|
250 return;
|
|
251
|
|
252 case MATCH_DUP:
|
|
253 case MATCH_PAR_DUP:
|
|
254 case MATCH_OP_DUP:
|
|
255 VEC_safe_push (locstr,heap, acc->duplocs,
|
|
256 VEC_char_to_string (acc->pathstr));
|
|
257 VEC_safe_push (int,heap, acc->dupnums, XINT (x, 0));
|
|
258
|
|
259 if (code == MATCH_DUP)
|
|
260 break;
|
|
261
|
|
262 base = (code == MATCH_OP_DUP ? '0' : 'a');
|
|
263 for (i = XVECLEN (x, 1) - 1; i >= 0; i--)
|
|
264 {
|
|
265 VEC_safe_push (char,heap, acc->pathstr, base + i);
|
|
266 walk_rtx (XVECEXP (x, 1, i), acc);
|
|
267 VEC_pop (char, acc->pathstr);
|
|
268 }
|
|
269 return;
|
|
270
|
|
271 default:
|
|
272 break;
|
|
273 }
|
|
274
|
|
275 fmt = GET_RTX_FORMAT (code);
|
|
276 len = GET_RTX_LENGTH (code);
|
|
277 for (i = 0; i < len; i++)
|
|
278 {
|
|
279 if (fmt[i] == 'e' || fmt[i] == 'u')
|
|
280 {
|
|
281 VEC_safe_push (char,heap, acc->pathstr, '0' + i);
|
|
282 walk_rtx (XEXP (x, i), acc);
|
|
283 VEC_pop (char, acc->pathstr);
|
|
284 }
|
|
285 else if (fmt[i] == 'E')
|
|
286 {
|
|
287 int j;
|
|
288 for (j = XVECLEN (x, i) - 1; j >= 0; j--)
|
|
289 {
|
|
290 VEC_safe_push (char,heap, acc->pathstr, 'a' + j);
|
|
291 walk_rtx (XVECEXP (x, i, j), acc);
|
|
292 VEC_pop (char, acc->pathstr);
|
|
293 }
|
|
294 }
|
|
295 }
|
|
296 }
|
|
297
|
|
298 /* Given a PATH, representing a path down the instruction's
|
|
299 pattern from the root to a certain point, output code to
|
|
300 evaluate to the rtx at that point. */
|
|
301
|
|
302 static void
|
|
303 print_path (const char *path)
|
|
304 {
|
|
305 int len = strlen (path);
|
|
306 int i;
|
|
307
|
|
308 if (len == 0)
|
|
309 {
|
|
310 /* Don't emit "pat", since we may try to take the address of it,
|
|
311 which isn't what is intended. */
|
|
312 fputs ("PATTERN (insn)", stdout);
|
|
313 return;
|
|
314 }
|
|
315
|
|
316 /* We first write out the operations (XEXP or XVECEXP) in reverse
|
|
317 order, then write "pat", then the indices in forward order. */
|
|
318
|
|
319 for (i = len - 1; i >= 0 ; i--)
|
|
320 {
|
|
321 if (ISLOWER (path[i]))
|
|
322 fputs ("XVECEXP (", stdout);
|
|
323 else if (ISDIGIT (path[i]))
|
|
324 fputs ("XEXP (", stdout);
|
|
325 else
|
|
326 gcc_unreachable ();
|
|
327 }
|
|
328
|
|
329 fputs ("pat", stdout);
|
|
330
|
|
331 for (i = 0; i < len; i++)
|
|
332 {
|
|
333 if (ISLOWER (path[i]))
|
|
334 printf (", 0, %d)", path[i] - 'a');
|
|
335 else if (ISDIGIT(path[i]))
|
|
336 printf (", %d)", path[i] - '0');
|
|
337 else
|
|
338 gcc_unreachable ();
|
|
339 }
|
|
340 }
|
|
341
|
|
342 static void
|
|
343 print_header (void)
|
|
344 {
|
|
345 /* N.B. Code below avoids putting squiggle braces in column 1 inside
|
|
346 a string, because this confuses some editors' syntax highlighting
|
|
347 engines. */
|
|
348
|
|
349 puts ("\
|
|
350 /* Generated automatically by the program `genextract'\n\
|
|
351 from the machine description file `md'. */\n\
|
|
352 \n\
|
|
353 #include \"config.h\"\n\
|
|
354 #include \"system.h\"\n\
|
|
355 #include \"coretypes.h\"\n\
|
|
356 #include \"tm.h\"\n\
|
|
357 #include \"rtl.h\"\n\
|
|
358 #include \"insn-config.h\"\n\
|
|
359 #include \"recog.h\"\n\
|
|
360 #include \"toplev.h\"\n\
|
|
361 \n\
|
|
362 /* This variable is used as the \"location\" of any missing operand\n\
|
|
363 whose numbers are skipped by a given pattern. */\n\
|
|
364 static rtx junk ATTRIBUTE_UNUSED;\n");
|
|
365
|
|
366 puts ("\
|
|
367 void\n\
|
|
368 insn_extract (rtx insn)\n{\n\
|
|
369 rtx *ro = recog_data.operand;\n\
|
|
370 rtx **ro_loc = recog_data.operand_loc;\n\
|
|
371 rtx pat = PATTERN (insn);\n\
|
|
372 int i ATTRIBUTE_UNUSED; /* only for peepholes */\n\
|
|
373 \n\
|
|
374 #ifdef ENABLE_CHECKING\n\
|
|
375 memset (ro, 0xab, sizeof (*ro) * MAX_RECOG_OPERANDS);\n\
|
|
376 memset (ro_loc, 0xab, sizeof (*ro_loc) * MAX_RECOG_OPERANDS);\n\
|
|
377 #endif\n");
|
|
378
|
|
379 puts ("\
|
|
380 switch (INSN_CODE (insn))\n\
|
|
381 {\n\
|
|
382 default:\n\
|
|
383 /* Control reaches here if insn_extract has been called with an\n\
|
|
384 unrecognizable insn (code -1), or an insn whose INSN_CODE\n\
|
|
385 corresponds to a DEFINE_EXPAND in the machine description;\n\
|
|
386 either way, a bug. */\n\
|
|
387 if (INSN_CODE (insn) < 0)\n\
|
|
388 fatal_insn (\"unrecognizable insn:\", insn);\n\
|
|
389 else\n\
|
|
390 fatal_insn (\"insn with invalid code number:\", insn);\n");
|
|
391 }
|
|
392
|
|
393 int
|
|
394 main (int argc, char **argv)
|
|
395 {
|
|
396 rtx desc;
|
|
397 unsigned int i;
|
|
398 struct extraction *p;
|
|
399 struct code_ptr *link;
|
|
400 const char *name;
|
|
401 int insn_code_number;
|
|
402 int line_no;
|
|
403
|
|
404 progname = "genextract";
|
|
405
|
|
406 if (init_md_reader_args (argc, argv) != SUCCESS_EXIT_CODE)
|
|
407 return (FATAL_EXIT_CODE);
|
|
408
|
|
409 /* Read the machine description. */
|
|
410
|
|
411 while ((desc = read_md_rtx (&line_no, &insn_code_number)) != NULL)
|
|
412 {
|
|
413 if (GET_CODE (desc) == DEFINE_INSN)
|
|
414 gen_insn (desc, insn_code_number);
|
|
415
|
|
416 else if (GET_CODE (desc) == DEFINE_PEEPHOLE)
|
|
417 {
|
|
418 struct code_ptr *link = XNEW (struct code_ptr);
|
|
419
|
|
420 link->insn_code = insn_code_number;
|
|
421 link->next = peepholes;
|
|
422 peepholes = link;
|
|
423 }
|
|
424 }
|
|
425
|
|
426 print_header ();
|
|
427
|
|
428 /* Write out code to handle peepholes and the insn_codes that it should
|
|
429 be called for. */
|
|
430 if (peepholes)
|
|
431 {
|
|
432 for (link = peepholes; link; link = link->next)
|
|
433 printf (" case %d:\n", link->insn_code);
|
|
434
|
|
435 /* The vector in the insn says how many operands it has.
|
|
436 And all it contains are operands. In fact, the vector was
|
|
437 created just for the sake of this function. We need to set the
|
|
438 location of the operands for sake of simplifications after
|
|
439 extraction, like eliminating subregs. */
|
|
440 puts (" for (i = XVECLEN (pat, 0) - 1; i >= 0; i--)\n"
|
|
441 " ro[i] = *(ro_loc[i] = &XVECEXP (pat, 0, i));\n"
|
|
442 " break;\n");
|
|
443 }
|
|
444
|
|
445 /* Write out all the ways to extract insn operands. */
|
|
446 for (p = extractions; p; p = p->next)
|
|
447 {
|
|
448 for (link = p->insns; link; link = link->next)
|
|
449 {
|
|
450 i = link->insn_code;
|
|
451 name = get_insn_name (i);
|
|
452 if (name)
|
|
453 printf (" case %d: /* %s */\n", i, name);
|
|
454 else
|
|
455 printf (" case %d:\n", i);
|
|
456 }
|
|
457
|
|
458 for (i = 0; i < p->op_count; i++)
|
|
459 {
|
|
460 if (p->oplocs[i] == 0)
|
|
461 {
|
|
462 printf (" ro[%d] = const0_rtx;\n", i);
|
|
463 printf (" ro_loc[%d] = &junk;\n", i);
|
|
464 }
|
|
465 else
|
|
466 {
|
|
467 printf (" ro[%d] = *(ro_loc[%d] = &", i, i);
|
|
468 print_path (p->oplocs[i]);
|
|
469 puts (");");
|
|
470 }
|
|
471 }
|
|
472
|
|
473 for (i = 0; i < p->dup_count; i++)
|
|
474 {
|
|
475 printf (" recog_data.dup_loc[%d] = &", i);
|
|
476 print_path (p->duplocs[i]);
|
|
477 puts (";");
|
|
478 printf (" recog_data.dup_num[%d] = %d;\n", i, p->dupnums[i]);
|
|
479 }
|
|
480
|
|
481 puts (" break;\n");
|
|
482 }
|
|
483
|
|
484 puts (" }\n}");
|
|
485 fflush (stdout);
|
|
486 return (ferror (stdout) != 0 ? FATAL_EXIT_CODE : SUCCESS_EXIT_CODE);
|
|
487 }
|