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