genemit.c revision 52284
1/* Generate code from machine description to emit insns as rtl. 2 Copyright (C) 1987, 88, 91, 94, 95, 97, 98, 1999 Free Software Foundation, Inc. 3 4This file is part of GNU CC. 5 6GNU CC is free software; you can redistribute it and/or modify 7it under the terms of the GNU General Public License as published by 8the Free Software Foundation; either version 2, or (at your option) 9any later version. 10 11GNU CC is distributed in the hope that it will be useful, 12but WITHOUT ANY WARRANTY; without even the implied warranty of 13MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14GNU General Public License for more details. 15 16You should have received a copy of the GNU General Public License 17along with GNU CC; see the file COPYING. If not, write to 18the Free Software Foundation, 59 Temple Place - Suite 330, 19Boston, MA 02111-1307, USA. */ 20 21 22#include "hconfig.h" 23#include "system.h" 24#include "rtl.h" 25#include "obstack.h" 26 27static struct obstack obstack; 28struct obstack *rtl_obstack = &obstack; 29 30#define obstack_chunk_alloc xmalloc 31#define obstack_chunk_free free 32 33void fatal PVPROTO ((const char *, ...)) 34 ATTRIBUTE_PRINTF_1 ATTRIBUTE_NORETURN; 35void fancy_abort PROTO((void)) ATTRIBUTE_NORETURN; 36 37/* Define this so we can link with print-rtl.o to get debug_rtx function. */ 38char **insn_name_ptr = 0; 39 40static int max_opno; 41static int max_dup_opno; 42static int register_constraints; 43static int insn_code_number; 44static int insn_index_number; 45 46/* Data structure for recording the patterns of insns that have CLOBBERs. 47 We use this to output a function that adds these CLOBBERs to a 48 previously-allocated PARALLEL expression. */ 49 50struct clobber_pat 51{ 52 struct clobber_ent *insns; 53 rtx pattern; 54 int first_clobber; 55 struct clobber_pat *next; 56} *clobber_list; 57 58/* Records one insn that uses the clobber list. */ 59 60struct clobber_ent 61{ 62 int code_number; /* Counts only insns. */ 63 struct clobber_ent *next; 64}; 65 66static void max_operand_1 PROTO((rtx)); 67static int max_operand_vec PROTO((rtx, int)); 68static void print_code PROTO((RTX_CODE)); 69static void gen_exp PROTO((rtx)); 70static void gen_insn PROTO((rtx)); 71static void gen_expand PROTO((rtx)); 72static void gen_split PROTO((rtx)); 73static void output_add_clobbers PROTO((void)); 74static void output_init_mov_optab PROTO((void)); 75 76 77static void 78max_operand_1 (x) 79 rtx x; 80{ 81 register RTX_CODE code; 82 register int i; 83 register int len; 84 register char *fmt; 85 86 if (x == 0) 87 return; 88 89 code = GET_CODE (x); 90 91 if (code == MATCH_OPERAND && XSTR (x, 2) != 0 && *XSTR (x, 2) != '\0') 92 register_constraints = 1; 93 if (code == MATCH_SCRATCH && XSTR (x, 1) != 0 && *XSTR (x, 1) != '\0') 94 register_constraints = 1; 95 if (code == MATCH_OPERAND || code == MATCH_OPERATOR 96 || code == MATCH_PARALLEL) 97 max_opno = MAX (max_opno, XINT (x, 0)); 98 if (code == MATCH_DUP || code == MATCH_OP_DUP || code == MATCH_PAR_DUP) 99 max_dup_opno = MAX (max_dup_opno, XINT (x, 0)); 100 101 fmt = GET_RTX_FORMAT (code); 102 len = GET_RTX_LENGTH (code); 103 for (i = 0; i < len; i++) 104 { 105 if (fmt[i] == 'e' || fmt[i] == 'u') 106 max_operand_1 (XEXP (x, i)); 107 else if (fmt[i] == 'E') 108 { 109 int j; 110 for (j = 0; j < XVECLEN (x, i); j++) 111 max_operand_1 (XVECEXP (x, i, j)); 112 } 113 } 114} 115 116static int 117max_operand_vec (insn, arg) 118 rtx insn; 119 int arg; 120{ 121 register int len = XVECLEN (insn, arg); 122 register int i; 123 124 max_opno = -1; 125 max_dup_opno = -1; 126 127 for (i = 0; i < len; i++) 128 max_operand_1 (XVECEXP (insn, arg, i)); 129 130 return max_opno + 1; 131} 132 133static void 134print_code (code) 135 RTX_CODE code; 136{ 137 register char *p1; 138 for (p1 = GET_RTX_NAME (code); *p1; p1++) 139 { 140 if (*p1 >= 'a' && *p1 <= 'z') 141 putchar (*p1 + 'A' - 'a'); 142 else 143 putchar (*p1); 144 } 145} 146 147/* Print a C expression to construct an RTX just like X, 148 substituting any operand references appearing within. */ 149 150static void 151gen_exp (x) 152 rtx x; 153{ 154 register RTX_CODE code; 155 register int i; 156 register int len; 157 register char *fmt; 158 159 if (x == 0) 160 { 161 printf ("NULL_RTX"); 162 return; 163 } 164 165 code = GET_CODE (x); 166 167 switch (code) 168 { 169 case MATCH_OPERAND: 170 case MATCH_DUP: 171 printf ("operand%d", XINT (x, 0)); 172 return; 173 174 case MATCH_OP_DUP: 175 printf ("gen_rtx (GET_CODE (operand%d), ", XINT (x, 0)); 176 if (GET_MODE (x) == VOIDmode) 177 printf ("GET_MODE (operand%d)", XINT (x, 0)); 178 else 179 printf ("%smode", GET_MODE_NAME (GET_MODE (x))); 180 for (i = 0; i < XVECLEN (x, 1); i++) 181 { 182 printf (",\n\t\t"); 183 gen_exp (XVECEXP (x, 1, i)); 184 } 185 printf (")"); 186 return; 187 188 case MATCH_OPERATOR: 189 printf ("gen_rtx (GET_CODE (operand%d)", XINT (x, 0)); 190 printf (", %smode", GET_MODE_NAME (GET_MODE (x))); 191 for (i = 0; i < XVECLEN (x, 2); i++) 192 { 193 printf (",\n\t\t"); 194 gen_exp (XVECEXP (x, 2, i)); 195 } 196 printf (")"); 197 return; 198 199 case MATCH_PARALLEL: 200 case MATCH_PAR_DUP: 201 printf ("operand%d", XINT (x, 0)); 202 return; 203 204 case MATCH_SCRATCH: 205 printf ("gen_rtx_SCRATCH (%smode)", GET_MODE_NAME (GET_MODE (x))); 206 return; 207 208 case ADDRESS: 209 fatal ("ADDRESS expression code used in named instruction pattern"); 210 211 case PC: 212 printf ("pc_rtx"); 213 return; 214 215 case CC0: 216 printf ("cc0_rtx"); 217 return; 218 219 case CONST_INT: 220 if (INTVAL (x) == 0) 221 printf ("const0_rtx"); 222 else if (INTVAL (x) == 1) 223 printf ("const1_rtx"); 224 else if (INTVAL (x) == -1) 225 printf ("constm1_rtx"); 226 else if (INTVAL (x) == STORE_FLAG_VALUE) 227 printf ("const_true_rtx"); 228 else 229 { 230 printf ("GEN_INT ("); 231 printf (HOST_WIDE_INT_PRINT_DEC, INTVAL (x)); 232 printf (")"); 233 } 234 return; 235 236 case CONST_DOUBLE: 237 /* These shouldn't be written in MD files. Instead, the appropriate 238 routines in varasm.c should be called. */ 239 abort (); 240 241 default: 242 break; 243 } 244 245 printf ("gen_rtx_"); 246 print_code (code); 247 printf (" (%smode", GET_MODE_NAME (GET_MODE (x))); 248 249 fmt = GET_RTX_FORMAT (code); 250 len = GET_RTX_LENGTH (code); 251 for (i = 0; i < len; i++) 252 { 253 if (fmt[i] == '0') 254 break; 255 printf (",\n\t"); 256 if (fmt[i] == 'e' || fmt[i] == 'u') 257 gen_exp (XEXP (x, i)); 258 else if (fmt[i] == 'i') 259 printf ("%u", XINT (x, i)); 260 else if (fmt[i] == 's') 261 printf ("\"%s\"", XSTR (x, i)); 262 else if (fmt[i] == 'E') 263 { 264 int j; 265 printf ("gen_rtvec (%d", XVECLEN (x, i)); 266 for (j = 0; j < XVECLEN (x, i); j++) 267 { 268 printf (",\n\t\t"); 269 gen_exp (XVECEXP (x, i, j)); 270 } 271 printf (")"); 272 } 273 else 274 abort (); 275 } 276 printf (")"); 277} 278 279/* Generate the `gen_...' function for a DEFINE_INSN. */ 280 281static void 282gen_insn (insn) 283 rtx insn; 284{ 285 int operands; 286 register int i; 287 288 /* See if the pattern for this insn ends with a group of CLOBBERs of (hard) 289 registers or MATCH_SCRATCHes. If so, store away the information for 290 later. */ 291 292 if (XVEC (insn, 1)) 293 { 294 for (i = XVECLEN (insn, 1) - 1; i > 0; i--) 295 if (GET_CODE (XVECEXP (insn, 1, i)) != CLOBBER 296 || (GET_CODE (XEXP (XVECEXP (insn, 1, i), 0)) != REG 297 && GET_CODE (XEXP (XVECEXP (insn, 1, i), 0)) != MATCH_SCRATCH)) 298 break; 299 300 if (i != XVECLEN (insn, 1) - 1) 301 { 302 register struct clobber_pat *p; 303 register struct clobber_ent *link 304 = (struct clobber_ent *) xmalloc (sizeof (struct clobber_ent)); 305 register int j; 306 307 link->code_number = insn_code_number; 308 309 /* See if any previous CLOBBER_LIST entry is the same as this 310 one. */ 311 312 for (p = clobber_list; p; p = p->next) 313 { 314 if (p->first_clobber != i + 1 315 || XVECLEN (p->pattern, 1) != XVECLEN (insn, 1)) 316 continue; 317 318 for (j = i + 1; j < XVECLEN (insn, 1); j++) 319 { 320 rtx old = XEXP (XVECEXP (p->pattern, 1, j), 0); 321 rtx new = XEXP (XVECEXP (insn, 1, j), 0); 322 323 /* OLD and NEW are the same if both are to be a SCRATCH 324 of the same mode, 325 or if both are registers of the same mode and number. */ 326 if (! (GET_MODE (old) == GET_MODE (new) 327 && ((GET_CODE (old) == MATCH_SCRATCH 328 && GET_CODE (new) == MATCH_SCRATCH) 329 || (GET_CODE (old) == REG && GET_CODE (new) == REG 330 && REGNO (old) == REGNO (new))))) 331 break; 332 } 333 334 if (j == XVECLEN (insn, 1)) 335 break; 336 } 337 338 if (p == 0) 339 { 340 p = (struct clobber_pat *) xmalloc (sizeof (struct clobber_pat)); 341 342 p->insns = 0; 343 p->pattern = insn; 344 p->first_clobber = i + 1; 345 p->next = clobber_list; 346 clobber_list = p; 347 } 348 349 link->next = p->insns; 350 p->insns = link; 351 } 352 } 353 354 /* Don't mention instructions whose names are the null string 355 or begin with '*'. They are in the machine description just 356 to be recognized. */ 357 if (XSTR (insn, 0)[0] == 0 || XSTR (insn, 0)[0] == '*') 358 return; 359 360 /* Find out how many operands this function has, 361 and also whether any of them have register constraints. */ 362 register_constraints = 0; 363 operands = max_operand_vec (insn, 1); 364 if (max_dup_opno >= operands) 365 fatal ("match_dup operand number has no match_operand"); 366 367 /* Output the function name and argument declarations. */ 368 printf ("rtx\ngen_%s (", XSTR (insn, 0)); 369 for (i = 0; i < operands; i++) 370 printf (i ? ", operand%d" : "operand%d", i); 371 printf (")\n"); 372 for (i = 0; i < operands; i++) 373 printf (" rtx operand%d;\n", i); 374 printf ("{\n"); 375 376 /* Output code to construct and return the rtl for the instruction body */ 377 378 if (XVECLEN (insn, 1) == 1) 379 { 380 printf (" return "); 381 gen_exp (XVECEXP (insn, 1, 0)); 382 printf (";\n}\n\n"); 383 } 384 else 385 { 386 printf (" return gen_rtx_PARALLEL (VOIDmode, gen_rtvec (%d", XVECLEN (insn, 1)); 387 for (i = 0; i < XVECLEN (insn, 1); i++) 388 { 389 printf (",\n\t\t"); 390 gen_exp (XVECEXP (insn, 1, i)); 391 } 392 printf ("));\n}\n\n"); 393 } 394} 395 396/* Generate the `gen_...' function for a DEFINE_EXPAND. */ 397 398static void 399gen_expand (expand) 400 rtx expand; 401{ 402 int operands; 403 register int i; 404 405 if (strlen (XSTR (expand, 0)) == 0) 406 fatal ("define_expand lacks a name"); 407 if (XVEC (expand, 1) == 0) 408 fatal ("define_expand for %s lacks a pattern", XSTR (expand, 0)); 409 410 /* Find out how many operands this function has, 411 and also whether any of them have register constraints. */ 412 register_constraints = 0; 413 414 operands = max_operand_vec (expand, 1); 415 416 /* Output the function name and argument declarations. */ 417 printf ("rtx\ngen_%s (", XSTR (expand, 0)); 418 for (i = 0; i < operands; i++) 419 printf (i ? ", operand%d" : "operand%d", i); 420 printf (")\n"); 421 for (i = 0; i < operands; i++) 422 printf (" rtx operand%d;\n", i); 423 printf ("{\n"); 424 425 /* If we don't have any C code to write, only one insn is being written, 426 and no MATCH_DUPs are present, we can just return the desired insn 427 like we do for a DEFINE_INSN. This saves memory. */ 428 if ((XSTR (expand, 3) == 0 || *XSTR (expand, 3) == '\0') 429 && operands > max_dup_opno 430 && XVECLEN (expand, 1) == 1) 431 { 432 printf (" return "); 433 gen_exp (XVECEXP (expand, 1, 0)); 434 printf (";\n}\n\n"); 435 return; 436 } 437 438 /* For each operand referred to only with MATCH_DUPs, 439 make a local variable. */ 440 for (i = operands; i <= max_dup_opno; i++) 441 printf (" rtx operand%d;\n", i); 442 if (operands > 0 || max_dup_opno >= 0) 443 printf (" rtx operands[%d];\n", MAX (operands, max_dup_opno + 1)); 444 printf (" rtx _val = 0;\n"); 445 printf (" start_sequence ();\n"); 446 447 /* The fourth operand of DEFINE_EXPAND is some code to be executed 448 before the actual construction. 449 This code expects to refer to `operands' 450 just as the output-code in a DEFINE_INSN does, 451 but here `operands' is an automatic array. 452 So copy the operand values there before executing it. */ 453 if (XSTR (expand, 3) && *XSTR (expand, 3)) 454 { 455 /* Output code to copy the arguments into `operands'. */ 456 for (i = 0; i < operands; i++) 457 printf (" operands[%d] = operand%d;\n", i, i); 458 459 /* Output the special code to be executed before the sequence 460 is generated. */ 461 printf ("%s\n", XSTR (expand, 3)); 462 463 /* Output code to copy the arguments back out of `operands' 464 (unless we aren't going to use them at all). */ 465 if (XVEC (expand, 1) != 0) 466 { 467 for (i = 0; i < operands; i++) 468 printf (" operand%d = operands[%d];\n", i, i); 469 for (; i <= max_dup_opno; i++) 470 printf (" operand%d = operands[%d];\n", i, i); 471 } 472 } 473 474 /* Output code to construct the rtl for the instruction bodies. 475 Use emit_insn to add them to the sequence being accumulated. 476 But don't do this if the user's code has set `no_more' nonzero. */ 477 478 for (i = 0; i < XVECLEN (expand, 1); i++) 479 { 480 rtx next = XVECEXP (expand, 1, i); 481 if ((GET_CODE (next) == SET && GET_CODE (SET_DEST (next)) == PC) 482 || (GET_CODE (next) == PARALLEL 483 && GET_CODE (XVECEXP (next, 0, 0)) == SET 484 && GET_CODE (SET_DEST (XVECEXP (next, 0, 0))) == PC) 485 || GET_CODE (next) == RETURN) 486 printf (" emit_jump_insn ("); 487 else if ((GET_CODE (next) == SET && GET_CODE (SET_SRC (next)) == CALL) 488 || GET_CODE (next) == CALL 489 || (GET_CODE (next) == PARALLEL 490 && GET_CODE (XVECEXP (next, 0, 0)) == SET 491 && GET_CODE (SET_SRC (XVECEXP (next, 0, 0))) == CALL) 492 || (GET_CODE (next) == PARALLEL 493 && GET_CODE (XVECEXP (next, 0, 0)) == CALL)) 494 printf (" emit_call_insn ("); 495 else if (GET_CODE (next) == CODE_LABEL) 496 printf (" emit_label ("); 497 else if (GET_CODE (next) == MATCH_OPERAND 498 || GET_CODE (next) == MATCH_OPERATOR 499 || GET_CODE (next) == MATCH_PARALLEL 500 || GET_CODE (next) == MATCH_OP_DUP 501 || GET_CODE (next) == MATCH_DUP 502 || GET_CODE (next) == PARALLEL) 503 printf (" emit ("); 504 else 505 printf (" emit_insn ("); 506 gen_exp (next); 507 printf (");\n"); 508 if (GET_CODE (next) == SET && GET_CODE (SET_DEST (next)) == PC 509 && GET_CODE (SET_SRC (next)) == LABEL_REF) 510 printf (" emit_barrier ();"); 511 } 512 513 /* Call `gen_sequence' to make a SEQUENCE out of all the 514 insns emitted within this gen_... function. */ 515 516 printf (" _val = gen_sequence ();\n"); 517 printf (" end_sequence ();\n"); 518 printf (" return _val;\n}\n\n"); 519} 520 521/* Like gen_expand, but generates a SEQUENCE. */ 522 523static void 524gen_split (split) 525 rtx split; 526{ 527 register int i; 528 int operands; 529 530 if (XVEC (split, 0) == 0) 531 fatal ("define_split (definition %d) lacks a pattern", insn_index_number); 532 else if (XVEC (split, 2) == 0) 533 fatal ("define_split (definition %d) lacks a replacement pattern", 534 insn_index_number); 535 536 /* Find out how many operands this function has. */ 537 538 max_operand_vec (split, 2); 539 operands = MAX (max_opno, max_dup_opno) + 1; 540 541 /* Output the function name and argument declarations. */ 542 printf ("rtx\ngen_split_%d (operands)\n rtx *operands;\n", 543 insn_code_number); 544 printf ("{\n"); 545 546 /* Declare all local variables. */ 547 for (i = 0; i < operands; i++) 548 printf (" rtx operand%d;\n", i); 549 printf (" rtx _val = 0;\n"); 550 printf (" start_sequence ();\n"); 551 552 /* The fourth operand of DEFINE_SPLIT is some code to be executed 553 before the actual construction. */ 554 555 if (XSTR (split, 3)) 556 printf ("%s\n", XSTR (split, 3)); 557 558 /* Output code to copy the arguments back out of `operands' */ 559 for (i = 0; i < operands; i++) 560 printf (" operand%d = operands[%d];\n", i, i); 561 562 /* Output code to construct the rtl for the instruction bodies. 563 Use emit_insn to add them to the sequence being accumulated. 564 But don't do this if the user's code has set `no_more' nonzero. */ 565 566 for (i = 0; i < XVECLEN (split, 2); i++) 567 { 568 rtx next = XVECEXP (split, 2, i); 569 if ((GET_CODE (next) == SET && GET_CODE (SET_DEST (next)) == PC) 570 || (GET_CODE (next) == PARALLEL 571 && GET_CODE (XVECEXP (next, 0, 0)) == SET 572 && GET_CODE (SET_DEST (XVECEXP (next, 0, 0))) == PC) 573 || GET_CODE (next) == RETURN) 574 printf (" emit_jump_insn ("); 575 else if ((GET_CODE (next) == SET && GET_CODE (SET_SRC (next)) == CALL) 576 || GET_CODE (next) == CALL 577 || (GET_CODE (next) == PARALLEL 578 && GET_CODE (XVECEXP (next, 0, 0)) == SET 579 && GET_CODE (SET_SRC (XVECEXP (next, 0, 0))) == CALL) 580 || (GET_CODE (next) == PARALLEL 581 && GET_CODE (XVECEXP (next, 0, 0)) == CALL)) 582 printf (" emit_call_insn ("); 583 else if (GET_CODE (next) == CODE_LABEL) 584 printf (" emit_label ("); 585 else if (GET_CODE (next) == MATCH_OPERAND 586 || GET_CODE (next) == MATCH_OPERATOR 587 || GET_CODE (next) == MATCH_PARALLEL 588 || GET_CODE (next) == MATCH_OP_DUP 589 || GET_CODE (next) == MATCH_DUP 590 || GET_CODE (next) == PARALLEL) 591 printf (" emit ("); 592 else 593 printf (" emit_insn ("); 594 gen_exp (next); 595 printf (");\n"); 596 if (GET_CODE (next) == SET && GET_CODE (SET_DEST (next)) == PC 597 && GET_CODE (SET_SRC (next)) == LABEL_REF) 598 printf (" emit_barrier ();"); 599 } 600 601 /* Call `gen_sequence' to make a SEQUENCE out of all the 602 insns emitted within this gen_... function. */ 603 604 printf (" _val = gen_sequence ();\n"); 605 printf (" end_sequence ();\n"); 606 printf (" return _val;\n}\n\n"); 607} 608 609/* Write a function, `add_clobbers', that is given a PARALLEL of sufficient 610 size for the insn and an INSN_CODE, and inserts the required CLOBBERs at 611 the end of the vector. */ 612 613static void 614output_add_clobbers () 615{ 616 struct clobber_pat *clobber; 617 struct clobber_ent *ent; 618 int i; 619 620 printf ("\n\nvoid\nadd_clobbers (pattern, insn_code_number)\n"); 621 printf (" rtx pattern;\n int insn_code_number;\n"); 622 printf ("{\n"); 623 printf (" switch (insn_code_number)\n"); 624 printf (" {\n"); 625 626 for (clobber = clobber_list; clobber; clobber = clobber->next) 627 { 628 for (ent = clobber->insns; ent; ent = ent->next) 629 printf (" case %d:\n", ent->code_number); 630 631 for (i = clobber->first_clobber; i < XVECLEN (clobber->pattern, 1); i++) 632 { 633 printf (" XVECEXP (pattern, 0, %d) = ", i); 634 gen_exp (XVECEXP (clobber->pattern, 1, i)); 635 printf (";\n"); 636 } 637 638 printf (" break;\n\n"); 639 } 640 641 printf (" default:\n"); 642 printf (" abort ();\n"); 643 printf (" }\n"); 644 printf ("}\n"); 645} 646 647/* Write a function, init_mov_optab, that is called to set up entries 648 in mov_optab for EXTRA_CC_MODES. */ 649 650static void 651output_init_mov_optab () 652{ 653#ifdef EXTRA_CC_NAMES 654 static char *cc_names[] = { EXTRA_CC_NAMES }; 655 char *p; 656 size_t i; 657 658 printf ("\nvoid\ninit_mov_optab ()\n{\n"); 659 660 for (i = 0; i < sizeof cc_names / sizeof cc_names[0]; i++) 661 { 662 printf ("#ifdef HAVE_mov"); 663 for (p = cc_names[i]; *p; p++) 664 printf ("%c", *p >= 'A' && *p <= 'Z' ? *p - 'A' + 'a' : *p); 665 printf ("\n"); 666 printf (" if (HAVE_mov"); 667 for (p = cc_names[i]; *p; p++) 668 printf ("%c", *p >= 'A' && *p <= 'Z' ? *p - 'A' + 'a' : *p); 669 printf (")\n"); 670 printf (" mov_optab->handlers[(int) %smode].insn_code = CODE_FOR_mov", 671 cc_names[i]); 672 for (p = cc_names[i]; *p; p++) 673 printf ("%c", *p >= 'A' && *p <= 'Z' ? *p - 'A' + 'a' : *p); 674 printf (";\n#endif\n"); 675 } 676 677 printf ("}\n"); 678#endif 679} 680 681PTR 682xmalloc (size) 683 size_t size; 684{ 685 register PTR val = (PTR) malloc (size); 686 687 if (val == 0) 688 fatal ("virtual memory exhausted"); 689 690 return val; 691} 692 693PTR 694xrealloc (old, size) 695 PTR old; 696 size_t size; 697{ 698 register PTR ptr; 699 if (old) 700 ptr = (PTR) realloc (old, size); 701 else 702 ptr = (PTR) malloc (size); 703 if (!ptr) 704 fatal ("virtual memory exhausted"); 705 return ptr; 706} 707 708void 709fatal VPROTO ((const char *format, ...)) 710{ 711#ifndef ANSI_PROTOTYPES 712 const char *format; 713#endif 714 va_list ap; 715 716 VA_START (ap, format); 717 718#ifndef ANSI_PROTOTYPES 719 format = va_arg (ap, const char *); 720#endif 721 722 fprintf (stderr, "genemit: "); 723 vfprintf (stderr, format, ap); 724 va_end (ap); 725 fprintf (stderr, "\n"); 726 exit (FATAL_EXIT_CODE); 727} 728 729/* More 'friendly' abort that prints the line and file. 730 config.h can #define abort fancy_abort if you like that sort of thing. */ 731 732void 733fancy_abort () 734{ 735 fatal ("Internal gcc abort."); 736} 737 738int 739main (argc, argv) 740 int argc; 741 char **argv; 742{ 743 rtx desc; 744 FILE *infile; 745 register int c; 746 747 obstack_init (rtl_obstack); 748 749 if (argc <= 1) 750 fatal ("No input file name."); 751 752 infile = fopen (argv[1], "r"); 753 if (infile == 0) 754 { 755 perror (argv[1]); 756 exit (FATAL_EXIT_CODE); 757 } 758 759 init_rtl (); 760 761 /* Assign sequential codes to all entries in the machine description 762 in parallel with the tables in insn-output.c. */ 763 764 insn_code_number = 0; 765 insn_index_number = 0; 766 767 printf ("/* Generated automatically by the program `genemit'\n\ 768from the machine description file `md'. */\n\n"); 769 770 printf ("#include \"config.h\"\n"); 771 printf ("#include \"system.h\"\n"); 772 printf ("#include \"rtl.h\"\n"); 773 printf ("#include \"expr.h\"\n"); 774 printf ("#include \"real.h\"\n"); 775 printf ("#include \"flags.h\"\n"); 776 printf ("#include \"output.h\"\n"); 777 printf ("#include \"insn-config.h\"\n"); 778 printf ("#include \"insn-flags.h\"\n"); 779 printf ("#include \"insn-codes.h\"\n"); 780 printf ("#include \"recog.h\"\n"); 781 printf ("#include \"reload.h\"\n\n"); 782 printf ("extern rtx recog_operand[];\n"); 783 printf ("#define operands emit_operand\n\n"); 784 printf ("#define FAIL return (end_sequence (), _val)\n"); 785 printf ("#define DONE return (_val = gen_sequence (), end_sequence (), _val)\n"); 786 787 /* Read the machine description. */ 788 789 while (1) 790 { 791 c = read_skip_spaces (infile); 792 if (c == EOF) 793 break; 794 ungetc (c, infile); 795 796 desc = read_rtx (infile); 797 if (GET_CODE (desc) == DEFINE_INSN) 798 { 799 gen_insn (desc); 800 ++insn_code_number; 801 } 802 if (GET_CODE (desc) == DEFINE_EXPAND) 803 { 804 gen_expand (desc); 805 ++insn_code_number; 806 } 807 if (GET_CODE (desc) == DEFINE_SPLIT) 808 { 809 gen_split (desc); 810 ++insn_code_number; 811 } 812 if (GET_CODE (desc) == DEFINE_PEEPHOLE) 813 { 814 ++insn_code_number; 815 } 816 ++insn_index_number; 817 } 818 819 /* Write out the routine to add CLOBBERs to a pattern. */ 820 output_add_clobbers (); 821 822 /* Write the routine to initialize mov_optab for the EXTRA_CC_MODES. */ 823 output_init_mov_optab (); 824 825 fflush (stdout); 826 exit (ferror (stdout) != 0 ? FATAL_EXIT_CODE : SUCCESS_EXIT_CODE); 827 /* NOTREACHED */ 828 return 0; 829} 830