]>
Commit | Line | Data |
---|---|---|
9db4e0ec | 1 | /* Generate code from to output assembler insns as recognized from rtl. |
d050d723 | 2 | Copyright (C) 1987, 1988, 1992, 1994, 1995, 1997, 1998, 1999, 2000 |
a995e389 | 3 | Free Software Foundation, Inc. |
9db4e0ec RK |
4 | |
5 | This file is part of GNU CC. | |
6 | ||
7 | GNU CC is free software; you can redistribute it and/or modify | |
8 | it under the terms of the GNU General Public License as published by | |
9 | the Free Software Foundation; either version 2, or (at your option) | |
10 | any later version. | |
11 | ||
12 | GNU CC is distributed in the hope that it will be useful, | |
13 | but WITHOUT ANY WARRANTY; without even the implied warranty of | |
14 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
15 | GNU General Public License for more details. | |
16 | ||
17 | You should have received a copy of the GNU General Public License | |
18 | along with GNU CC; see the file COPYING. If not, write to | |
a35311b0 RK |
19 | the Free Software Foundation, 59 Temple Place - Suite 330, |
20 | Boston, MA 02111-1307, USA. */ | |
9db4e0ec RK |
21 | |
22 | ||
23 | /* This program reads the machine description for the compiler target machine | |
24 | and produces a file containing these things: | |
25 | ||
a995e389 RH |
26 | 1. An array of `struct insn_data', which is indexed by insn code number, |
27 | which contains: | |
9db4e0ec | 28 | |
a995e389 RH |
29 | a. `name' is the name for that pattern. Nameless patterns are |
30 | given a name. | |
31 | ||
4bbf910e RH |
32 | b. `output' hold either the output template, an array of output |
33 | templates, or an output function. | |
34 | ||
35 | c. `genfun' is the function to generate a body for that pattern, | |
a995e389 RH |
36 | given operands as arguments. |
37 | ||
4bbf910e | 38 | d. `n_operands' is the number of distinct operands in the pattern |
a995e389 | 39 | for that insn, |
9db4e0ec | 40 | |
4bbf910e | 41 | e. `n_dups' is the number of match_dup's that appear in the insn's |
a995e389 RH |
42 | pattern. This says how many elements of `recog_data.dup_loc' are |
43 | significant after an insn has been recognized. | |
9db4e0ec | 44 | |
4bbf910e | 45 | f. `n_alternatives' is the number of alternatives in the constraints |
a995e389 | 46 | of each pattern. |
9db4e0ec | 47 | |
4bbf910e RH |
48 | g. `output_format' tells what type of thing `output' is. |
49 | ||
a995e389 | 50 | h. `operand' is the base of an array of operand data for the insn. |
9db4e0ec | 51 | |
a995e389 | 52 | 2. An array of `struct insn_operand data', used by `operand' above. |
9db4e0ec | 53 | |
a995e389 RH |
54 | a. `predicate', an int-valued function, is the match_operand predicate |
55 | for this operand. | |
9db4e0ec | 56 | |
a995e389 RH |
57 | b. `constraint' is the constraint for this operand. This exists |
58 | only if register constraints appear in match_operand rtx's. | |
9db4e0ec | 59 | |
a995e389 RH |
60 | c. `address_p' indicates that the operand appears within ADDRESS |
61 | rtx's. This exists only if there are *no* register constraints | |
62 | in the match_operand rtx's. | |
9db4e0ec | 63 | |
a995e389 | 64 | d. `mode' is the machine mode that that operand is supposed to have. |
9db4e0ec | 65 | |
a995e389 | 66 | e. `strict_low', is nonzero for operands contained in a STRICT_LOW_PART. |
9db4e0ec | 67 | |
dfac187e BS |
68 | f. `eliminable', is nonzero for operands that are matched normally by |
69 | MATCH_OPERAND; it is zero for operands that should not be changed during | |
70 | register elimination such as MATCH_OPERATORs. | |
71 | ||
a995e389 RH |
72 | The code number of an insn is simply its position in the machine |
73 | description; code numbers are assigned sequentially to entries in | |
74 | the description, starting with code number 0. | |
9db4e0ec | 75 | |
a995e389 | 76 | Thus, the following entry in the machine description |
9db4e0ec RK |
77 | |
78 | (define_insn "clrdf" | |
79 | [(set (match_operand:DF 0 "general_operand" "") | |
80 | (const_int 0))] | |
81 | "" | |
82 | "clrd %0") | |
83 | ||
a995e389 RH |
84 | assuming it is the 25th entry present, would cause |
85 | insn_data[24].template to be "clrd %0", and | |
86 | insn_data[24].n_operands to be 1. */ | |
9db4e0ec | 87 | \f |
20f92396 | 88 | #include "hconfig.h" |
0b93b64e | 89 | #include "system.h" |
9db4e0ec RK |
90 | #include "rtl.h" |
91 | #include "obstack.h" | |
f8b6598e | 92 | #include "errors.h" |
9db4e0ec | 93 | |
a995e389 RH |
94 | /* No instruction can have more operands than this. Sorry for this |
95 | arbitrary limit, but what machine will have an instruction with | |
96 | this many operands? */ | |
9db4e0ec RK |
97 | |
98 | #define MAX_MAX_OPERANDS 40 | |
99 | ||
100 | static struct obstack obstack; | |
101 | struct obstack *rtl_obstack = &obstack; | |
102 | ||
103 | #define obstack_chunk_alloc xmalloc | |
104 | #define obstack_chunk_free free | |
105 | ||
3cce094d | 106 | static int n_occurrences PARAMS ((int, const char *)); |
88a56c2e | 107 | static void strip_whitespace PARAMS ((char *)); |
9db4e0ec RK |
108 | |
109 | /* insns in the machine description are assigned sequential code numbers | |
110 | that are used by insn-recog.c (produced by genrecog) to communicate | |
111 | to insn-output.c (produced by this program). */ | |
112 | ||
113 | static int next_code_number; | |
114 | ||
115 | /* This counts all definitions in the md file, | |
116 | for the sake of error messages. */ | |
117 | ||
118 | static int next_index_number; | |
119 | ||
a995e389 RH |
120 | /* This counts all operands used in the md file. The first is null. */ |
121 | ||
122 | static int next_operand_number = 1; | |
123 | ||
124 | /* Record in this chain all information about the operands we will output. */ | |
125 | ||
126 | struct operand_data | |
127 | { | |
128 | struct operand_data *next; | |
129 | int index; | |
c1b59dce KG |
130 | const char *predicate; |
131 | const char *constraint; | |
a995e389 RH |
132 | enum machine_mode mode; |
133 | unsigned char n_alternatives; | |
134 | char address_p; | |
135 | char strict_low; | |
dfac187e | 136 | char eliminable; |
a995e389 RH |
137 | char seen; |
138 | }; | |
139 | ||
140 | /* Begin with a null operand at index 0. */ | |
141 | ||
142 | static struct operand_data null_operand = | |
143 | { | |
f4e2ed09 | 144 | 0, 0, "", "", VOIDmode, 0, 0, 0, 0, 0 |
a995e389 RH |
145 | }; |
146 | ||
147 | static struct operand_data *odata = &null_operand; | |
148 | static struct operand_data **odata_end = &null_operand.next; | |
149 | ||
4bbf910e RH |
150 | /* Must match the constants in recog.h. */ |
151 | ||
152 | #define INSN_OUTPUT_FORMAT_NONE 0 /* abort */ | |
153 | #define INSN_OUTPUT_FORMAT_SINGLE 1 /* const char * */ | |
154 | #define INSN_OUTPUT_FORMAT_MULTI 2 /* const char * const * */ | |
155 | #define INSN_OUTPUT_FORMAT_FUNCTION 3 /* const char * (*)(...) */ | |
156 | ||
9db4e0ec RK |
157 | /* Record in this chain all information that we will output, |
158 | associated with the code number of the insn. */ | |
159 | ||
160 | struct data | |
161 | { | |
a995e389 | 162 | struct data *next; |
c1b59dce KG |
163 | const char *name; |
164 | const char *template; | |
a995e389 RH |
165 | int code_number; |
166 | int index_number; | |
9db4e0ec RK |
167 | int n_operands; /* Number of operands this insn recognizes */ |
168 | int n_dups; /* Number times match_dup appears in pattern */ | |
169 | int n_alternatives; /* Number of alternatives in each constraint */ | |
a995e389 | 170 | int operand_number; /* Operand index in the big array. */ |
4bbf910e | 171 | int output_format; /* INSN_OUTPUT_FORMAT_*. */ |
a995e389 | 172 | struct operand_data operand[MAX_MAX_OPERANDS]; |
9db4e0ec RK |
173 | }; |
174 | ||
a995e389 | 175 | /* This variable points to the first link in the insn chain. */ |
9db4e0ec | 176 | |
a995e389 | 177 | static struct data *idata, **idata_end = &idata; |
9db4e0ec | 178 | \f |
a94ae8f5 KG |
179 | static void output_prologue PARAMS ((void)); |
180 | static void output_predicate_decls PARAMS ((void)); | |
181 | static void output_operand_data PARAMS ((void)); | |
182 | static void output_insn_data PARAMS ((void)); | |
183 | static void output_get_insn_name PARAMS ((void)); | |
184 | static void scan_operands PARAMS ((struct data *, rtx, int, int)); | |
185 | static int compare_operands PARAMS ((struct operand_data *, | |
a995e389 | 186 | struct operand_data *)); |
a94ae8f5 | 187 | static void place_operands PARAMS ((struct data *)); |
3cce094d | 188 | static void process_template PARAMS ((struct data *, const char *)); |
a94ae8f5 KG |
189 | static void validate_insn_alternatives PARAMS ((struct data *)); |
190 | static void gen_insn PARAMS ((rtx)); | |
191 | static void gen_peephole PARAMS ((rtx)); | |
192 | static void gen_expand PARAMS ((rtx)); | |
193 | static void gen_split PARAMS ((rtx)); | |
56c0e996 | 194 | \f |
a995e389 RH |
195 | const char * |
196 | get_insn_name (index) | |
8aeba909 RH |
197 | int index; |
198 | { | |
199 | static char buf[100]; | |
200 | ||
201 | struct data *i, *last_named = NULL; | |
a995e389 | 202 | for (i = idata; i ; i = i->next) |
8aeba909 RH |
203 | { |
204 | if (i->index_number == index) | |
205 | return i->name; | |
206 | if (i->name) | |
207 | last_named = i; | |
208 | } | |
209 | ||
210 | if (last_named) | |
211 | sprintf(buf, "%s+%d", last_named->name, index - last_named->index_number); | |
212 | else | |
213 | sprintf(buf, "insn %d", index); | |
214 | ||
215 | return buf; | |
216 | } | |
217 | ||
9db4e0ec RK |
218 | static void |
219 | output_prologue () | |
220 | { | |
9db4e0ec RK |
221 | printf ("/* Generated automatically by the program `genoutput'\n\ |
222 | from the machine description file `md'. */\n\n"); | |
223 | ||
224 | printf ("#include \"config.h\"\n"); | |
729da3f5 | 225 | printf ("#include \"system.h\"\n"); |
ccd043a9 | 226 | printf ("#include \"flags.h\"\n"); |
3bc9f12b | 227 | printf ("#include \"ggc.h\"\n"); |
9db4e0ec | 228 | printf ("#include \"rtl.h\"\n"); |
6baf1cc8 | 229 | printf ("#include \"tm_p.h\"\n"); |
49ad7cfa | 230 | printf ("#include \"function.h\"\n"); |
9db4e0ec RK |
231 | printf ("#include \"regs.h\"\n"); |
232 | printf ("#include \"hard-reg-set.h\"\n"); | |
233 | printf ("#include \"real.h\"\n"); | |
234 | printf ("#include \"insn-config.h\"\n\n"); | |
235 | printf ("#include \"conditions.h\"\n"); | |
236 | printf ("#include \"insn-flags.h\"\n"); | |
237 | printf ("#include \"insn-attr.h\"\n\n"); | |
238 | printf ("#include \"insn-codes.h\"\n\n"); | |
239 | printf ("#include \"recog.h\"\n\n"); | |
c3fc86c9 | 240 | printf ("#include \"toplev.h\"\n"); |
9db4e0ec RK |
241 | printf ("#include \"output.h\"\n"); |
242 | } | |
243 | ||
a995e389 RH |
244 | |
245 | /* We need to define all predicates used. Keep a list of those we | |
246 | have defined so far. There normally aren't very many predicates | |
247 | used, so a linked list should be fast enough. */ | |
248 | ||
9db4e0ec | 249 | static void |
a995e389 | 250 | output_predicate_decls () |
9db4e0ec | 251 | { |
c1b59dce | 252 | struct predicate { const char *name; struct predicate *next; } *predicates = 0; |
a995e389 RH |
253 | register struct operand_data *d; |
254 | struct predicate *p; | |
9db4e0ec | 255 | |
a995e389 RH |
256 | for (d = odata; d; d = d->next) |
257 | if (d->predicate && d->predicate[0]) | |
258 | { | |
259 | for (p = predicates; p; p = p->next) | |
260 | if (strcmp (p->name, d->predicate) == 0) | |
261 | break; | |
9db4e0ec | 262 | |
a995e389 RH |
263 | if (p == 0) |
264 | { | |
a94ae8f5 | 265 | printf ("extern int %s PARAMS ((rtx, enum machine_mode));\n", |
a995e389 RH |
266 | d->predicate); |
267 | p = (struct predicate *) alloca (sizeof (struct predicate)); | |
268 | p->name = d->predicate; | |
269 | p->next = predicates; | |
270 | predicates = p; | |
271 | } | |
272 | } | |
273 | ||
274 | printf ("\n\n"); | |
275 | } | |
9db4e0ec | 276 | |
a995e389 RH |
277 | static void |
278 | output_operand_data () | |
279 | { | |
280 | register struct operand_data *d; | |
281 | ||
282 | printf ("\nstatic const struct insn_operand_data operand_data[] = \n{\n"); | |
283 | ||
284 | for (d = odata; d; d = d->next) | |
9db4e0ec | 285 | { |
a995e389 RH |
286 | printf (" {\n"); |
287 | ||
288 | printf (" %s,\n", | |
289 | d->predicate && d->predicate[0] ? d->predicate : "0"); | |
290 | ||
19af6455 | 291 | printf (" \"%s\",\n", d->constraint ? d->constraint : ""); |
9db4e0ec | 292 | |
a995e389 RH |
293 | printf (" %smode,\n", GET_MODE_NAME (d->mode)); |
294 | ||
dfac187e BS |
295 | printf (" %d,\n", d->strict_low); |
296 | ||
297 | printf (" %d\n", d->eliminable); | |
a995e389 RH |
298 | |
299 | printf(" },\n"); | |
300 | } | |
301 | printf("};\n\n\n"); | |
302 | } | |
303 | ||
304 | static void | |
305 | output_insn_data () | |
306 | { | |
307 | register struct data *d; | |
308 | int name_offset = 0; | |
309 | int next_name_offset; | |
310 | const char * last_name = 0; | |
311 | const char * next_name = 0; | |
312 | register struct data *n; | |
313 | ||
314 | for (n = idata, next_name_offset = 1; n; n = n->next, next_name_offset++) | |
315 | if (n->name) | |
9db4e0ec | 316 | { |
a995e389 RH |
317 | next_name = n->name; |
318 | break; | |
9db4e0ec | 319 | } |
9db4e0ec | 320 | |
a995e389 | 321 | printf ("\nconst struct insn_data insn_data[] = \n{\n"); |
9db4e0ec | 322 | |
a995e389 | 323 | for (d = idata; d; d = d->next) |
9db4e0ec | 324 | { |
a995e389 RH |
325 | printf (" {\n"); |
326 | ||
327 | if (d->name) | |
9db4e0ec | 328 | { |
a995e389 RH |
329 | printf (" \"%s\",\n", d->name); |
330 | name_offset = 0; | |
331 | last_name = d->name; | |
332 | next_name = 0; | |
333 | for (n = d->next, next_name_offset = 1; n; | |
334 | n = n->next, next_name_offset++) | |
9db4e0ec | 335 | { |
a995e389 RH |
336 | if (n->name) |
337 | { | |
338 | next_name = n->name; | |
339 | break; | |
340 | } | |
9db4e0ec | 341 | } |
9db4e0ec | 342 | } |
a995e389 | 343 | else |
9db4e0ec | 344 | { |
a995e389 RH |
345 | name_offset++; |
346 | if (next_name && (last_name == 0 | |
347 | || name_offset > next_name_offset / 2)) | |
348 | printf (" \"%s-%d\",\n", next_name, | |
349 | next_name_offset - name_offset); | |
350 | else | |
351 | printf (" \"%s+%d\",\n", last_name, name_offset); | |
9db4e0ec | 352 | } |
9db4e0ec | 353 | |
4bbf910e RH |
354 | switch (d->output_format) |
355 | { | |
356 | case INSN_OUTPUT_FORMAT_NONE: | |
357 | printf (" 0,\n"); | |
358 | break; | |
359 | case INSN_OUTPUT_FORMAT_SINGLE: | |
360 | printf (" \"%s\",\n", d->template); | |
361 | break; | |
362 | case INSN_OUTPUT_FORMAT_MULTI: | |
363 | case INSN_OUTPUT_FORMAT_FUNCTION: | |
4a71b24f | 364 | printf (" (const PTR) output_%d,\n", d->code_number); |
4bbf910e RH |
365 | break; |
366 | default: | |
367 | abort (); | |
368 | } | |
a995e389 RH |
369 | |
370 | if (d->name && d->name[0] != '*') | |
706b0f60 | 371 | printf (" (insn_gen_fn) gen_%s,\n", d->name); |
a995e389 RH |
372 | else |
373 | printf (" 0,\n"); | |
374 | ||
375 | printf (" &operand_data[%d],\n", d->operand_number); | |
376 | printf (" %d,\n", d->n_operands); | |
377 | printf (" %d,\n", d->n_dups); | |
4bbf910e RH |
378 | printf (" %d,\n", d->n_alternatives); |
379 | printf (" %d\n", d->output_format); | |
a995e389 RH |
380 | |
381 | printf(" },\n"); | |
9db4e0ec | 382 | } |
a995e389 RH |
383 | printf ("};\n\n\n"); |
384 | } | |
9db4e0ec | 385 | |
a995e389 RH |
386 | static void |
387 | output_get_insn_name () | |
388 | { | |
389 | printf ("const char *\n"); | |
390 | printf ("get_insn_name (code)\n"); | |
391 | printf (" int code;\n"); | |
392 | printf ("{\n"); | |
393 | printf (" return insn_data[code].name;\n"); | |
394 | printf ("}\n"); | |
9db4e0ec | 395 | } |
a995e389 | 396 | |
9db4e0ec | 397 | \f |
a995e389 RH |
398 | /* Stores in max_opno the largest operand number present in `part', if |
399 | that is larger than the previous value of max_opno, and the rest of | |
400 | the operand data into `d->operand[i]'. | |
9db4e0ec RK |
401 | |
402 | THIS_ADDRESS_P is nonzero if the containing rtx was an ADDRESS. | |
403 | THIS_STRICT_LOW is nonzero if the containing rtx was a STRICT_LOW_PART. */ | |
404 | ||
405 | static int max_opno; | |
406 | static int num_dups; | |
9db4e0ec RK |
407 | |
408 | static void | |
a995e389 RH |
409 | scan_operands (d, part, this_address_p, this_strict_low) |
410 | struct data *d; | |
9db4e0ec RK |
411 | rtx part; |
412 | int this_address_p; | |
413 | int this_strict_low; | |
414 | { | |
415 | register int i, j; | |
6f7d635c | 416 | register const char *format_ptr; |
9db4e0ec RK |
417 | int opno; |
418 | ||
419 | if (part == 0) | |
420 | return; | |
421 | ||
422 | switch (GET_CODE (part)) | |
423 | { | |
424 | case MATCH_OPERAND: | |
425 | opno = XINT (part, 0); | |
426 | if (opno > max_opno) | |
427 | max_opno = opno; | |
428 | if (max_opno >= MAX_MAX_OPERANDS) | |
5a806d65 | 429 | { |
8aeba909 | 430 | error ("Too many operands (%d) in definition %s.\n", |
a995e389 | 431 | max_opno + 1, get_insn_name (next_index_number)); |
5a806d65 RK |
432 | return; |
433 | } | |
a995e389 | 434 | if (d->operand[opno].seen) |
8aeba909 | 435 | error ("Definition %s specified operand number %d more than once.\n", |
a995e389 RH |
436 | get_insn_name (next_index_number), opno); |
437 | d->operand[opno].seen = 1; | |
438 | d->operand[opno].mode = GET_MODE (part); | |
439 | d->operand[opno].strict_low = this_strict_low; | |
440 | d->operand[opno].predicate = XSTR (part, 1); | |
441 | d->operand[opno].constraint = XSTR (part, 2); | |
88a56c2e HPN |
442 | if (XSTR (part, 2) != NULL && *XSTR (part, 2) != 0) |
443 | { | |
444 | strip_whitespace (XSTR (part, 2)); | |
445 | d->operand[opno].n_alternatives | |
446 | = n_occurrences (',', XSTR (part, 2)) + 1; | |
447 | } | |
a995e389 | 448 | d->operand[opno].address_p = this_address_p; |
dfac187e | 449 | d->operand[opno].eliminable = 1; |
9db4e0ec RK |
450 | return; |
451 | ||
452 | case MATCH_SCRATCH: | |
453 | opno = XINT (part, 0); | |
454 | if (opno > max_opno) | |
455 | max_opno = opno; | |
456 | if (max_opno >= MAX_MAX_OPERANDS) | |
5a806d65 | 457 | { |
8aeba909 | 458 | error ("Too many operands (%d) in definition %s.\n", |
a995e389 | 459 | max_opno + 1, get_insn_name (next_index_number)); |
5a806d65 RK |
460 | return; |
461 | } | |
a995e389 | 462 | if (d->operand[opno].seen) |
8aeba909 | 463 | error ("Definition %s specified operand number %d more than once.\n", |
a995e389 RH |
464 | get_insn_name (next_index_number), opno); |
465 | d->operand[opno].seen = 1; | |
466 | d->operand[opno].mode = GET_MODE (part); | |
467 | d->operand[opno].strict_low = 0; | |
468 | d->operand[opno].predicate = "scratch_operand"; | |
469 | d->operand[opno].constraint = XSTR (part, 1); | |
88a56c2e HPN |
470 | if (XSTR (part, 1) != NULL && *XSTR (part, 1) != 0) |
471 | { | |
472 | strip_whitespace (XSTR (part, 1)); | |
473 | d->operand[opno].n_alternatives | |
474 | = n_occurrences (',', XSTR (part, 1)) + 1; | |
475 | } | |
a995e389 | 476 | d->operand[opno].address_p = 0; |
dfac187e | 477 | d->operand[opno].eliminable = 0; |
9db4e0ec RK |
478 | return; |
479 | ||
480 | case MATCH_OPERATOR: | |
481 | case MATCH_PARALLEL: | |
482 | opno = XINT (part, 0); | |
483 | if (opno > max_opno) | |
484 | max_opno = opno; | |
485 | if (max_opno >= MAX_MAX_OPERANDS) | |
5a806d65 | 486 | { |
8aeba909 | 487 | error ("Too many operands (%d) in definition %s.\n", |
a995e389 | 488 | max_opno + 1, get_insn_name (next_index_number)); |
5a806d65 RK |
489 | return; |
490 | } | |
a995e389 | 491 | if (d->operand[opno].seen) |
8aeba909 | 492 | error ("Definition %s specified operand number %d more than once.\n", |
a995e389 RH |
493 | get_insn_name (next_index_number), opno); |
494 | d->operand[opno].seen = 1; | |
495 | d->operand[opno].mode = GET_MODE (part); | |
496 | d->operand[opno].strict_low = 0; | |
497 | d->operand[opno].predicate = XSTR (part, 1); | |
498 | d->operand[opno].constraint = 0; | |
499 | d->operand[opno].address_p = 0; | |
dfac187e | 500 | d->operand[opno].eliminable = 0; |
9db4e0ec | 501 | for (i = 0; i < XVECLEN (part, 2); i++) |
a995e389 | 502 | scan_operands (d, XVECEXP (part, 2, i), 0, 0); |
9db4e0ec RK |
503 | return; |
504 | ||
505 | case MATCH_DUP: | |
506 | case MATCH_OP_DUP: | |
ed18f94d | 507 | case MATCH_PAR_DUP: |
9db4e0ec RK |
508 | ++num_dups; |
509 | return; | |
510 | ||
511 | case ADDRESS: | |
a995e389 | 512 | scan_operands (d, XEXP (part, 0), 1, 0); |
9db4e0ec RK |
513 | return; |
514 | ||
515 | case STRICT_LOW_PART: | |
a995e389 | 516 | scan_operands (d, XEXP (part, 0), 0, 1); |
9db4e0ec | 517 | return; |
ccd043a9 RL |
518 | |
519 | default: | |
520 | break; | |
9db4e0ec RK |
521 | } |
522 | ||
523 | format_ptr = GET_RTX_FORMAT (GET_CODE (part)); | |
524 | ||
525 | for (i = 0; i < GET_RTX_LENGTH (GET_CODE (part)); i++) | |
526 | switch (*format_ptr++) | |
527 | { | |
528 | case 'e': | |
ccd043a9 | 529 | case 'u': |
a995e389 | 530 | scan_operands (d, XEXP (part, i), 0, 0); |
9db4e0ec RK |
531 | break; |
532 | case 'E': | |
533 | if (XVEC (part, i) != NULL) | |
534 | for (j = 0; j < XVECLEN (part, i); j++) | |
a995e389 | 535 | scan_operands (d, XVECEXP (part, i, j), 0, 0); |
9db4e0ec RK |
536 | break; |
537 | } | |
538 | } | |
a995e389 RH |
539 | |
540 | /* Compare two operands for content equality. */ | |
541 | ||
542 | static int | |
543 | compare_operands (d0, d1) | |
544 | struct operand_data *d0, *d1; | |
545 | { | |
c1b59dce | 546 | const char *p0, *p1; |
a995e389 RH |
547 | |
548 | p0 = d0->predicate; | |
549 | if (!p0) | |
550 | p0 = ""; | |
551 | p1 = d1->predicate; | |
552 | if (!p1) | |
553 | p1 = ""; | |
554 | if (strcmp (p0, p1) != 0) | |
555 | return 0; | |
556 | ||
19af6455 BS |
557 | p0 = d0->constraint; |
558 | if (!p0) | |
559 | p0 = ""; | |
560 | p1 = d1->constraint; | |
561 | if (!p1) | |
562 | p1 = ""; | |
563 | if (strcmp (p0, p1) != 0) | |
564 | return 0; | |
a995e389 RH |
565 | |
566 | if (d0->mode != d1->mode) | |
567 | return 0; | |
568 | ||
a995e389 RH |
569 | if (d0->strict_low != d1->strict_low) |
570 | return 0; | |
571 | ||
dfac187e BS |
572 | if (d0->eliminable != d1->eliminable) |
573 | return 0; | |
574 | ||
a995e389 RH |
575 | return 1; |
576 | } | |
577 | ||
578 | /* Scan the list of operands we've already committed to output and either | |
579 | find a subsequence that is the same, or allocate a new one at the end. */ | |
580 | ||
581 | static void | |
582 | place_operands (d) | |
583 | struct data *d; | |
584 | { | |
585 | struct operand_data *od, *od2; | |
586 | int i; | |
587 | ||
588 | if (d->n_operands == 0) | |
589 | { | |
590 | d->operand_number = 0; | |
591 | return; | |
592 | } | |
593 | ||
594 | /* Brute force substring search. */ | |
595 | for (od = odata, i = 0; od; od = od->next, i = 0) | |
596 | if (compare_operands (od, &d->operand[0])) | |
597 | { | |
598 | od2 = od->next; | |
599 | i = 1; | |
600 | while (1) | |
601 | { | |
602 | if (i == d->n_operands) | |
603 | goto full_match; | |
604 | if (od2 == NULL) | |
605 | goto partial_match; | |
606 | if (! compare_operands (od2, &d->operand[i])) | |
607 | break; | |
608 | ++i, od2 = od2->next; | |
609 | } | |
610 | } | |
611 | ||
612 | /* Either partial match at the end of the list, or no match. In either | |
613 | case, we tack on what operands are remaining to the end of the list. */ | |
614 | partial_match: | |
615 | d->operand_number = next_operand_number - i; | |
616 | for (; i < d->n_operands; ++i) | |
617 | { | |
618 | od2 = &d->operand[i]; | |
619 | *odata_end = od2; | |
620 | odata_end = &od2->next; | |
621 | od2->index = next_operand_number++; | |
622 | } | |
623 | *odata_end = NULL; | |
624 | return; | |
625 | ||
626 | full_match: | |
627 | d->operand_number = od->index; | |
628 | return; | |
629 | } | |
630 | ||
9db4e0ec RK |
631 | \f |
632 | /* Process an assembler template from a define_insn or a define_peephole. | |
633 | It is either the assembler code template, a list of assembler code | |
634 | templates, or C code to generate the assembler code template. */ | |
635 | ||
636 | static void | |
637 | process_template (d, template) | |
638 | struct data *d; | |
3cce094d | 639 | const char *template; |
9db4e0ec | 640 | { |
3cce094d | 641 | register const char *cp; |
9db4e0ec RK |
642 | register int i; |
643 | ||
4bbf910e RH |
644 | /* Templates starting with * contain straight code to be run. */ |
645 | if (template[0] == '*') | |
9db4e0ec | 646 | { |
4bbf910e RH |
647 | d->template = 0; |
648 | d->output_format = INSN_OUTPUT_FORMAT_FUNCTION; | |
9db4e0ec | 649 | |
a94ae8f5 | 650 | printf ("\nstatic const char *output_%d PARAMS ((rtx *, rtx));\n", |
4bbf910e RH |
651 | d->code_number); |
652 | puts ("\nstatic const char *"); | |
653 | printf ("output_%d (operands, insn)\n", d->code_number); | |
654 | puts (" rtx *operands ATTRIBUTE_UNUSED;"); | |
655 | puts (" rtx insn ATTRIBUTE_UNUSED;"); | |
656 | puts ("{"); | |
657 | ||
658 | puts (template + 1); | |
659 | puts ("}"); | |
660 | } | |
9db4e0ec RK |
661 | |
662 | /* If the assembler code template starts with a @ it is a newline-separated | |
4bbf910e RH |
663 | list of assembler code templates, one for each alternative. */ |
664 | else if (template[0] == '@') | |
9db4e0ec | 665 | { |
4bbf910e RH |
666 | d->template = 0; |
667 | d->output_format = INSN_OUTPUT_FORMAT_MULTI; | |
9db4e0ec | 668 | |
4bbf910e | 669 | printf ("\nstatic const char * const output_%d[] = {\n", d->code_number); |
9db4e0ec RK |
670 | |
671 | for (i = 0, cp = &template[1]; *cp; ) | |
672 | { | |
673 | while (*cp == '\n' || *cp == ' ' || *cp== '\t') | |
674 | cp++; | |
675 | ||
4bbf910e | 676 | printf (" \""); |
9db4e0ec | 677 | while (*cp != '\n' && *cp != '\0') |
2f013c71 RK |
678 | { |
679 | putchar (*cp); | |
680 | cp++; | |
681 | } | |
9db4e0ec RK |
682 | |
683 | printf ("\",\n"); | |
684 | i++; | |
685 | } | |
686 | ||
4bbf910e | 687 | printf ("};\n"); |
9db4e0ec RK |
688 | } |
689 | else | |
690 | { | |
4bbf910e RH |
691 | d->template = template; |
692 | d->output_format = INSN_OUTPUT_FORMAT_SINGLE; | |
9db4e0ec | 693 | } |
9db4e0ec RK |
694 | } |
695 | \f | |
696 | /* Check insn D for consistency in number of constraint alternatives. */ | |
697 | ||
698 | static void | |
699 | validate_insn_alternatives (d) | |
700 | struct data *d; | |
701 | { | |
702 | register int n = 0, start; | |
a995e389 RH |
703 | |
704 | /* Make sure all the operands have the same number of alternatives | |
705 | in their constraints. Let N be that number. */ | |
9db4e0ec | 706 | for (start = 0; start < d->n_operands; start++) |
a995e389 | 707 | if (d->operand[start].n_alternatives > 0) |
9db4e0ec RK |
708 | { |
709 | if (n == 0) | |
a995e389 RH |
710 | n = d->operand[start].n_alternatives; |
711 | else if (n != d->operand[start].n_alternatives) | |
8aeba909 | 712 | error ("wrong number of alternatives in operand %d of insn %s", |
a995e389 | 713 | start, get_insn_name (d->index_number)); |
9db4e0ec | 714 | } |
a995e389 | 715 | |
9db4e0ec RK |
716 | /* Record the insn's overall number of alternatives. */ |
717 | d->n_alternatives = n; | |
718 | } | |
719 | \f | |
a995e389 RH |
720 | /* Look at a define_insn just read. Assign its code number. Record |
721 | on idata the template and the number of arguments. If the insn has | |
722 | a hairy output action, output a function for now. */ | |
9db4e0ec RK |
723 | |
724 | static void | |
725 | gen_insn (insn) | |
726 | rtx insn; | |
727 | { | |
728 | register struct data *d = (struct data *) xmalloc (sizeof (struct data)); | |
729 | register int i; | |
730 | ||
731 | d->code_number = next_code_number++; | |
732 | d->index_number = next_index_number; | |
733 | if (XSTR (insn, 0)[0]) | |
734 | d->name = XSTR (insn, 0); | |
735 | else | |
736 | d->name = 0; | |
737 | ||
738 | /* Build up the list in the same order as the insns are seen | |
739 | in the machine description. */ | |
740 | d->next = 0; | |
a995e389 RH |
741 | *idata_end = d; |
742 | idata_end = &d->next; | |
9db4e0ec RK |
743 | |
744 | max_opno = -1; | |
745 | num_dups = 0; | |
a995e389 | 746 | memset (d->operand, 0, sizeof (d->operand)); |
9db4e0ec RK |
747 | |
748 | for (i = 0; i < XVECLEN (insn, 1); i++) | |
a995e389 | 749 | scan_operands (d, XVECEXP (insn, 1, i), 0, 0); |
9db4e0ec RK |
750 | |
751 | d->n_operands = max_opno + 1; | |
752 | d->n_dups = num_dups; | |
753 | ||
9db4e0ec | 754 | validate_insn_alternatives (d); |
a995e389 | 755 | place_operands (d); |
9db4e0ec RK |
756 | process_template (d, XSTR (insn, 3)); |
757 | } | |
758 | \f | |
759 | /* Look at a define_peephole just read. Assign its code number. | |
a995e389 | 760 | Record on idata the template and the number of arguments. |
9db4e0ec RK |
761 | If the insn has a hairy output action, output it now. */ |
762 | ||
763 | static void | |
764 | gen_peephole (peep) | |
765 | rtx peep; | |
766 | { | |
767 | register struct data *d = (struct data *) xmalloc (sizeof (struct data)); | |
768 | register int i; | |
769 | ||
770 | d->code_number = next_code_number++; | |
771 | d->index_number = next_index_number; | |
772 | d->name = 0; | |
773 | ||
774 | /* Build up the list in the same order as the insns are seen | |
775 | in the machine description. */ | |
776 | d->next = 0; | |
a995e389 RH |
777 | *idata_end = d; |
778 | idata_end = &d->next; | |
9db4e0ec RK |
779 | |
780 | max_opno = -1; | |
a995e389 RH |
781 | num_dups = 0; |
782 | memset (d->operand, 0, sizeof (d->operand)); | |
783 | ||
784 | /* Get the number of operands by scanning all the patterns of the | |
785 | peephole optimizer. But ignore all the rest of the information | |
786 | thus obtained. */ | |
9db4e0ec | 787 | for (i = 0; i < XVECLEN (peep, 0); i++) |
a995e389 | 788 | scan_operands (d, XVECEXP (peep, 0, i), 0, 0); |
9db4e0ec RK |
789 | |
790 | d->n_operands = max_opno + 1; | |
791 | d->n_dups = 0; | |
792 | ||
9db4e0ec | 793 | validate_insn_alternatives (d); |
a995e389 | 794 | place_operands (d); |
9db4e0ec RK |
795 | process_template (d, XSTR (peep, 2)); |
796 | } | |
797 | \f | |
798 | /* Process a define_expand just read. Assign its code number, | |
799 | only for the purposes of `insn_gen_function'. */ | |
800 | ||
801 | static void | |
802 | gen_expand (insn) | |
803 | rtx insn; | |
804 | { | |
805 | register struct data *d = (struct data *) xmalloc (sizeof (struct data)); | |
806 | register int i; | |
807 | ||
808 | d->code_number = next_code_number++; | |
809 | d->index_number = next_index_number; | |
810 | if (XSTR (insn, 0)[0]) | |
811 | d->name = XSTR (insn, 0); | |
812 | else | |
813 | d->name = 0; | |
814 | ||
815 | /* Build up the list in the same order as the insns are seen | |
816 | in the machine description. */ | |
817 | d->next = 0; | |
a995e389 RH |
818 | *idata_end = d; |
819 | idata_end = &d->next; | |
9db4e0ec RK |
820 | |
821 | max_opno = -1; | |
822 | num_dups = 0; | |
a995e389 | 823 | memset (d->operand, 0, sizeof (d->operand)); |
9db4e0ec RK |
824 | |
825 | /* Scan the operands to get the specified predicates and modes, | |
826 | since expand_binop needs to know them. */ | |
827 | ||
9db4e0ec RK |
828 | if (XVEC (insn, 1)) |
829 | for (i = 0; i < XVECLEN (insn, 1); i++) | |
a995e389 | 830 | scan_operands (d, XVECEXP (insn, 1, i), 0, 0); |
9db4e0ec RK |
831 | |
832 | d->n_operands = max_opno + 1; | |
833 | d->n_dups = num_dups; | |
9db4e0ec | 834 | d->template = 0; |
4bbf910e | 835 | d->output_format = INSN_OUTPUT_FORMAT_NONE; |
a995e389 | 836 | |
9db4e0ec | 837 | validate_insn_alternatives (d); |
a995e389 | 838 | place_operands (d); |
9db4e0ec RK |
839 | } |
840 | \f | |
841 | /* Process a define_split just read. Assign its code number, | |
842 | only for reasons of consistency and to simplify genrecog. */ | |
843 | ||
9db4e0ec RK |
844 | static void |
845 | gen_split (split) | |
846 | rtx split; | |
847 | { | |
848 | register struct data *d = (struct data *) xmalloc (sizeof (struct data)); | |
849 | register int i; | |
850 | ||
851 | d->code_number = next_code_number++; | |
852 | d->index_number = next_index_number; | |
853 | d->name = 0; | |
854 | ||
855 | /* Build up the list in the same order as the insns are seen | |
856 | in the machine description. */ | |
857 | d->next = 0; | |
a995e389 RH |
858 | *idata_end = d; |
859 | idata_end = &d->next; | |
9db4e0ec RK |
860 | |
861 | max_opno = -1; | |
862 | num_dups = 0; | |
a995e389 | 863 | memset (d->operand, 0, sizeof (d->operand)); |
9db4e0ec | 864 | |
a995e389 RH |
865 | /* Get the number of operands by scanning all the patterns of the |
866 | split patterns. But ignore all the rest of the information thus | |
867 | obtained. */ | |
9db4e0ec | 868 | for (i = 0; i < XVECLEN (split, 0); i++) |
a995e389 | 869 | scan_operands (d, XVECEXP (split, 0, i), 0, 0); |
9db4e0ec RK |
870 | |
871 | d->n_operands = max_opno + 1; | |
9db4e0ec | 872 | d->n_dups = 0; |
42495ca0 | 873 | d->n_alternatives = 0; |
9db4e0ec | 874 | d->template = 0; |
4bbf910e | 875 | d->output_format = INSN_OUTPUT_FORMAT_NONE; |
a995e389 RH |
876 | |
877 | place_operands (d); | |
9db4e0ec RK |
878 | } |
879 | \f | |
2778b98d | 880 | PTR |
9db4e0ec | 881 | xmalloc (size) |
2778b98d | 882 | size_t size; |
9db4e0ec | 883 | { |
2778b98d | 884 | register PTR val = (PTR) malloc (size); |
9db4e0ec RK |
885 | |
886 | if (val == 0) | |
887 | fatal ("virtual memory exhausted"); | |
888 | return val; | |
889 | } | |
890 | ||
2778b98d | 891 | PTR |
470b68c0 RH |
892 | xrealloc (old, size) |
893 | PTR old; | |
2778b98d | 894 | size_t size; |
9db4e0ec | 895 | { |
470b68c0 | 896 | register PTR ptr; |
09d83d25 | 897 | if (old) |
470b68c0 RH |
898 | ptr = (PTR) realloc (old, size); |
899 | else | |
900 | ptr = (PTR) malloc (size); | |
901 | if (!ptr) | |
9db4e0ec | 902 | fatal ("virtual memory exhausted"); |
470b68c0 | 903 | return ptr; |
9db4e0ec RK |
904 | } |
905 | ||
a94ae8f5 | 906 | extern int main PARAMS ((int, char **)); |
c1b59dce | 907 | |
9db4e0ec RK |
908 | int |
909 | main (argc, argv) | |
910 | int argc; | |
911 | char **argv; | |
912 | { | |
913 | rtx desc; | |
914 | FILE *infile; | |
9db4e0ec RK |
915 | register int c; |
916 | ||
f8b6598e | 917 | progname = "genoutput"; |
9db4e0ec RK |
918 | obstack_init (rtl_obstack); |
919 | ||
920 | if (argc <= 1) | |
921 | fatal ("No input file name."); | |
922 | ||
923 | infile = fopen (argv[1], "r"); | |
924 | if (infile == 0) | |
925 | { | |
926 | perror (argv[1]); | |
c1b59dce | 927 | return (FATAL_EXIT_CODE); |
9db4e0ec | 928 | } |
bcdaba58 | 929 | read_rtx_filename = argv[1]; |
9db4e0ec | 930 | |
9db4e0ec RK |
931 | output_prologue (); |
932 | next_code_number = 0; | |
933 | next_index_number = 0; | |
9db4e0ec RK |
934 | |
935 | /* Read the machine description. */ | |
936 | ||
937 | while (1) | |
938 | { | |
939 | c = read_skip_spaces (infile); | |
940 | if (c == EOF) | |
941 | break; | |
942 | ungetc (c, infile); | |
943 | ||
944 | desc = read_rtx (infile); | |
945 | if (GET_CODE (desc) == DEFINE_INSN) | |
946 | gen_insn (desc); | |
947 | if (GET_CODE (desc) == DEFINE_PEEPHOLE) | |
948 | gen_peephole (desc); | |
949 | if (GET_CODE (desc) == DEFINE_EXPAND) | |
950 | gen_expand (desc); | |
ede7cd44 RH |
951 | if (GET_CODE (desc) == DEFINE_SPLIT |
952 | || GET_CODE (desc) == DEFINE_PEEPHOLE2) | |
9db4e0ec RK |
953 | gen_split (desc); |
954 | next_index_number++; | |
955 | } | |
956 | ||
a995e389 RH |
957 | printf("\n\n"); |
958 | output_predicate_decls (); | |
959 | output_operand_data (); | |
960 | output_insn_data (); | |
961 | output_get_insn_name (); | |
9db4e0ec RK |
962 | |
963 | fflush (stdout); | |
c1b59dce | 964 | return (ferror (stdout) != 0 || have_error |
6a270722 | 965 | ? FATAL_EXIT_CODE : SUCCESS_EXIT_CODE); |
9db4e0ec RK |
966 | } |
967 | ||
968 | static int | |
969 | n_occurrences (c, s) | |
d149d5f5 | 970 | int c; |
3cce094d | 971 | const char *s; |
9db4e0ec RK |
972 | { |
973 | int n = 0; | |
974 | while (*s) | |
975 | n += (*s++ == c); | |
976 | return n; | |
977 | } | |
88a56c2e HPN |
978 | |
979 | /* Remove whitespace in `s' by moving up characters until the end. */ | |
980 | static void | |
981 | strip_whitespace (s) | |
982 | char *s; | |
983 | { | |
984 | char *p = s; | |
985 | int ch; | |
986 | ||
987 | while ((ch = *s++) != '\0') | |
988 | if (! ISSPACE (ch)) | |
989 | *p++ = ch; | |
990 | ||
991 | *p = '\0'; | |
992 | } |