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