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