]>
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 | ||
a94ae8f5 | 106 | static int n_occurrences PARAMS ((int, 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 KG |
187 | static void place_operands PARAMS ((struct data *)); |
188 | static void process_template PARAMS ((struct data *, char *)); | |
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)); | |
194 | static int n_occurrences PARAMS ((int, char *)); | |
56c0e996 | 195 | \f |
a995e389 RH |
196 | const char * |
197 | get_insn_name (index) | |
8aeba909 RH |
198 | int index; |
199 | { | |
200 | static char buf[100]; | |
201 | ||
202 | struct data *i, *last_named = NULL; | |
a995e389 | 203 | for (i = idata; i ; i = i->next) |
8aeba909 RH |
204 | { |
205 | if (i->index_number == index) | |
206 | return i->name; | |
207 | if (i->name) | |
208 | last_named = i; | |
209 | } | |
210 | ||
211 | if (last_named) | |
212 | sprintf(buf, "%s+%d", last_named->name, index - last_named->index_number); | |
213 | else | |
214 | sprintf(buf, "insn %d", index); | |
215 | ||
216 | return buf; | |
217 | } | |
218 | ||
9db4e0ec RK |
219 | static void |
220 | output_prologue () | |
221 | { | |
9db4e0ec RK |
222 | printf ("/* Generated automatically by the program `genoutput'\n\ |
223 | from the machine description file `md'. */\n\n"); | |
224 | ||
225 | printf ("#include \"config.h\"\n"); | |
729da3f5 | 226 | printf ("#include \"system.h\"\n"); |
ccd043a9 | 227 | printf ("#include \"flags.h\"\n"); |
3bc9f12b | 228 | printf ("#include \"ggc.h\"\n"); |
9db4e0ec | 229 | printf ("#include \"rtl.h\"\n"); |
6baf1cc8 | 230 | printf ("#include \"tm_p.h\"\n"); |
49ad7cfa | 231 | printf ("#include \"function.h\"\n"); |
9db4e0ec RK |
232 | printf ("#include \"regs.h\"\n"); |
233 | printf ("#include \"hard-reg-set.h\"\n"); | |
234 | printf ("#include \"real.h\"\n"); | |
235 | printf ("#include \"insn-config.h\"\n\n"); | |
236 | printf ("#include \"conditions.h\"\n"); | |
237 | printf ("#include \"insn-flags.h\"\n"); | |
238 | printf ("#include \"insn-attr.h\"\n\n"); | |
239 | printf ("#include \"insn-codes.h\"\n\n"); | |
240 | printf ("#include \"recog.h\"\n\n"); | |
c3fc86c9 | 241 | printf ("#include \"toplev.h\"\n"); |
9db4e0ec RK |
242 | printf ("#include \"output.h\"\n"); |
243 | } | |
244 | ||
a995e389 RH |
245 | |
246 | /* We need to define all predicates used. Keep a list of those we | |
247 | have defined so far. There normally aren't very many predicates | |
248 | used, so a linked list should be fast enough. */ | |
249 | ||
9db4e0ec | 250 | static void |
a995e389 | 251 | output_predicate_decls () |
9db4e0ec | 252 | { |
c1b59dce | 253 | struct predicate { const char *name; struct predicate *next; } *predicates = 0; |
a995e389 RH |
254 | register struct operand_data *d; |
255 | struct predicate *p; | |
9db4e0ec | 256 | |
a995e389 RH |
257 | for (d = odata; d; d = d->next) |
258 | if (d->predicate && d->predicate[0]) | |
259 | { | |
260 | for (p = predicates; p; p = p->next) | |
261 | if (strcmp (p->name, d->predicate) == 0) | |
262 | break; | |
9db4e0ec | 263 | |
a995e389 RH |
264 | if (p == 0) |
265 | { | |
a94ae8f5 | 266 | printf ("extern int %s PARAMS ((rtx, enum machine_mode));\n", |
a995e389 RH |
267 | d->predicate); |
268 | p = (struct predicate *) alloca (sizeof (struct predicate)); | |
269 | p->name = d->predicate; | |
270 | p->next = predicates; | |
271 | predicates = p; | |
272 | } | |
273 | } | |
274 | ||
275 | printf ("\n\n"); | |
276 | } | |
9db4e0ec | 277 | |
a995e389 RH |
278 | static void |
279 | output_operand_data () | |
280 | { | |
281 | register struct operand_data *d; | |
282 | ||
283 | printf ("\nstatic const struct insn_operand_data operand_data[] = \n{\n"); | |
284 | ||
285 | for (d = odata; d; d = d->next) | |
9db4e0ec | 286 | { |
a995e389 RH |
287 | printf (" {\n"); |
288 | ||
289 | printf (" %s,\n", | |
290 | d->predicate && d->predicate[0] ? d->predicate : "0"); | |
291 | ||
19af6455 | 292 | printf (" \"%s\",\n", d->constraint ? d->constraint : ""); |
9db4e0ec | 293 | |
a995e389 RH |
294 | printf (" %smode,\n", GET_MODE_NAME (d->mode)); |
295 | ||
dfac187e BS |
296 | printf (" %d,\n", d->strict_low); |
297 | ||
298 | printf (" %d\n", d->eliminable); | |
a995e389 RH |
299 | |
300 | printf(" },\n"); | |
301 | } | |
302 | printf("};\n\n\n"); | |
303 | } | |
304 | ||
305 | static void | |
306 | output_insn_data () | |
307 | { | |
308 | register struct data *d; | |
309 | int name_offset = 0; | |
310 | int next_name_offset; | |
311 | const char * last_name = 0; | |
312 | const char * next_name = 0; | |
313 | register struct data *n; | |
314 | ||
315 | for (n = idata, next_name_offset = 1; n; n = n->next, next_name_offset++) | |
316 | if (n->name) | |
9db4e0ec | 317 | { |
a995e389 RH |
318 | next_name = n->name; |
319 | break; | |
9db4e0ec | 320 | } |
9db4e0ec | 321 | |
a995e389 | 322 | printf ("\nconst struct insn_data insn_data[] = \n{\n"); |
9db4e0ec | 323 | |
a995e389 | 324 | for (d = idata; d; d = d->next) |
9db4e0ec | 325 | { |
a995e389 RH |
326 | printf (" {\n"); |
327 | ||
328 | if (d->name) | |
9db4e0ec | 329 | { |
a995e389 RH |
330 | printf (" \"%s\",\n", d->name); |
331 | name_offset = 0; | |
332 | last_name = d->name; | |
333 | next_name = 0; | |
334 | for (n = d->next, next_name_offset = 1; n; | |
335 | n = n->next, next_name_offset++) | |
9db4e0ec | 336 | { |
a995e389 RH |
337 | if (n->name) |
338 | { | |
339 | next_name = n->name; | |
340 | break; | |
341 | } | |
9db4e0ec | 342 | } |
9db4e0ec | 343 | } |
a995e389 | 344 | else |
9db4e0ec | 345 | { |
a995e389 RH |
346 | name_offset++; |
347 | if (next_name && (last_name == 0 | |
348 | || name_offset > next_name_offset / 2)) | |
349 | printf (" \"%s-%d\",\n", next_name, | |
350 | next_name_offset - name_offset); | |
351 | else | |
352 | printf (" \"%s+%d\",\n", last_name, name_offset); | |
9db4e0ec | 353 | } |
9db4e0ec | 354 | |
4bbf910e RH |
355 | switch (d->output_format) |
356 | { | |
357 | case INSN_OUTPUT_FORMAT_NONE: | |
358 | printf (" 0,\n"); | |
359 | break; | |
360 | case INSN_OUTPUT_FORMAT_SINGLE: | |
361 | printf (" \"%s\",\n", d->template); | |
362 | break; | |
363 | case INSN_OUTPUT_FORMAT_MULTI: | |
364 | case INSN_OUTPUT_FORMAT_FUNCTION: | |
4a71b24f | 365 | printf (" (const PTR) output_%d,\n", d->code_number); |
4bbf910e RH |
366 | break; |
367 | default: | |
368 | abort (); | |
369 | } | |
a995e389 RH |
370 | |
371 | if (d->name && d->name[0] != '*') | |
706b0f60 | 372 | printf (" (insn_gen_fn) gen_%s,\n", d->name); |
a995e389 RH |
373 | else |
374 | printf (" 0,\n"); | |
375 | ||
376 | printf (" &operand_data[%d],\n", d->operand_number); | |
377 | printf (" %d,\n", d->n_operands); | |
378 | printf (" %d,\n", d->n_dups); | |
4bbf910e RH |
379 | printf (" %d,\n", d->n_alternatives); |
380 | printf (" %d\n", d->output_format); | |
a995e389 RH |
381 | |
382 | printf(" },\n"); | |
9db4e0ec | 383 | } |
a995e389 RH |
384 | printf ("};\n\n\n"); |
385 | } | |
9db4e0ec | 386 | |
a995e389 RH |
387 | static void |
388 | output_get_insn_name () | |
389 | { | |
390 | printf ("const char *\n"); | |
391 | printf ("get_insn_name (code)\n"); | |
392 | printf (" int code;\n"); | |
393 | printf ("{\n"); | |
394 | printf (" return insn_data[code].name;\n"); | |
395 | printf ("}\n"); | |
9db4e0ec | 396 | } |
a995e389 | 397 | |
9db4e0ec | 398 | \f |
a995e389 RH |
399 | /* Stores in max_opno the largest operand number present in `part', if |
400 | that is larger than the previous value of max_opno, and the rest of | |
401 | the operand data into `d->operand[i]'. | |
9db4e0ec RK |
402 | |
403 | THIS_ADDRESS_P is nonzero if the containing rtx was an ADDRESS. | |
404 | THIS_STRICT_LOW is nonzero if the containing rtx was a STRICT_LOW_PART. */ | |
405 | ||
406 | static int max_opno; | |
407 | static int num_dups; | |
9db4e0ec RK |
408 | |
409 | static void | |
a995e389 RH |
410 | scan_operands (d, part, this_address_p, this_strict_low) |
411 | struct data *d; | |
9db4e0ec RK |
412 | rtx part; |
413 | int this_address_p; | |
414 | int this_strict_low; | |
415 | { | |
416 | register int i, j; | |
6f7d635c | 417 | register const char *format_ptr; |
9db4e0ec RK |
418 | int opno; |
419 | ||
420 | if (part == 0) | |
421 | return; | |
422 | ||
423 | switch (GET_CODE (part)) | |
424 | { | |
425 | case MATCH_OPERAND: | |
426 | opno = XINT (part, 0); | |
427 | if (opno > max_opno) | |
428 | max_opno = opno; | |
429 | if (max_opno >= MAX_MAX_OPERANDS) | |
5a806d65 | 430 | { |
8aeba909 | 431 | error ("Too many operands (%d) in definition %s.\n", |
a995e389 | 432 | max_opno + 1, get_insn_name (next_index_number)); |
5a806d65 RK |
433 | return; |
434 | } | |
a995e389 | 435 | if (d->operand[opno].seen) |
8aeba909 | 436 | error ("Definition %s specified operand number %d more than once.\n", |
a995e389 RH |
437 | get_insn_name (next_index_number), opno); |
438 | d->operand[opno].seen = 1; | |
439 | d->operand[opno].mode = GET_MODE (part); | |
440 | d->operand[opno].strict_low = this_strict_low; | |
441 | d->operand[opno].predicate = XSTR (part, 1); | |
442 | d->operand[opno].constraint = XSTR (part, 2); | |
88a56c2e HPN |
443 | if (XSTR (part, 2) != NULL && *XSTR (part, 2) != 0) |
444 | { | |
445 | strip_whitespace (XSTR (part, 2)); | |
446 | d->operand[opno].n_alternatives | |
447 | = n_occurrences (',', XSTR (part, 2)) + 1; | |
448 | } | |
a995e389 | 449 | d->operand[opno].address_p = this_address_p; |
dfac187e | 450 | d->operand[opno].eliminable = 1; |
9db4e0ec RK |
451 | return; |
452 | ||
453 | case MATCH_SCRATCH: | |
454 | opno = XINT (part, 0); | |
455 | if (opno > max_opno) | |
456 | max_opno = opno; | |
457 | if (max_opno >= MAX_MAX_OPERANDS) | |
5a806d65 | 458 | { |
8aeba909 | 459 | error ("Too many operands (%d) in definition %s.\n", |
a995e389 | 460 | max_opno + 1, get_insn_name (next_index_number)); |
5a806d65 RK |
461 | return; |
462 | } | |
a995e389 | 463 | if (d->operand[opno].seen) |
8aeba909 | 464 | error ("Definition %s specified operand number %d more than once.\n", |
a995e389 RH |
465 | get_insn_name (next_index_number), opno); |
466 | d->operand[opno].seen = 1; | |
467 | d->operand[opno].mode = GET_MODE (part); | |
468 | d->operand[opno].strict_low = 0; | |
469 | d->operand[opno].predicate = "scratch_operand"; | |
470 | d->operand[opno].constraint = XSTR (part, 1); | |
88a56c2e HPN |
471 | if (XSTR (part, 1) != NULL && *XSTR (part, 1) != 0) |
472 | { | |
473 | strip_whitespace (XSTR (part, 1)); | |
474 | d->operand[opno].n_alternatives | |
475 | = n_occurrences (',', XSTR (part, 1)) + 1; | |
476 | } | |
a995e389 | 477 | d->operand[opno].address_p = 0; |
dfac187e | 478 | d->operand[opno].eliminable = 0; |
9db4e0ec RK |
479 | return; |
480 | ||
481 | case MATCH_OPERATOR: | |
482 | case MATCH_PARALLEL: | |
483 | opno = XINT (part, 0); | |
484 | if (opno > max_opno) | |
485 | max_opno = opno; | |
486 | if (max_opno >= MAX_MAX_OPERANDS) | |
5a806d65 | 487 | { |
8aeba909 | 488 | error ("Too many operands (%d) in definition %s.\n", |
a995e389 | 489 | max_opno + 1, get_insn_name (next_index_number)); |
5a806d65 RK |
490 | return; |
491 | } | |
a995e389 | 492 | if (d->operand[opno].seen) |
8aeba909 | 493 | error ("Definition %s specified operand number %d more than once.\n", |
a995e389 RH |
494 | get_insn_name (next_index_number), opno); |
495 | d->operand[opno].seen = 1; | |
496 | d->operand[opno].mode = GET_MODE (part); | |
497 | d->operand[opno].strict_low = 0; | |
498 | d->operand[opno].predicate = XSTR (part, 1); | |
499 | d->operand[opno].constraint = 0; | |
500 | d->operand[opno].address_p = 0; | |
dfac187e | 501 | d->operand[opno].eliminable = 0; |
9db4e0ec | 502 | for (i = 0; i < XVECLEN (part, 2); i++) |
a995e389 | 503 | scan_operands (d, XVECEXP (part, 2, i), 0, 0); |
9db4e0ec RK |
504 | return; |
505 | ||
506 | case MATCH_DUP: | |
507 | case MATCH_OP_DUP: | |
ed18f94d | 508 | case MATCH_PAR_DUP: |
9db4e0ec RK |
509 | ++num_dups; |
510 | return; | |
511 | ||
512 | case ADDRESS: | |
a995e389 | 513 | scan_operands (d, XEXP (part, 0), 1, 0); |
9db4e0ec RK |
514 | return; |
515 | ||
516 | case STRICT_LOW_PART: | |
a995e389 | 517 | scan_operands (d, XEXP (part, 0), 0, 1); |
9db4e0ec | 518 | return; |
ccd043a9 RL |
519 | |
520 | default: | |
521 | break; | |
9db4e0ec RK |
522 | } |
523 | ||
524 | format_ptr = GET_RTX_FORMAT (GET_CODE (part)); | |
525 | ||
526 | for (i = 0; i < GET_RTX_LENGTH (GET_CODE (part)); i++) | |
527 | switch (*format_ptr++) | |
528 | { | |
529 | case 'e': | |
ccd043a9 | 530 | case 'u': |
a995e389 | 531 | scan_operands (d, XEXP (part, i), 0, 0); |
9db4e0ec RK |
532 | break; |
533 | case 'E': | |
534 | if (XVEC (part, i) != NULL) | |
535 | for (j = 0; j < XVECLEN (part, i); j++) | |
a995e389 | 536 | scan_operands (d, XVECEXP (part, i, j), 0, 0); |
9db4e0ec RK |
537 | break; |
538 | } | |
539 | } | |
a995e389 RH |
540 | |
541 | /* Compare two operands for content equality. */ | |
542 | ||
543 | static int | |
544 | compare_operands (d0, d1) | |
545 | struct operand_data *d0, *d1; | |
546 | { | |
c1b59dce | 547 | const char *p0, *p1; |
a995e389 RH |
548 | |
549 | p0 = d0->predicate; | |
550 | if (!p0) | |
551 | p0 = ""; | |
552 | p1 = d1->predicate; | |
553 | if (!p1) | |
554 | p1 = ""; | |
555 | if (strcmp (p0, p1) != 0) | |
556 | return 0; | |
557 | ||
19af6455 BS |
558 | p0 = d0->constraint; |
559 | if (!p0) | |
560 | p0 = ""; | |
561 | p1 = d1->constraint; | |
562 | if (!p1) | |
563 | p1 = ""; | |
564 | if (strcmp (p0, p1) != 0) | |
565 | return 0; | |
a995e389 RH |
566 | |
567 | if (d0->mode != d1->mode) | |
568 | return 0; | |
569 | ||
a995e389 RH |
570 | if (d0->strict_low != d1->strict_low) |
571 | return 0; | |
572 | ||
dfac187e BS |
573 | if (d0->eliminable != d1->eliminable) |
574 | return 0; | |
575 | ||
a995e389 RH |
576 | return 1; |
577 | } | |
578 | ||
579 | /* Scan the list of operands we've already committed to output and either | |
580 | find a subsequence that is the same, or allocate a new one at the end. */ | |
581 | ||
582 | static void | |
583 | place_operands (d) | |
584 | struct data *d; | |
585 | { | |
586 | struct operand_data *od, *od2; | |
587 | int i; | |
588 | ||
589 | if (d->n_operands == 0) | |
590 | { | |
591 | d->operand_number = 0; | |
592 | return; | |
593 | } | |
594 | ||
595 | /* Brute force substring search. */ | |
596 | for (od = odata, i = 0; od; od = od->next, i = 0) | |
597 | if (compare_operands (od, &d->operand[0])) | |
598 | { | |
599 | od2 = od->next; | |
600 | i = 1; | |
601 | while (1) | |
602 | { | |
603 | if (i == d->n_operands) | |
604 | goto full_match; | |
605 | if (od2 == NULL) | |
606 | goto partial_match; | |
607 | if (! compare_operands (od2, &d->operand[i])) | |
608 | break; | |
609 | ++i, od2 = od2->next; | |
610 | } | |
611 | } | |
612 | ||
613 | /* Either partial match at the end of the list, or no match. In either | |
614 | case, we tack on what operands are remaining to the end of the list. */ | |
615 | partial_match: | |
616 | d->operand_number = next_operand_number - i; | |
617 | for (; i < d->n_operands; ++i) | |
618 | { | |
619 | od2 = &d->operand[i]; | |
620 | *odata_end = od2; | |
621 | odata_end = &od2->next; | |
622 | od2->index = next_operand_number++; | |
623 | } | |
624 | *odata_end = NULL; | |
625 | return; | |
626 | ||
627 | full_match: | |
628 | d->operand_number = od->index; | |
629 | return; | |
630 | } | |
631 | ||
9db4e0ec RK |
632 | \f |
633 | /* Process an assembler template from a define_insn or a define_peephole. | |
634 | It is either the assembler code template, a list of assembler code | |
635 | templates, or C code to generate the assembler code template. */ | |
636 | ||
637 | static void | |
638 | process_template (d, template) | |
639 | struct data *d; | |
640 | char *template; | |
641 | { | |
642 | register char *cp; | |
643 | register int i; | |
644 | ||
4bbf910e RH |
645 | /* Templates starting with * contain straight code to be run. */ |
646 | if (template[0] == '*') | |
9db4e0ec | 647 | { |
4bbf910e RH |
648 | d->template = 0; |
649 | d->output_format = INSN_OUTPUT_FORMAT_FUNCTION; | |
9db4e0ec | 650 | |
a94ae8f5 | 651 | printf ("\nstatic const char *output_%d PARAMS ((rtx *, rtx));\n", |
4bbf910e RH |
652 | d->code_number); |
653 | puts ("\nstatic const char *"); | |
654 | printf ("output_%d (operands, insn)\n", d->code_number); | |
655 | puts (" rtx *operands ATTRIBUTE_UNUSED;"); | |
656 | puts (" rtx insn ATTRIBUTE_UNUSED;"); | |
657 | puts ("{"); | |
658 | ||
659 | puts (template + 1); | |
660 | puts ("}"); | |
661 | } | |
9db4e0ec RK |
662 | |
663 | /* If the assembler code template starts with a @ it is a newline-separated | |
4bbf910e RH |
664 | list of assembler code templates, one for each alternative. */ |
665 | else if (template[0] == '@') | |
9db4e0ec | 666 | { |
4bbf910e RH |
667 | d->template = 0; |
668 | d->output_format = INSN_OUTPUT_FORMAT_MULTI; | |
9db4e0ec | 669 | |
4bbf910e | 670 | printf ("\nstatic const char * const output_%d[] = {\n", d->code_number); |
9db4e0ec RK |
671 | |
672 | for (i = 0, cp = &template[1]; *cp; ) | |
673 | { | |
674 | while (*cp == '\n' || *cp == ' ' || *cp== '\t') | |
675 | cp++; | |
676 | ||
4bbf910e | 677 | printf (" \""); |
9db4e0ec | 678 | while (*cp != '\n' && *cp != '\0') |
2f013c71 RK |
679 | { |
680 | putchar (*cp); | |
681 | cp++; | |
682 | } | |
9db4e0ec RK |
683 | |
684 | printf ("\",\n"); | |
685 | i++; | |
686 | } | |
687 | ||
4bbf910e | 688 | printf ("};\n"); |
9db4e0ec RK |
689 | } |
690 | else | |
691 | { | |
4bbf910e RH |
692 | d->template = template; |
693 | d->output_format = INSN_OUTPUT_FORMAT_SINGLE; | |
9db4e0ec | 694 | } |
9db4e0ec RK |
695 | } |
696 | \f | |
697 | /* Check insn D for consistency in number of constraint alternatives. */ | |
698 | ||
699 | static void | |
700 | validate_insn_alternatives (d) | |
701 | struct data *d; | |
702 | { | |
703 | register int n = 0, start; | |
a995e389 RH |
704 | |
705 | /* Make sure all the operands have the same number of alternatives | |
706 | in their constraints. Let N be that number. */ | |
9db4e0ec | 707 | for (start = 0; start < d->n_operands; start++) |
a995e389 | 708 | if (d->operand[start].n_alternatives > 0) |
9db4e0ec RK |
709 | { |
710 | if (n == 0) | |
a995e389 RH |
711 | n = d->operand[start].n_alternatives; |
712 | else if (n != d->operand[start].n_alternatives) | |
8aeba909 | 713 | error ("wrong number of alternatives in operand %d of insn %s", |
a995e389 | 714 | start, get_insn_name (d->index_number)); |
9db4e0ec | 715 | } |
a995e389 | 716 | |
9db4e0ec RK |
717 | /* Record the insn's overall number of alternatives. */ |
718 | d->n_alternatives = n; | |
719 | } | |
720 | \f | |
a995e389 RH |
721 | /* Look at a define_insn just read. Assign its code number. Record |
722 | on idata the template and the number of arguments. If the insn has | |
723 | a hairy output action, output a function for now. */ | |
9db4e0ec RK |
724 | |
725 | static void | |
726 | gen_insn (insn) | |
727 | rtx insn; | |
728 | { | |
729 | register struct data *d = (struct data *) xmalloc (sizeof (struct data)); | |
730 | register int i; | |
731 | ||
732 | d->code_number = next_code_number++; | |
733 | d->index_number = next_index_number; | |
734 | if (XSTR (insn, 0)[0]) | |
735 | d->name = XSTR (insn, 0); | |
736 | else | |
737 | d->name = 0; | |
738 | ||
739 | /* Build up the list in the same order as the insns are seen | |
740 | in the machine description. */ | |
741 | d->next = 0; | |
a995e389 RH |
742 | *idata_end = d; |
743 | idata_end = &d->next; | |
9db4e0ec RK |
744 | |
745 | max_opno = -1; | |
746 | num_dups = 0; | |
a995e389 | 747 | memset (d->operand, 0, sizeof (d->operand)); |
9db4e0ec RK |
748 | |
749 | for (i = 0; i < XVECLEN (insn, 1); i++) | |
a995e389 | 750 | scan_operands (d, XVECEXP (insn, 1, i), 0, 0); |
9db4e0ec RK |
751 | |
752 | d->n_operands = max_opno + 1; | |
753 | d->n_dups = num_dups; | |
754 | ||
9db4e0ec | 755 | validate_insn_alternatives (d); |
a995e389 | 756 | place_operands (d); |
9db4e0ec RK |
757 | process_template (d, XSTR (insn, 3)); |
758 | } | |
759 | \f | |
760 | /* Look at a define_peephole just read. Assign its code number. | |
a995e389 | 761 | Record on idata the template and the number of arguments. |
9db4e0ec RK |
762 | If the insn has a hairy output action, output it now. */ |
763 | ||
764 | static void | |
765 | gen_peephole (peep) | |
766 | rtx peep; | |
767 | { | |
768 | register struct data *d = (struct data *) xmalloc (sizeof (struct data)); | |
769 | register int i; | |
770 | ||
771 | d->code_number = next_code_number++; | |
772 | d->index_number = next_index_number; | |
773 | d->name = 0; | |
774 | ||
775 | /* Build up the list in the same order as the insns are seen | |
776 | in the machine description. */ | |
777 | d->next = 0; | |
a995e389 RH |
778 | *idata_end = d; |
779 | idata_end = &d->next; | |
9db4e0ec RK |
780 | |
781 | max_opno = -1; | |
a995e389 RH |
782 | num_dups = 0; |
783 | memset (d->operand, 0, sizeof (d->operand)); | |
784 | ||
785 | /* Get the number of operands by scanning all the patterns of the | |
786 | peephole optimizer. But ignore all the rest of the information | |
787 | thus obtained. */ | |
9db4e0ec | 788 | for (i = 0; i < XVECLEN (peep, 0); i++) |
a995e389 | 789 | scan_operands (d, XVECEXP (peep, 0, i), 0, 0); |
9db4e0ec RK |
790 | |
791 | d->n_operands = max_opno + 1; | |
792 | d->n_dups = 0; | |
793 | ||
9db4e0ec | 794 | validate_insn_alternatives (d); |
a995e389 | 795 | place_operands (d); |
9db4e0ec RK |
796 | process_template (d, XSTR (peep, 2)); |
797 | } | |
798 | \f | |
799 | /* Process a define_expand just read. Assign its code number, | |
800 | only for the purposes of `insn_gen_function'. */ | |
801 | ||
802 | static void | |
803 | gen_expand (insn) | |
804 | rtx insn; | |
805 | { | |
806 | register struct data *d = (struct data *) xmalloc (sizeof (struct data)); | |
807 | register int i; | |
808 | ||
809 | d->code_number = next_code_number++; | |
810 | d->index_number = next_index_number; | |
811 | if (XSTR (insn, 0)[0]) | |
812 | d->name = XSTR (insn, 0); | |
813 | else | |
814 | d->name = 0; | |
815 | ||
816 | /* Build up the list in the same order as the insns are seen | |
817 | in the machine description. */ | |
818 | d->next = 0; | |
a995e389 RH |
819 | *idata_end = d; |
820 | idata_end = &d->next; | |
9db4e0ec RK |
821 | |
822 | max_opno = -1; | |
823 | num_dups = 0; | |
a995e389 | 824 | memset (d->operand, 0, sizeof (d->operand)); |
9db4e0ec RK |
825 | |
826 | /* Scan the operands to get the specified predicates and modes, | |
827 | since expand_binop needs to know them. */ | |
828 | ||
9db4e0ec RK |
829 | if (XVEC (insn, 1)) |
830 | for (i = 0; i < XVECLEN (insn, 1); i++) | |
a995e389 | 831 | scan_operands (d, XVECEXP (insn, 1, i), 0, 0); |
9db4e0ec RK |
832 | |
833 | d->n_operands = max_opno + 1; | |
834 | d->n_dups = num_dups; | |
9db4e0ec | 835 | d->template = 0; |
4bbf910e | 836 | d->output_format = INSN_OUTPUT_FORMAT_NONE; |
a995e389 | 837 | |
9db4e0ec | 838 | validate_insn_alternatives (d); |
a995e389 | 839 | place_operands (d); |
9db4e0ec RK |
840 | } |
841 | \f | |
842 | /* Process a define_split just read. Assign its code number, | |
843 | only for reasons of consistency and to simplify genrecog. */ | |
844 | ||
9db4e0ec RK |
845 | static void |
846 | gen_split (split) | |
847 | rtx split; | |
848 | { | |
849 | register struct data *d = (struct data *) xmalloc (sizeof (struct data)); | |
850 | register int i; | |
851 | ||
852 | d->code_number = next_code_number++; | |
853 | d->index_number = next_index_number; | |
854 | d->name = 0; | |
855 | ||
856 | /* Build up the list in the same order as the insns are seen | |
857 | in the machine description. */ | |
858 | d->next = 0; | |
a995e389 RH |
859 | *idata_end = d; |
860 | idata_end = &d->next; | |
9db4e0ec RK |
861 | |
862 | max_opno = -1; | |
863 | num_dups = 0; | |
a995e389 | 864 | memset (d->operand, 0, sizeof (d->operand)); |
9db4e0ec | 865 | |
a995e389 RH |
866 | /* Get the number of operands by scanning all the patterns of the |
867 | split patterns. But ignore all the rest of the information thus | |
868 | obtained. */ | |
9db4e0ec | 869 | for (i = 0; i < XVECLEN (split, 0); i++) |
a995e389 | 870 | scan_operands (d, XVECEXP (split, 0, i), 0, 0); |
9db4e0ec RK |
871 | |
872 | d->n_operands = max_opno + 1; | |
9db4e0ec | 873 | d->n_dups = 0; |
42495ca0 | 874 | d->n_alternatives = 0; |
9db4e0ec | 875 | d->template = 0; |
4bbf910e | 876 | d->output_format = INSN_OUTPUT_FORMAT_NONE; |
a995e389 RH |
877 | |
878 | place_operands (d); | |
9db4e0ec RK |
879 | } |
880 | \f | |
2778b98d | 881 | PTR |
9db4e0ec | 882 | xmalloc (size) |
2778b98d | 883 | size_t size; |
9db4e0ec | 884 | { |
2778b98d | 885 | register PTR val = (PTR) malloc (size); |
9db4e0ec RK |
886 | |
887 | if (val == 0) | |
888 | fatal ("virtual memory exhausted"); | |
889 | return val; | |
890 | } | |
891 | ||
2778b98d | 892 | PTR |
470b68c0 RH |
893 | xrealloc (old, size) |
894 | PTR old; | |
2778b98d | 895 | size_t size; |
9db4e0ec | 896 | { |
470b68c0 | 897 | register PTR ptr; |
09d83d25 | 898 | if (old) |
470b68c0 RH |
899 | ptr = (PTR) realloc (old, size); |
900 | else | |
901 | ptr = (PTR) malloc (size); | |
902 | if (!ptr) | |
9db4e0ec | 903 | fatal ("virtual memory exhausted"); |
470b68c0 | 904 | return ptr; |
9db4e0ec RK |
905 | } |
906 | ||
a94ae8f5 | 907 | extern int main PARAMS ((int, char **)); |
c1b59dce | 908 | |
9db4e0ec RK |
909 | int |
910 | main (argc, argv) | |
911 | int argc; | |
912 | char **argv; | |
913 | { | |
914 | rtx desc; | |
915 | FILE *infile; | |
9db4e0ec RK |
916 | register int c; |
917 | ||
f8b6598e | 918 | progname = "genoutput"; |
9db4e0ec RK |
919 | obstack_init (rtl_obstack); |
920 | ||
921 | if (argc <= 1) | |
922 | fatal ("No input file name."); | |
923 | ||
924 | infile = fopen (argv[1], "r"); | |
925 | if (infile == 0) | |
926 | { | |
927 | perror (argv[1]); | |
c1b59dce | 928 | return (FATAL_EXIT_CODE); |
9db4e0ec | 929 | } |
bcdaba58 | 930 | read_rtx_filename = argv[1]; |
9db4e0ec | 931 | |
9db4e0ec RK |
932 | output_prologue (); |
933 | next_code_number = 0; | |
934 | next_index_number = 0; | |
9db4e0ec RK |
935 | |
936 | /* Read the machine description. */ | |
937 | ||
938 | while (1) | |
939 | { | |
940 | c = read_skip_spaces (infile); | |
941 | if (c == EOF) | |
942 | break; | |
943 | ungetc (c, infile); | |
944 | ||
945 | desc = read_rtx (infile); | |
946 | if (GET_CODE (desc) == DEFINE_INSN) | |
947 | gen_insn (desc); | |
948 | if (GET_CODE (desc) == DEFINE_PEEPHOLE) | |
949 | gen_peephole (desc); | |
950 | if (GET_CODE (desc) == DEFINE_EXPAND) | |
951 | gen_expand (desc); | |
ede7cd44 RH |
952 | if (GET_CODE (desc) == DEFINE_SPLIT |
953 | || GET_CODE (desc) == DEFINE_PEEPHOLE2) | |
9db4e0ec RK |
954 | gen_split (desc); |
955 | next_index_number++; | |
956 | } | |
957 | ||
a995e389 RH |
958 | printf("\n\n"); |
959 | output_predicate_decls (); | |
960 | output_operand_data (); | |
961 | output_insn_data (); | |
962 | output_get_insn_name (); | |
9db4e0ec RK |
963 | |
964 | fflush (stdout); | |
c1b59dce | 965 | return (ferror (stdout) != 0 || have_error |
6a270722 | 966 | ? FATAL_EXIT_CODE : SUCCESS_EXIT_CODE); |
9db4e0ec RK |
967 | } |
968 | ||
969 | static int | |
970 | n_occurrences (c, s) | |
d149d5f5 | 971 | int c; |
9db4e0ec RK |
972 | char *s; |
973 | { | |
974 | int n = 0; | |
975 | while (*s) | |
976 | n += (*s++ == c); | |
977 | return n; | |
978 | } | |
88a56c2e HPN |
979 | |
980 | /* Remove whitespace in `s' by moving up characters until the end. */ | |
981 | static void | |
982 | strip_whitespace (s) | |
983 | char *s; | |
984 | { | |
985 | char *p = s; | |
986 | int ch; | |
987 | ||
988 | while ((ch = *s++) != '\0') | |
989 | if (! ISSPACE (ch)) | |
990 | *p++ = ch; | |
991 | ||
992 | *p = '\0'; | |
993 | } |