]>
Commit | Line | Data |
---|---|---|
9db4e0ec | 1 | /* Generate code from to output assembler insns as recognized from rtl. |
aeee4812 | 2 | Copyright (C) 1987-2023 Free Software Foundation, Inc. |
9db4e0ec | 3 | |
1322177d | 4 | This file is part of GCC. |
9db4e0ec | 5 | |
1322177d LB |
6 | GCC is free software; you can redistribute it and/or modify it under |
7 | the terms of the GNU General Public License as published by the Free | |
9dcd6f09 | 8 | Software Foundation; either version 3, or (at your option) any later |
1322177d | 9 | version. |
9db4e0ec | 10 | |
1322177d LB |
11 | GCC is distributed in the hope that it will be useful, but WITHOUT ANY |
12 | WARRANTY; without even the implied warranty of MERCHANTABILITY or | |
13 | FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License | |
14 | for more details. | |
9db4e0ec RK |
15 | |
16 | You should have received a copy of the GNU General Public License | |
9dcd6f09 NC |
17 | along with GCC; see the file COPYING3. If not see |
18 | <http://www.gnu.org/licenses/>. */ | |
9db4e0ec RK |
19 | |
20 | ||
21 | /* This program reads the machine description for the compiler target machine | |
22 | and produces a file containing these things: | |
23 | ||
f12c802a | 24 | 1. An array of `struct insn_data_d', which is indexed by insn code number, |
a995e389 | 25 | which contains: |
9db4e0ec | 26 | |
a995e389 RH |
27 | a. `name' is the name for that pattern. Nameless patterns are |
28 | given a name. | |
29 | ||
4bbf910e RH |
30 | b. `output' hold either the output template, an array of output |
31 | templates, or an output function. | |
32 | ||
33 | c. `genfun' is the function to generate a body for that pattern, | |
a995e389 RH |
34 | given operands as arguments. |
35 | ||
4bbf910e | 36 | d. `n_operands' is the number of distinct operands in the pattern |
a995e389 | 37 | for that insn, |
9db4e0ec | 38 | |
4bbf910e | 39 | e. `n_dups' is the number of match_dup's that appear in the insn's |
a995e389 RH |
40 | pattern. This says how many elements of `recog_data.dup_loc' are |
41 | significant after an insn has been recognized. | |
9db4e0ec | 42 | |
4bbf910e | 43 | f. `n_alternatives' is the number of alternatives in the constraints |
a995e389 | 44 | of each pattern. |
9db4e0ec | 45 | |
4bbf910e RH |
46 | g. `output_format' tells what type of thing `output' is. |
47 | ||
a995e389 | 48 | h. `operand' is the base of an array of operand data for the insn. |
9db4e0ec | 49 | |
a995e389 | 50 | 2. An array of `struct insn_operand data', used by `operand' above. |
9db4e0ec | 51 | |
a995e389 RH |
52 | a. `predicate', an int-valued function, is the match_operand predicate |
53 | for this operand. | |
9db4e0ec | 54 | |
f38840db | 55 | b. `constraint' is the constraint for this operand. |
9db4e0ec | 56 | |
a995e389 | 57 | c. `address_p' indicates that the operand appears within ADDRESS |
f38840db | 58 | rtx's. |
9db4e0ec | 59 | |
a995e389 | 60 | d. `mode' is the machine mode that that operand is supposed to have. |
9db4e0ec | 61 | |
a995e389 | 62 | e. `strict_low', is nonzero for operands contained in a STRICT_LOW_PART. |
9db4e0ec | 63 | |
dfac187e BS |
64 | f. `eliminable', is nonzero for operands that are matched normally by |
65 | MATCH_OPERAND; it is zero for operands that should not be changed during | |
66 | register elimination such as MATCH_OPERATORs. | |
67 | ||
4fd3a105 RS |
68 | g. `allows_mem', is true for operands that accept MEM rtxes. |
69 | ||
a995e389 RH |
70 | The code number of an insn is simply its position in the machine |
71 | description; code numbers are assigned sequentially to entries in | |
72 | the description, starting with code number 0. | |
9db4e0ec | 73 | |
a995e389 | 74 | Thus, the following entry in the machine description |
9db4e0ec RK |
75 | |
76 | (define_insn "clrdf" | |
77 | [(set (match_operand:DF 0 "general_operand" "") | |
78 | (const_int 0))] | |
79 | "" | |
80 | "clrd %0") | |
81 | ||
a995e389 RH |
82 | assuming it is the 25th entry present, would cause |
83 | insn_data[24].template to be "clrd %0", and | |
84 | insn_data[24].n_operands to be 1. */ | |
9db4e0ec | 85 | \f |
4977bab6 | 86 | #include "bconfig.h" |
0b93b64e | 87 | #include "system.h" |
4977bab6 ZW |
88 | #include "coretypes.h" |
89 | #include "tm.h" | |
9db4e0ec | 90 | #include "rtl.h" |
d80eb1e1 | 91 | #include "errors.h" |
10692477 | 92 | #include "read-md.h" |
c88c0d42 | 93 | #include "gensupport.h" |
9db4e0ec | 94 | |
a995e389 RH |
95 | /* No instruction can have more operands than this. Sorry for this |
96 | arbitrary limit, but what machine will have an instruction with | |
97 | this many operands? */ | |
9db4e0ec RK |
98 | |
99 | #define MAX_MAX_OPERANDS 40 | |
100 | ||
8677664e RS |
101 | static char general_mem[] = { TARGET_MEM_CONSTRAINT, 0 }; |
102 | ||
3d7aafde AJ |
103 | static int n_occurrences (int, const char *); |
104 | static const char *strip_whitespace (const char *); | |
9db4e0ec | 105 | |
a995e389 RH |
106 | /* This counts all operands used in the md file. The first is null. */ |
107 | ||
108 | static int next_operand_number = 1; | |
109 | ||
110 | /* Record in this chain all information about the operands we will output. */ | |
111 | ||
112 | struct operand_data | |
113 | { | |
114 | struct operand_data *next; | |
115 | int index; | |
c1b59dce KG |
116 | const char *predicate; |
117 | const char *constraint; | |
ef4bddc2 | 118 | machine_mode mode; |
a995e389 RH |
119 | unsigned char n_alternatives; |
120 | char address_p; | |
121 | char strict_low; | |
dfac187e | 122 | char eliminable; |
a995e389 RH |
123 | char seen; |
124 | }; | |
125 | ||
126 | /* Begin with a null operand at index 0. */ | |
127 | ||
128 | static struct operand_data null_operand = | |
129 | { | |
0d4a1197 | 130 | 0, 0, "", "", E_VOIDmode, 0, 0, 0, 0, 0 |
a995e389 RH |
131 | }; |
132 | ||
133 | static struct operand_data *odata = &null_operand; | |
134 | static struct operand_data **odata_end = &null_operand.next; | |
135 | ||
4bbf910e RH |
136 | /* Must match the constants in recog.h. */ |
137 | ||
138 | #define INSN_OUTPUT_FORMAT_NONE 0 /* abort */ | |
139 | #define INSN_OUTPUT_FORMAT_SINGLE 1 /* const char * */ | |
140 | #define INSN_OUTPUT_FORMAT_MULTI 2 /* const char * const * */ | |
141 | #define INSN_OUTPUT_FORMAT_FUNCTION 3 /* const char * (*)(...) */ | |
142 | ||
9db4e0ec RK |
143 | /* Record in this chain all information that we will output, |
144 | associated with the code number of the insn. */ | |
145 | ||
6c1dae73 | 146 | class data |
9db4e0ec | 147 | { |
6c1dae73 | 148 | public: |
99b1c316 | 149 | class data *next; |
c1b59dce | 150 | const char *name; |
8ad97cfc | 151 | const char *template_code; |
ca018d3c | 152 | file_location loc; |
a995e389 | 153 | int code_number; |
b29387ee | 154 | int n_generator_args; /* Number of arguments passed to generator */ |
9db4e0ec RK |
155 | int n_operands; /* Number of operands this insn recognizes */ |
156 | int n_dups; /* Number times match_dup appears in pattern */ | |
157 | int n_alternatives; /* Number of alternatives in each constraint */ | |
a995e389 | 158 | int operand_number; /* Operand index in the big array. */ |
4bbf910e | 159 | int output_format; /* INSN_OUTPUT_FORMAT_*. */ |
957ae904 | 160 | bool compact_syntax_p; |
a995e389 | 161 | struct operand_data operand[MAX_MAX_OPERANDS]; |
9db4e0ec RK |
162 | }; |
163 | ||
a995e389 | 164 | /* This variable points to the first link in the insn chain. */ |
99b1c316 | 165 | static class data *idata; |
e714561a SB |
166 | |
167 | /* This variable points to the end of the insn chain. This is where | |
168 | everything relevant from the machien description is appended to. */ | |
99b1c316 | 169 | static class data **idata_end; |
9db4e0ec | 170 | |
9db4e0ec | 171 | \f |
3d7aafde | 172 | static void output_prologue (void); |
3d7aafde AJ |
173 | static void output_operand_data (void); |
174 | static void output_insn_data (void); | |
175 | static void output_get_insn_name (void); | |
99b1c316 | 176 | static void scan_operands (class data *, rtx, int, int); |
3d7aafde AJ |
177 | static int compare_operands (struct operand_data *, |
178 | struct operand_data *); | |
99b1c316 MS |
179 | static void place_operands (class data *); |
180 | static void process_template (class data *, const char *); | |
181 | static void validate_insn_alternatives (class data *); | |
182 | static void validate_insn_operands (class data *); | |
f38840db | 183 | |
6c1dae73 | 184 | class constraint_data |
f38840db | 185 | { |
6c1dae73 | 186 | public: |
99b1c316 | 187 | class constraint_data *next_this_letter; |
ca018d3c | 188 | file_location loc; |
f38840db | 189 | unsigned int namelen; |
ca018d3c | 190 | char name[1]; |
f38840db ZW |
191 | }; |
192 | ||
8677664e RS |
193 | /* All machine-independent constraint characters (except digits) that |
194 | are handled outside the define*_constraint mechanism. */ | |
d1457701 | 195 | static const char indep_constraints[] = ",=+%*?!^$#&g"; |
f38840db | 196 | |
99b1c316 | 197 | static class constraint_data * |
f38840db ZW |
198 | constraints_by_letter_table[1 << CHAR_BIT]; |
199 | ||
ca018d3c | 200 | static int mdep_constraint_len (const char *, file_location, int); |
5d2d3e43 | 201 | static void note_constraint (md_rtx_info *); |
56c0e996 | 202 | \f |
9db4e0ec | 203 | static void |
3d7aafde | 204 | output_prologue (void) |
9db4e0ec | 205 | { |
9db4e0ec | 206 | printf ("/* Generated automatically by the program `genoutput'\n\ |
d96a2fcd | 207 | from the machine description file `md'. */\n\n"); |
9db4e0ec | 208 | |
8fcc61f8 | 209 | printf ("#define IN_TARGET_CODE 1\n"); |
9db4e0ec | 210 | printf ("#include \"config.h\"\n"); |
729da3f5 | 211 | printf ("#include \"system.h\"\n"); |
4977bab6 | 212 | printf ("#include \"coretypes.h\"\n"); |
c7131fb2 | 213 | printf ("#include \"backend.h\"\n"); |
9fdcd34e | 214 | printf ("#include \"predict.h\"\n"); |
c7131fb2 AM |
215 | printf ("#include \"tree.h\"\n"); |
216 | printf ("#include \"rtl.h\"\n"); | |
ccd043a9 | 217 | printf ("#include \"flags.h\"\n"); |
40e23961 | 218 | printf ("#include \"alias.h\"\n"); |
d8a2d370 DN |
219 | printf ("#include \"varasm.h\"\n"); |
220 | printf ("#include \"stor-layout.h\"\n"); | |
221 | printf ("#include \"calls.h\"\n"); | |
36566b39 PK |
222 | printf ("#include \"insn-config.h\"\n"); |
223 | printf ("#include \"expmed.h\"\n"); | |
224 | printf ("#include \"dojump.h\"\n"); | |
225 | printf ("#include \"explow.h\"\n"); | |
4d0cdd0c | 226 | printf ("#include \"memmodel.h\"\n"); |
36566b39 PK |
227 | printf ("#include \"emit-rtl.h\"\n"); |
228 | printf ("#include \"stmt.h\"\n"); | |
f3a8030a | 229 | printf ("#include \"expr.h\"\n"); |
e78d8e51 | 230 | printf ("#include \"insn-codes.h\"\n"); |
6baf1cc8 | 231 | printf ("#include \"tm_p.h\"\n"); |
9db4e0ec | 232 | printf ("#include \"regs.h\"\n"); |
9db4e0ec | 233 | printf ("#include \"conditions.h\"\n"); |
9db4e0ec | 234 | printf ("#include \"insn-attr.h\"\n\n"); |
9db4e0ec | 235 | printf ("#include \"recog.h\"\n\n"); |
79a3f089 | 236 | printf ("#include \"diagnostic-core.h\"\n"); |
9db4e0ec | 237 | printf ("#include \"output.h\"\n"); |
4977bab6 | 238 | printf ("#include \"target.h\"\n"); |
279bb624 | 239 | printf ("#include \"tm-constrs.h\"\n"); |
9db4e0ec RK |
240 | } |
241 | ||
a995e389 | 242 | static void |
3d7aafde | 243 | output_operand_data (void) |
a995e389 | 244 | { |
b3694847 | 245 | struct operand_data *d; |
a995e389 RH |
246 | |
247 | printf ("\nstatic const struct insn_operand_data operand_data[] = \n{\n"); | |
248 | ||
249 | for (d = odata; d; d = d->next) | |
9db4e0ec | 250 | { |
4fd3a105 RS |
251 | struct pred_data *pred; |
252 | ||
a995e389 RH |
253 | printf (" {\n"); |
254 | ||
255 | printf (" %s,\n", | |
256 | d->predicate && d->predicate[0] ? d->predicate : "0"); | |
257 | ||
19af6455 | 258 | printf (" \"%s\",\n", d->constraint ? d->constraint : ""); |
9db4e0ec | 259 | |
0d4a1197 | 260 | printf (" E_%smode,\n", GET_MODE_NAME (d->mode)); |
a995e389 | 261 | |
dfac187e BS |
262 | printf (" %d,\n", d->strict_low); |
263 | ||
6ddfdb0f BS |
264 | printf (" %d,\n", d->constraint == NULL ? 1 : 0); |
265 | ||
4fd3a105 RS |
266 | printf (" %d,\n", d->eliminable); |
267 | ||
268 | pred = NULL; | |
269 | if (d->predicate) | |
270 | pred = lookup_predicate (d->predicate); | |
271 | printf (" %d\n", pred && pred->codes[MEM]); | |
a995e389 | 272 | |
c3284718 | 273 | printf (" },\n"); |
a995e389 | 274 | } |
c3284718 | 275 | printf ("};\n\n\n"); |
a995e389 RH |
276 | } |
277 | ||
278 | static void | |
3d7aafde | 279 | output_insn_data (void) |
a995e389 | 280 | { |
99b1c316 | 281 | class data *d; |
a995e389 RH |
282 | int name_offset = 0; |
283 | int next_name_offset; | |
284 | const char * last_name = 0; | |
285 | const char * next_name = 0; | |
99b1c316 | 286 | class data *n; |
a995e389 RH |
287 | |
288 | for (n = idata, next_name_offset = 1; n; n = n->next, next_name_offset++) | |
289 | if (n->name) | |
9db4e0ec | 290 | { |
a995e389 RH |
291 | next_name = n->name; |
292 | break; | |
9db4e0ec | 293 | } |
9db4e0ec | 294 | |
3897f229 | 295 | printf ("#if GCC_VERSION >= 2007\n__extension__\n#endif\n"); |
f12c802a | 296 | printf ("\nconst struct insn_data_d insn_data[] = \n{\n"); |
9db4e0ec | 297 | |
a995e389 | 298 | for (d = idata; d; d = d->next) |
9db4e0ec | 299 | { |
ca018d3c | 300 | printf (" /* %s:%d */\n", d->loc.filename, d->loc.lineno); |
a995e389 RH |
301 | printf (" {\n"); |
302 | ||
303 | if (d->name) | |
9db4e0ec | 304 | { |
a995e389 RH |
305 | printf (" \"%s\",\n", d->name); |
306 | name_offset = 0; | |
307 | last_name = d->name; | |
308 | next_name = 0; | |
309 | for (n = d->next, next_name_offset = 1; n; | |
310 | n = n->next, next_name_offset++) | |
9db4e0ec | 311 | { |
a995e389 RH |
312 | if (n->name) |
313 | { | |
314 | next_name = n->name; | |
315 | break; | |
316 | } | |
9db4e0ec | 317 | } |
9db4e0ec | 318 | } |
a995e389 | 319 | else |
9db4e0ec | 320 | { |
a995e389 RH |
321 | name_offset++; |
322 | if (next_name && (last_name == 0 | |
323 | || name_offset > next_name_offset / 2)) | |
324 | printf (" \"%s-%d\",\n", next_name, | |
325 | next_name_offset - name_offset); | |
326 | else | |
327 | printf (" \"%s+%d\",\n", last_name, name_offset); | |
9db4e0ec | 328 | } |
9db4e0ec | 329 | |
4bbf910e RH |
330 | switch (d->output_format) |
331 | { | |
332 | case INSN_OUTPUT_FORMAT_NONE: | |
9ca1483b | 333 | printf ("#if HAVE_DESIGNATED_UNION_INITIALIZERS\n"); |
3897f229 JM |
334 | printf (" { 0 },\n"); |
335 | printf ("#else\n"); | |
336 | printf (" { 0, 0, 0 },\n"); | |
337 | printf ("#endif\n"); | |
4bbf910e RH |
338 | break; |
339 | case INSN_OUTPUT_FORMAT_SINGLE: | |
212d447c | 340 | { |
8ad97cfc | 341 | const char *p = d->template_code; |
212d447c | 342 | char prev = 0; |
3d7aafde | 343 | |
9ca1483b | 344 | printf ("#if HAVE_DESIGNATED_UNION_INITIALIZERS\n"); |
3897f229 JM |
345 | printf (" { .single =\n"); |
346 | printf ("#else\n"); | |
347 | printf (" {\n"); | |
348 | printf ("#endif\n"); | |
212d447c DC |
349 | printf (" \""); |
350 | while (*p) | |
351 | { | |
6b8b9d7b CM |
352 | if (IS_VSPACE (*p) && prev != '\\') |
353 | { | |
354 | /* Preserve two consecutive \n's or \r's, but treat \r\n | |
355 | as a single newline. */ | |
356 | if (*p == '\n' && prev != '\r') | |
357 | printf ("\\n\\\n"); | |
358 | } | |
212d447c DC |
359 | else |
360 | putchar (*p); | |
361 | prev = *p; | |
362 | ++p; | |
363 | } | |
364 | printf ("\",\n"); | |
9ca1483b | 365 | printf ("#if HAVE_DESIGNATED_UNION_INITIALIZERS\n"); |
3897f229 JM |
366 | printf (" },\n"); |
367 | printf ("#else\n"); | |
368 | printf (" 0, 0 },\n"); | |
369 | printf ("#endif\n"); | |
212d447c | 370 | } |
4bbf910e RH |
371 | break; |
372 | case INSN_OUTPUT_FORMAT_MULTI: | |
9ca1483b | 373 | printf ("#if HAVE_DESIGNATED_UNION_INITIALIZERS\n"); |
3897f229 JM |
374 | printf (" { .multi = output_%d },\n", d->code_number); |
375 | printf ("#else\n"); | |
376 | printf (" { 0, output_%d, 0 },\n", d->code_number); | |
377 | printf ("#endif\n"); | |
378 | break; | |
4bbf910e | 379 | case INSN_OUTPUT_FORMAT_FUNCTION: |
9ca1483b | 380 | printf ("#if HAVE_DESIGNATED_UNION_INITIALIZERS\n"); |
3897f229 JM |
381 | printf (" { .function = output_%d },\n", d->code_number); |
382 | printf ("#else\n"); | |
383 | printf (" { 0, 0, output_%d },\n", d->code_number); | |
384 | printf ("#endif\n"); | |
4bbf910e RH |
385 | break; |
386 | default: | |
b2d59f6f | 387 | gcc_unreachable (); |
4bbf910e | 388 | } |
a995e389 RH |
389 | |
390 | if (d->name && d->name[0] != '*') | |
eb923e54 | 391 | printf (" { (insn_gen_fn::stored_funcptr) gen_%s },\n", d->name); |
a995e389 | 392 | else |
eb923e54 | 393 | printf (" { 0 },\n"); |
a995e389 RH |
394 | |
395 | printf (" &operand_data[%d],\n", d->operand_number); | |
b29387ee | 396 | printf (" %d,\n", d->n_generator_args); |
a995e389 RH |
397 | printf (" %d,\n", d->n_operands); |
398 | printf (" %d,\n", d->n_dups); | |
4bbf910e RH |
399 | printf (" %d,\n", d->n_alternatives); |
400 | printf (" %d\n", d->output_format); | |
a995e389 | 401 | |
c3284718 | 402 | printf (" },\n"); |
9db4e0ec | 403 | } |
a995e389 RH |
404 | printf ("};\n\n\n"); |
405 | } | |
9db4e0ec | 406 | |
a995e389 | 407 | static void |
3d7aafde | 408 | output_get_insn_name (void) |
a995e389 RH |
409 | { |
410 | printf ("const char *\n"); | |
6906ba40 | 411 | printf ("get_insn_name (int code)\n"); |
a995e389 | 412 | printf ("{\n"); |
a0f0e963 SB |
413 | printf (" if (code == NOOP_MOVE_INSN_CODE)\n"); |
414 | printf (" return \"NOOP_MOVE\";\n"); | |
415 | printf (" else\n"); | |
416 | printf (" return insn_data[code].name;\n"); | |
a995e389 | 417 | printf ("}\n"); |
9db4e0ec | 418 | } |
a995e389 | 419 | |
9db4e0ec | 420 | \f |
b29387ee | 421 | /* Stores the operand data into `d->operand[i]'. |
9db4e0ec RK |
422 | |
423 | THIS_ADDRESS_P is nonzero if the containing rtx was an ADDRESS. | |
424 | THIS_STRICT_LOW is nonzero if the containing rtx was a STRICT_LOW_PART. */ | |
425 | ||
9db4e0ec | 426 | static void |
99b1c316 | 427 | scan_operands (class data *d, rtx part, int this_address_p, |
3d7aafde | 428 | int this_strict_low) |
9db4e0ec | 429 | { |
b3694847 SS |
430 | int i, j; |
431 | const char *format_ptr; | |
9db4e0ec RK |
432 | int opno; |
433 | ||
434 | if (part == 0) | |
435 | return; | |
436 | ||
437 | switch (GET_CODE (part)) | |
438 | { | |
439 | case MATCH_OPERAND: | |
440 | opno = XINT (part, 0); | |
b29387ee | 441 | if (opno >= MAX_MAX_OPERANDS) |
5a806d65 | 442 | { |
ca018d3c | 443 | error_at (d->loc, "maximum number of operands exceeded"); |
5a806d65 RK |
444 | return; |
445 | } | |
a995e389 | 446 | if (d->operand[opno].seen) |
ca018d3c | 447 | error_at (d->loc, "repeated operand number %d\n", opno); |
d96a2fcd | 448 | |
a995e389 RH |
449 | d->operand[opno].seen = 1; |
450 | d->operand[opno].mode = GET_MODE (part); | |
451 | d->operand[opno].strict_low = this_strict_low; | |
452 | d->operand[opno].predicate = XSTR (part, 1); | |
665f2503 RK |
453 | d->operand[opno].constraint = strip_whitespace (XSTR (part, 2)); |
454 | d->operand[opno].n_alternatives | |
455 | = n_occurrences (',', d->operand[opno].constraint) + 1; | |
a995e389 | 456 | d->operand[opno].address_p = this_address_p; |
dfac187e | 457 | d->operand[opno].eliminable = 1; |
9db4e0ec RK |
458 | return; |
459 | ||
460 | case MATCH_SCRATCH: | |
461 | opno = XINT (part, 0); | |
b29387ee | 462 | if (opno >= MAX_MAX_OPERANDS) |
5a806d65 | 463 | { |
ca018d3c | 464 | error_at (d->loc, "maximum number of operands exceeded"); |
5a806d65 RK |
465 | return; |
466 | } | |
a995e389 | 467 | if (d->operand[opno].seen) |
ca018d3c | 468 | error_at (d->loc, "repeated operand number %d\n", opno); |
d96a2fcd | 469 | |
a995e389 RH |
470 | d->operand[opno].seen = 1; |
471 | d->operand[opno].mode = GET_MODE (part); | |
472 | d->operand[opno].strict_low = 0; | |
473 | d->operand[opno].predicate = "scratch_operand"; | |
665f2503 RK |
474 | d->operand[opno].constraint = strip_whitespace (XSTR (part, 1)); |
475 | d->operand[opno].n_alternatives | |
476 | = n_occurrences (',', d->operand[opno].constraint) + 1; | |
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); | |
b29387ee | 484 | if (opno >= MAX_MAX_OPERANDS) |
5a806d65 | 485 | { |
ca018d3c | 486 | error_at (d->loc, "maximum number of operands exceeded"); |
5a806d65 RK |
487 | return; |
488 | } | |
a995e389 | 489 | if (d->operand[opno].seen) |
ca018d3c | 490 | error_at (d->loc, "repeated operand number %d\n", opno); |
d96a2fcd | 491 | |
a995e389 RH |
492 | d->operand[opno].seen = 1; |
493 | d->operand[opno].mode = GET_MODE (part); | |
494 | d->operand[opno].strict_low = 0; | |
495 | d->operand[opno].predicate = XSTR (part, 1); | |
496 | d->operand[opno].constraint = 0; | |
497 | d->operand[opno].address_p = 0; | |
dfac187e | 498 | d->operand[opno].eliminable = 0; |
9db4e0ec | 499 | for (i = 0; i < XVECLEN (part, 2); i++) |
a995e389 | 500 | scan_operands (d, XVECEXP (part, 2, i), 0, 0); |
9db4e0ec RK |
501 | return; |
502 | ||
9db4e0ec | 503 | case STRICT_LOW_PART: |
a995e389 | 504 | scan_operands (d, XEXP (part, 0), 0, 1); |
9db4e0ec | 505 | return; |
3d7aafde | 506 | |
ccd043a9 RL |
507 | default: |
508 | break; | |
9db4e0ec RK |
509 | } |
510 | ||
511 | format_ptr = GET_RTX_FORMAT (GET_CODE (part)); | |
512 | ||
513 | for (i = 0; i < GET_RTX_LENGTH (GET_CODE (part)); i++) | |
514 | switch (*format_ptr++) | |
515 | { | |
516 | case 'e': | |
ccd043a9 | 517 | case 'u': |
a995e389 | 518 | scan_operands (d, XEXP (part, i), 0, 0); |
9db4e0ec RK |
519 | break; |
520 | case 'E': | |
521 | if (XVEC (part, i) != NULL) | |
522 | for (j = 0; j < XVECLEN (part, i); j++) | |
a995e389 | 523 | scan_operands (d, XVECEXP (part, i, j), 0, 0); |
9db4e0ec RK |
524 | break; |
525 | } | |
526 | } | |
a995e389 RH |
527 | |
528 | /* Compare two operands for content equality. */ | |
529 | ||
530 | static int | |
3d7aafde | 531 | compare_operands (struct operand_data *d0, struct operand_data *d1) |
a995e389 | 532 | { |
c1b59dce | 533 | const char *p0, *p1; |
a995e389 RH |
534 | |
535 | p0 = d0->predicate; | |
536 | if (!p0) | |
537 | p0 = ""; | |
538 | p1 = d1->predicate; | |
539 | if (!p1) | |
540 | p1 = ""; | |
541 | if (strcmp (p0, p1) != 0) | |
542 | return 0; | |
543 | ||
19af6455 BS |
544 | p0 = d0->constraint; |
545 | if (!p0) | |
546 | p0 = ""; | |
547 | p1 = d1->constraint; | |
548 | if (!p1) | |
549 | p1 = ""; | |
550 | if (strcmp (p0, p1) != 0) | |
551 | return 0; | |
a995e389 RH |
552 | |
553 | if (d0->mode != d1->mode) | |
554 | return 0; | |
555 | ||
a995e389 RH |
556 | if (d0->strict_low != d1->strict_low) |
557 | return 0; | |
558 | ||
dfac187e BS |
559 | if (d0->eliminable != d1->eliminable) |
560 | return 0; | |
561 | ||
a995e389 RH |
562 | return 1; |
563 | } | |
564 | ||
565 | /* Scan the list of operands we've already committed to output and either | |
566 | find a subsequence that is the same, or allocate a new one at the end. */ | |
567 | ||
568 | static void | |
99b1c316 | 569 | place_operands (class data *d) |
a995e389 RH |
570 | { |
571 | struct operand_data *od, *od2; | |
572 | int i; | |
573 | ||
574 | if (d->n_operands == 0) | |
575 | { | |
576 | d->operand_number = 0; | |
577 | return; | |
578 | } | |
579 | ||
580 | /* Brute force substring search. */ | |
581 | for (od = odata, i = 0; od; od = od->next, i = 0) | |
582 | if (compare_operands (od, &d->operand[0])) | |
583 | { | |
584 | od2 = od->next; | |
585 | i = 1; | |
586 | while (1) | |
587 | { | |
588 | if (i == d->n_operands) | |
589 | goto full_match; | |
590 | if (od2 == NULL) | |
591 | goto partial_match; | |
592 | if (! compare_operands (od2, &d->operand[i])) | |
593 | break; | |
594 | ++i, od2 = od2->next; | |
595 | } | |
596 | } | |
597 | ||
598 | /* Either partial match at the end of the list, or no match. In either | |
599 | case, we tack on what operands are remaining to the end of the list. */ | |
600 | partial_match: | |
601 | d->operand_number = next_operand_number - i; | |
602 | for (; i < d->n_operands; ++i) | |
603 | { | |
604 | od2 = &d->operand[i]; | |
605 | *odata_end = od2; | |
606 | odata_end = &od2->next; | |
607 | od2->index = next_operand_number++; | |
608 | } | |
609 | *odata_end = NULL; | |
610 | return; | |
611 | ||
612 | full_match: | |
613 | d->operand_number = od->index; | |
614 | return; | |
615 | } | |
616 | ||
9db4e0ec RK |
617 | \f |
618 | /* Process an assembler template from a define_insn or a define_peephole. | |
619 | It is either the assembler code template, a list of assembler code | |
620 | templates, or C code to generate the assembler code template. */ | |
621 | ||
622 | static void | |
99b1c316 | 623 | process_template (class data *d, const char *template_code) |
9db4e0ec | 624 | { |
b3694847 SS |
625 | const char *cp; |
626 | int i; | |
9db4e0ec | 627 | |
4bbf910e | 628 | /* Templates starting with * contain straight code to be run. */ |
8ad97cfc | 629 | if (template_code[0] == '*') |
9db4e0ec | 630 | { |
8ad97cfc | 631 | d->template_code = 0; |
4bbf910e | 632 | d->output_format = INSN_OUTPUT_FORMAT_FUNCTION; |
9db4e0ec | 633 | |
4bbf910e | 634 | puts ("\nstatic const char *"); |
95770ca3 | 635 | printf ("output_%d (rtx *operands ATTRIBUTE_UNUSED, rtx_insn *insn ATTRIBUTE_UNUSED)\n", |
6906ba40 | 636 | d->code_number); |
4bbf910e | 637 | puts ("{"); |
b78027d1 | 638 | rtx_reader_ptr->print_md_ptr_loc (template_code); |
8ad97cfc | 639 | puts (template_code + 1); |
4bbf910e RH |
640 | puts ("}"); |
641 | } | |
9db4e0ec RK |
642 | |
643 | /* If the assembler code template starts with a @ it is a newline-separated | |
4bbf910e | 644 | list of assembler code templates, one for each alternative. */ |
8ad97cfc | 645 | else if (template_code[0] == '@') |
9db4e0ec | 646 | { |
94c765ab | 647 | int found_star = 0; |
9db4e0ec | 648 | |
94c765ab R |
649 | for (cp = &template_code[1]; *cp; ) |
650 | { | |
651 | while (ISSPACE (*cp)) | |
652 | cp++; | |
653 | if (*cp == '*') | |
654 | found_star = 1; | |
655 | while (!IS_VSPACE (*cp) && *cp != '\0') | |
656 | ++cp; | |
657 | } | |
658 | d->template_code = 0; | |
659 | if (found_star) | |
660 | { | |
661 | d->output_format = INSN_OUTPUT_FORMAT_FUNCTION; | |
662 | puts ("\nstatic const char *"); | |
663 | printf ("output_%d (rtx *operands ATTRIBUTE_UNUSED, " | |
95770ca3 | 664 | "rtx_insn *insn ATTRIBUTE_UNUSED)\n", d->code_number); |
94c765ab R |
665 | puts ("{"); |
666 | puts (" switch (which_alternative)\n {"); | |
667 | } | |
668 | else | |
669 | { | |
670 | d->output_format = INSN_OUTPUT_FORMAT_MULTI; | |
671 | printf ("\nstatic const char * const output_%d[] = {\n", | |
672 | d->code_number); | |
673 | } | |
9db4e0ec | 674 | |
8ad97cfc | 675 | for (i = 0, cp = &template_code[1]; *cp; ) |
9db4e0ec | 676 | { |
94c765ab | 677 | const char *ep, *sp, *bp; |
4112be4a | 678 | |
6b8b9d7b | 679 | while (ISSPACE (*cp)) |
9db4e0ec RK |
680 | cp++; |
681 | ||
94c765ab R |
682 | bp = cp; |
683 | if (found_star) | |
684 | { | |
685 | printf (" case %d:", i); | |
686 | if (*cp == '*') | |
687 | { | |
688 | printf ("\n "); | |
689 | cp++; | |
690 | } | |
691 | else | |
692 | printf (" return \""); | |
693 | } | |
694 | else | |
695 | printf (" \""); | |
4112be4a JJ |
696 | |
697 | for (ep = sp = cp; !IS_VSPACE (*ep) && *ep != '\0'; ++ep) | |
698 | if (!ISSPACE (*ep)) | |
699 | sp = ep + 1; | |
700 | ||
701 | if (sp != ep) | |
ca018d3c | 702 | message_at (d->loc, "trailing whitespace in output template"); |
4112be4a | 703 | |
957ae904 TC |
704 | /* Check for any unexpanded iterators. */ |
705 | if (bp[0] != '*' && d->compact_syntax_p) | |
2f013c71 | 706 | { |
957ae904 TC |
707 | const char *p = cp; |
708 | const char *last_bracket = nullptr; | |
709 | while (p < sp) | |
710 | { | |
711 | if (*p == '\\' && p + 1 < sp) | |
712 | { | |
713 | putchar (*p); | |
714 | putchar (*(p+1)); | |
715 | p += 2; | |
716 | continue; | |
717 | } | |
718 | ||
719 | if (*p == '>' && last_bracket && *last_bracket == '<') | |
720 | { | |
721 | int len = p - last_bracket; | |
722 | fatal_at (d->loc, "unresolved iterator '%.*s' in '%s'", | |
723 | len - 1, last_bracket + 1, cp); | |
724 | } | |
725 | else if (*p == '<' || *p == '>') | |
726 | last_bracket = p; | |
727 | ||
728 | putchar (*p); | |
729 | p += 1; | |
730 | } | |
731 | ||
732 | if (last_bracket) | |
733 | { | |
734 | char *nl = strchr (const_cast<char*> (cp), '\n'); | |
735 | if (nl) | |
736 | *nl = '\0'; | |
737 | fatal_at (d->loc, "unmatched angle brackets, likely an " | |
738 | "error in iterator syntax in %s", cp); | |
739 | } | |
740 | } | |
741 | else | |
742 | { | |
743 | while (cp < sp) | |
744 | putchar (*(cp++)); | |
2f013c71 | 745 | } |
9db4e0ec | 746 | |
957ae904 TC |
747 | cp = sp; |
748 | ||
94c765ab R |
749 | if (!found_star) |
750 | puts ("\","); | |
751 | else if (*bp != '*') | |
752 | puts ("\";"); | |
753 | else | |
754 | { | |
755 | /* The usual action will end with a return. | |
756 | If there is neither break or return at the end, this is | |
757 | assumed to be intentional; this allows to have multiple | |
758 | consecutive alternatives share some code. */ | |
759 | puts (""); | |
760 | } | |
9db4e0ec RK |
761 | i++; |
762 | } | |
c6d79bee | 763 | if (i == 1) |
ca018d3c RS |
764 | message_at (d->loc, "'@' is redundant for output template with" |
765 | " single alternative"); | |
c6d79bee | 766 | if (i != d->n_alternatives) |
ca018d3c RS |
767 | error_at (d->loc, "wrong number of alternatives in the output" |
768 | " template"); | |
9db4e0ec | 769 | |
94c765ab R |
770 | if (found_star) |
771 | puts (" default: gcc_unreachable ();\n }\n}"); | |
772 | else | |
773 | printf ("};\n"); | |
9db4e0ec RK |
774 | } |
775 | else | |
776 | { | |
8ad97cfc | 777 | d->template_code = template_code; |
4bbf910e | 778 | d->output_format = INSN_OUTPUT_FORMAT_SINGLE; |
9db4e0ec | 779 | } |
9db4e0ec RK |
780 | } |
781 | \f | |
782 | /* Check insn D for consistency in number of constraint alternatives. */ | |
783 | ||
784 | static void | |
99b1c316 | 785 | validate_insn_alternatives (class data *d) |
9db4e0ec | 786 | { |
b3694847 | 787 | int n = 0, start; |
a995e389 RH |
788 | |
789 | /* Make sure all the operands have the same number of alternatives | |
790 | in their constraints. Let N be that number. */ | |
9db4e0ec | 791 | for (start = 0; start < d->n_operands; start++) |
a995e389 | 792 | if (d->operand[start].n_alternatives > 0) |
9db4e0ec | 793 | { |
97488870 R |
794 | int len, i; |
795 | const char *p; | |
796 | char c; | |
797 | int which_alternative = 0; | |
798 | int alternative_count_unsure = 0; | |
5fd4bc96 | 799 | bool seen_write = false; |
bdd8e3dd | 800 | bool alt_mismatch = false; |
97488870 R |
801 | |
802 | for (p = d->operand[start].constraint; (c = *p); p += len) | |
803 | { | |
73f793e3 RS |
804 | if ((c == '%' || c == '=' || c == '+') |
805 | && p != d->operand[start].constraint) | |
ca018d3c RS |
806 | error_at (d->loc, "character '%c' can only be used at the" |
807 | " beginning of a constraint string", c); | |
5fd4bc96 JG |
808 | |
809 | if (c == '=' || c == '+') | |
810 | seen_write = true; | |
811 | ||
812 | /* Earlyclobber operands must always be marked write-only | |
813 | or read/write. */ | |
814 | if (!seen_write && c == '&') | |
ca018d3c RS |
815 | error_at (d->loc, "earlyclobber operands may not be" |
816 | " read-only in alternative %d", which_alternative); | |
5fd4bc96 | 817 | |
f38840db ZW |
818 | if (ISSPACE (c) || strchr (indep_constraints, c)) |
819 | len = 1; | |
820 | else if (ISDIGIT (c)) | |
821 | { | |
822 | const char *q = p; | |
823 | do | |
824 | q++; | |
825 | while (ISDIGIT (*q)); | |
826 | len = q - p; | |
827 | } | |
828 | else | |
ca018d3c | 829 | len = mdep_constraint_len (p, d->loc, start); |
97488870 R |
830 | |
831 | if (c == ',') | |
832 | { | |
833 | which_alternative++; | |
834 | continue; | |
835 | } | |
836 | ||
837 | for (i = 1; i < len; i++) | |
838 | if (p[i] == '\0') | |
839 | { | |
ca018d3c RS |
840 | error_at (d->loc, "NUL in alternative %d of operand %d", |
841 | which_alternative, start); | |
97488870 R |
842 | alternative_count_unsure = 1; |
843 | break; | |
844 | } | |
845 | else if (strchr (",#*", p[i])) | |
846 | { | |
ca018d3c RS |
847 | error_at (d->loc, "'%c' in alternative %d of operand %d", |
848 | p[i], which_alternative, start); | |
97488870 R |
849 | alternative_count_unsure = 1; |
850 | } | |
851 | } | |
bb933490 | 852 | if (!alternative_count_unsure) |
d96a2fcd | 853 | { |
bb933490 RS |
854 | if (n == 0) |
855 | n = d->operand[start].n_alternatives; | |
856 | else if (n != d->operand[start].n_alternatives) | |
bdd8e3dd JR |
857 | { |
858 | if (!alt_mismatch) | |
859 | { | |
860 | alt_mismatch = true; | |
861 | error_at (d->loc, | |
862 | "alternative number mismatch: " | |
863 | "operand %d has %d, operand %d has %d", | |
864 | 0, n, start, d->operand[start].n_alternatives); | |
865 | } | |
866 | else | |
867 | error_at (d->loc, "operand %d has %d alternatives", | |
868 | start, d->operand[start].n_alternatives); | |
869 | } | |
d96a2fcd | 870 | } |
9db4e0ec | 871 | } |
a995e389 | 872 | |
9db4e0ec RK |
873 | /* Record the insn's overall number of alternatives. */ |
874 | d->n_alternatives = n; | |
875 | } | |
c77e04ae RH |
876 | |
877 | /* Verify that there are no gaps in operand numbers for INSNs. */ | |
878 | ||
879 | static void | |
99b1c316 | 880 | validate_insn_operands (class data *d) |
c77e04ae RH |
881 | { |
882 | int i; | |
883 | ||
884 | for (i = 0; i < d->n_operands; ++i) | |
885 | if (d->operand[i].seen == 0) | |
ca018d3c | 886 | error_at (d->loc, "missing operand %d", i); |
c77e04ae | 887 | } |
7ddf71e3 PB |
888 | |
889 | static void | |
99b1c316 | 890 | validate_optab_operands (class data *d) |
7ddf71e3 PB |
891 | { |
892 | if (!d->name || d->name[0] == '\0' || d->name[0] == '*') | |
893 | return; | |
894 | ||
895 | /* Miscellaneous tests. */ | |
6ba3079d | 896 | if (startswith (d->name, "cstore") |
7ddf71e3 PB |
897 | && d->name[strlen (d->name) - 1] == '4' |
898 | && d->operand[0].mode == VOIDmode) | |
899 | { | |
ca018d3c | 900 | message_at (d->loc, "missing mode for operand 0 of cstore"); |
7ddf71e3 PB |
901 | have_error = 1; |
902 | } | |
903 | } | |
9db4e0ec | 904 | \f |
a995e389 RH |
905 | /* Look at a define_insn just read. Assign its code number. Record |
906 | on idata the template and the number of arguments. If the insn has | |
907 | a hairy output action, output a function for now. */ | |
9db4e0ec RK |
908 | |
909 | static void | |
5d2d3e43 | 910 | gen_insn (md_rtx_info *info) |
9db4e0ec | 911 | { |
b29387ee | 912 | struct pattern_stats stats; |
5d2d3e43 | 913 | rtx insn = info->def; |
ca018d3c | 914 | data *d = new data; |
b3694847 | 915 | int i; |
9db4e0ec | 916 | |
5d2d3e43 RS |
917 | d->code_number = info->index; |
918 | d->loc = info->loc; | |
9db4e0ec RK |
919 | if (XSTR (insn, 0)[0]) |
920 | d->name = XSTR (insn, 0); | |
921 | else | |
922 | d->name = 0; | |
923 | ||
957ae904 TC |
924 | d->compact_syntax_p = compact_syntax.contains (insn); |
925 | ||
9db4e0ec RK |
926 | /* Build up the list in the same order as the insns are seen |
927 | in the machine description. */ | |
928 | d->next = 0; | |
a995e389 RH |
929 | *idata_end = d; |
930 | idata_end = &d->next; | |
9db4e0ec | 931 | |
a995e389 | 932 | memset (d->operand, 0, sizeof (d->operand)); |
9db4e0ec RK |
933 | |
934 | for (i = 0; i < XVECLEN (insn, 1); i++) | |
a995e389 | 935 | scan_operands (d, XVECEXP (insn, 1, i), 0, 0); |
9db4e0ec | 936 | |
b29387ee RS |
937 | get_pattern_stats (&stats, XVEC (insn, 1)); |
938 | d->n_generator_args = stats.num_generator_args; | |
939 | d->n_operands = stats.num_insn_operands; | |
940 | d->n_dups = stats.num_dups; | |
9db4e0ec | 941 | |
c77e04ae | 942 | validate_insn_operands (d); |
9db4e0ec | 943 | validate_insn_alternatives (d); |
7ddf71e3 | 944 | validate_optab_operands (d); |
a995e389 | 945 | place_operands (d); |
1f3b37a3 | 946 | process_template (d, XTMPL (insn, 3)); |
9db4e0ec RK |
947 | } |
948 | \f | |
949 | /* Look at a define_peephole just read. Assign its code number. | |
a995e389 | 950 | Record on idata the template and the number of arguments. |
9db4e0ec RK |
951 | If the insn has a hairy output action, output it now. */ |
952 | ||
953 | static void | |
5d2d3e43 | 954 | gen_peephole (md_rtx_info *info) |
9db4e0ec | 955 | { |
b29387ee | 956 | struct pattern_stats stats; |
ca018d3c | 957 | data *d = new data; |
b3694847 | 958 | int i; |
9db4e0ec | 959 | |
5d2d3e43 RS |
960 | d->code_number = info->index; |
961 | d->loc = info->loc; | |
9db4e0ec RK |
962 | d->name = 0; |
963 | ||
964 | /* Build up the list in the same order as the insns are seen | |
965 | in the machine description. */ | |
966 | d->next = 0; | |
a995e389 RH |
967 | *idata_end = d; |
968 | idata_end = &d->next; | |
9db4e0ec | 969 | |
a995e389 RH |
970 | memset (d->operand, 0, sizeof (d->operand)); |
971 | ||
972 | /* Get the number of operands by scanning all the patterns of the | |
973 | peephole optimizer. But ignore all the rest of the information | |
974 | thus obtained. */ | |
5d2d3e43 | 975 | rtx peep = info->def; |
9db4e0ec | 976 | for (i = 0; i < XVECLEN (peep, 0); i++) |
a995e389 | 977 | scan_operands (d, XVECEXP (peep, 0, i), 0, 0); |
9db4e0ec | 978 | |
b29387ee RS |
979 | get_pattern_stats (&stats, XVEC (peep, 0)); |
980 | d->n_generator_args = 0; | |
981 | d->n_operands = stats.num_insn_operands; | |
9db4e0ec RK |
982 | d->n_dups = 0; |
983 | ||
9db4e0ec | 984 | validate_insn_alternatives (d); |
a995e389 | 985 | place_operands (d); |
1f3b37a3 | 986 | process_template (d, XTMPL (peep, 2)); |
9db4e0ec RK |
987 | } |
988 | \f | |
989 | /* Process a define_expand just read. Assign its code number, | |
990 | only for the purposes of `insn_gen_function'. */ | |
991 | ||
992 | static void | |
5d2d3e43 | 993 | gen_expand (md_rtx_info *info) |
9db4e0ec | 994 | { |
b29387ee | 995 | struct pattern_stats stats; |
5d2d3e43 | 996 | rtx insn = info->def; |
ca018d3c | 997 | data *d = new data; |
b3694847 | 998 | int i; |
9db4e0ec | 999 | |
5d2d3e43 RS |
1000 | d->code_number = info->index; |
1001 | d->loc = info->loc; | |
9db4e0ec RK |
1002 | if (XSTR (insn, 0)[0]) |
1003 | d->name = XSTR (insn, 0); | |
1004 | else | |
1005 | d->name = 0; | |
1006 | ||
1007 | /* Build up the list in the same order as the insns are seen | |
1008 | in the machine description. */ | |
1009 | d->next = 0; | |
a995e389 RH |
1010 | *idata_end = d; |
1011 | idata_end = &d->next; | |
9db4e0ec | 1012 | |
a995e389 | 1013 | memset (d->operand, 0, sizeof (d->operand)); |
9db4e0ec RK |
1014 | |
1015 | /* Scan the operands to get the specified predicates and modes, | |
1016 | since expand_binop needs to know them. */ | |
1017 | ||
9db4e0ec RK |
1018 | if (XVEC (insn, 1)) |
1019 | for (i = 0; i < XVECLEN (insn, 1); i++) | |
a995e389 | 1020 | scan_operands (d, XVECEXP (insn, 1, i), 0, 0); |
9db4e0ec | 1021 | |
b29387ee RS |
1022 | get_pattern_stats (&stats, XVEC (insn, 1)); |
1023 | d->n_generator_args = stats.num_generator_args; | |
1024 | d->n_operands = stats.num_insn_operands; | |
1025 | d->n_dups = stats.num_dups; | |
8ad97cfc | 1026 | d->template_code = 0; |
4bbf910e | 1027 | d->output_format = INSN_OUTPUT_FORMAT_NONE; |
a995e389 | 1028 | |
9db4e0ec | 1029 | validate_insn_alternatives (d); |
7ddf71e3 | 1030 | validate_optab_operands (d); |
a995e389 | 1031 | place_operands (d); |
9db4e0ec RK |
1032 | } |
1033 | \f | |
e714561a SB |
1034 | static void |
1035 | init_insn_for_nothing (void) | |
1036 | { | |
99b1c316 | 1037 | idata = XCNEW (class data); |
ca018d3c RS |
1038 | new (idata) data (); |
1039 | idata->name = "*placeholder_for_nothing"; | |
3814e880 | 1040 | idata->loc = file_location ("<internal>", 0, 0); |
ca018d3c | 1041 | idata_end = &idata->next; |
e714561a SB |
1042 | } |
1043 | ||
66b0fe8f | 1044 | extern int main (int, const char **); |
c1b59dce | 1045 | |
9db4e0ec | 1046 | int |
66b0fe8f | 1047 | main (int argc, const char **argv) |
9db4e0ec | 1048 | { |
d80eb1e1 RH |
1049 | progname = "genoutput"; |
1050 | ||
e714561a SB |
1051 | init_insn_for_nothing (); |
1052 | ||
600ab3fc | 1053 | if (!init_rtx_reader_args (argc, argv)) |
c88c0d42 | 1054 | return (FATAL_EXIT_CODE); |
9db4e0ec | 1055 | |
9db4e0ec | 1056 | output_prologue (); |
9db4e0ec RK |
1057 | |
1058 | /* Read the machine description. */ | |
1059 | ||
5d2d3e43 RS |
1060 | md_rtx_info info; |
1061 | while (read_md_rtx (&info)) | |
1062 | switch (GET_CODE (info.def)) | |
1063 | { | |
1064 | case DEFINE_INSN: | |
1065 | gen_insn (&info); | |
9db4e0ec | 1066 | break; |
9db4e0ec | 1067 | |
5d2d3e43 RS |
1068 | case DEFINE_PEEPHOLE: |
1069 | gen_peephole (&info); | |
1070 | break; | |
f38840db | 1071 | |
5d2d3e43 RS |
1072 | case DEFINE_EXPAND: |
1073 | gen_expand (&info); | |
1074 | break; | |
f38840db | 1075 | |
5d2d3e43 RS |
1076 | case DEFINE_CONSTRAINT: |
1077 | case DEFINE_REGISTER_CONSTRAINT: | |
1078 | case DEFINE_ADDRESS_CONSTRAINT: | |
1079 | case DEFINE_MEMORY_CONSTRAINT: | |
9eb1ca69 | 1080 | case DEFINE_SPECIAL_MEMORY_CONSTRAINT: |
02f2dc44 | 1081 | case DEFINE_RELAXED_MEMORY_CONSTRAINT: |
5d2d3e43 RS |
1082 | note_constraint (&info); |
1083 | break; | |
f38840db | 1084 | |
5d2d3e43 RS |
1085 | default: |
1086 | break; | |
1087 | } | |
9db4e0ec | 1088 | |
c3284718 | 1089 | printf ("\n\n"); |
a995e389 RH |
1090 | output_operand_data (); |
1091 | output_insn_data (); | |
1092 | output_get_insn_name (); | |
9db4e0ec RK |
1093 | |
1094 | fflush (stdout); | |
c1b59dce | 1095 | return (ferror (stdout) != 0 || have_error |
6a270722 | 1096 | ? FATAL_EXIT_CODE : SUCCESS_EXIT_CODE); |
9db4e0ec RK |
1097 | } |
1098 | ||
665f2503 RK |
1099 | /* Return the number of occurrences of character C in string S or |
1100 | -1 if S is the null string. */ | |
1101 | ||
9db4e0ec | 1102 | static int |
3d7aafde | 1103 | n_occurrences (int c, const char *s) |
9db4e0ec RK |
1104 | { |
1105 | int n = 0; | |
665f2503 RK |
1106 | |
1107 | if (s == 0 || *s == '\0') | |
1108 | return -1; | |
1109 | ||
9db4e0ec RK |
1110 | while (*s) |
1111 | n += (*s++ == c); | |
665f2503 | 1112 | |
9db4e0ec RK |
1113 | return n; |
1114 | } | |
88a56c2e | 1115 | |
665f2503 RK |
1116 | /* Remove whitespace in `s' by moving up characters until the end. |
1117 | Return a new string. */ | |
1118 | ||
1119 | static const char * | |
3d7aafde | 1120 | strip_whitespace (const char *s) |
88a56c2e | 1121 | { |
665f2503 RK |
1122 | char *p, *q; |
1123 | char ch; | |
1124 | ||
1125 | if (s == 0) | |
1126 | return 0; | |
88a56c2e | 1127 | |
5ed6ace5 | 1128 | p = q = XNEWVEC (char, strlen (s) + 1); |
88a56c2e HPN |
1129 | while ((ch = *s++) != '\0') |
1130 | if (! ISSPACE (ch)) | |
1131 | *p++ = ch; | |
1132 | ||
1133 | *p = '\0'; | |
665f2503 | 1134 | return q; |
88a56c2e | 1135 | } |
97488870 | 1136 | |
5d2d3e43 RS |
1137 | /* Record just enough information about the constraint in *INFO to allow |
1138 | checking of operand constraint strings above, in validate_insn_alternatives. | |
1139 | Does not validate most properties of the constraint itself; does enforce | |
1140 | no duplicate names, no overlap with MI constraints, and no prefixes. */ | |
f38840db | 1141 | static void |
5d2d3e43 | 1142 | note_constraint (md_rtx_info *info) |
f38840db | 1143 | { |
5d2d3e43 | 1144 | rtx exp = info->def; |
f38840db | 1145 | const char *name = XSTR (exp, 0); |
99b1c316 | 1146 | class constraint_data **iter, **slot, *new_cdata; |
f38840db | 1147 | |
8677664e RS |
1148 | if (strcmp (name, "TARGET_MEM_CONSTRAINT") == 0) |
1149 | name = general_mem; | |
1150 | unsigned int namelen = strlen (name); | |
1151 | ||
1152 | if (strchr (indep_constraints, name[0])) | |
f38840db ZW |
1153 | { |
1154 | if (name[1] == '\0') | |
5d2d3e43 RS |
1155 | error_at (info->loc, "constraint letter '%s' cannot be " |
1156 | "redefined by the machine description", name); | |
f38840db | 1157 | else |
5d2d3e43 RS |
1158 | error_at (info->loc, "constraint name '%s' cannot be defined by " |
1159 | "the machine description, as it begins with '%c'", | |
1160 | name, name[0]); | |
f38840db ZW |
1161 | return; |
1162 | } | |
1163 | ||
1164 | slot = &constraints_by_letter_table[(unsigned int)name[0]]; | |
1165 | for (iter = slot; *iter; iter = &(*iter)->next_this_letter) | |
1166 | { | |
1167 | /* This causes slot to end up pointing to the | |
1168 | next_this_letter field of the last constraint with a name | |
1169 | of equal or greater length than the new constraint; hence | |
1170 | the new constraint will be inserted after all previous | |
1171 | constraints with names of the same length. */ | |
1172 | if ((*iter)->namelen >= namelen) | |
1173 | slot = iter; | |
1174 | ||
1175 | if (!strcmp ((*iter)->name, name)) | |
1176 | { | |
5d2d3e43 | 1177 | error_at (info->loc, "redefinition of constraint '%s'", name); |
ca018d3c | 1178 | message_at ((*iter)->loc, "previous definition is here"); |
f38840db ZW |
1179 | return; |
1180 | } | |
1181 | else if (!strncmp ((*iter)->name, name, (*iter)->namelen)) | |
1182 | { | |
5d2d3e43 | 1183 | error_at (info->loc, "defining constraint '%s' here", name); |
ca018d3c RS |
1184 | message_at ((*iter)->loc, "renders constraint '%s' " |
1185 | "(defined here) a prefix", (*iter)->name); | |
f38840db ZW |
1186 | return; |
1187 | } | |
1188 | else if (!strncmp ((*iter)->name, name, namelen)) | |
1189 | { | |
5d2d3e43 | 1190 | error_at (info->loc, "constraint '%s' is a prefix", name); |
ca018d3c RS |
1191 | message_at ((*iter)->loc, "of constraint '%s' " |
1192 | "(defined here)", (*iter)->name); | |
f38840db ZW |
1193 | return; |
1194 | } | |
1195 | } | |
99b1c316 MS |
1196 | new_cdata = XNEWVAR (class constraint_data, |
1197 | sizeof (class constraint_data) + namelen); | |
ca018d3c | 1198 | new (new_cdata) constraint_data (); |
c3284718 | 1199 | strcpy (CONST_CAST (char *, new_cdata->name), name); |
8ad97cfc | 1200 | new_cdata->namelen = namelen; |
5d2d3e43 | 1201 | new_cdata->loc = info->loc; |
8ad97cfc KG |
1202 | new_cdata->next_this_letter = *slot; |
1203 | *slot = new_cdata; | |
f38840db ZW |
1204 | } |
1205 | ||
1206 | /* Return the length of the constraint name beginning at position S | |
1207 | of an operand constraint string, or issue an error message if there | |
1208 | is no such constraint. Does not expect to be called for generic | |
1209 | constraints. */ | |
1210 | static int | |
ca018d3c | 1211 | mdep_constraint_len (const char *s, file_location loc, int opno) |
f38840db | 1212 | { |
99b1c316 | 1213 | class constraint_data *p; |
f38840db ZW |
1214 | |
1215 | p = constraints_by_letter_table[(unsigned int)s[0]]; | |
1216 | ||
1217 | if (p) | |
1218 | for (; p; p = p->next_this_letter) | |
1219 | if (!strncmp (s, p->name, p->namelen)) | |
1220 | return p->namelen; | |
1221 | ||
ca018d3c RS |
1222 | error_at (loc, "error: undefined machine-specific constraint " |
1223 | "at this point: \"%s\"", s); | |
1224 | message_at (loc, "note: in operand %d", opno); | |
f38840db ZW |
1225 | return 1; /* safe */ |
1226 | } |