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