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