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