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