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