1/* Generate code from machine description to emit insns as rtl. 2 Copyright (C) 1987-2022 Free Software Foundation, Inc. 3 4This file is part of GCC. 5 6GCC is free software; you can redistribute it and/or modify it under 7the terms of the GNU General Public License as published by the Free 8Software Foundation; either version 3, or (at your option) any later 9version. 10 11GCC is distributed in the hope that it will be useful, but WITHOUT ANY 12WARRANTY; without even the implied warranty of MERCHANTABILITY or 13FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 14for more details. 15 16You should have received a copy of the GNU General Public License 17along with GCC; see the file COPYING3. If not see 18<http://www.gnu.org/licenses/>. */ 19 20 21#include "bconfig.h" 22#include "system.h" 23#include "coretypes.h" 24#include "tm.h" 25#include "rtl.h" 26#include "errors.h" 27#include "read-md.h" 28#include "gensupport.h" 29 30 31/* Data structure for recording the patterns of insns that have CLOBBERs. 32 We use this to output a function that adds these CLOBBERs to a 33 previously-allocated PARALLEL expression. */ 34 35struct clobber_pat 36{ 37 struct clobber_ent *insns; 38 rtx pattern; 39 int first_clobber; 40 struct clobber_pat *next; 41 int has_hard_reg; 42} *clobber_list; 43 44/* Records one insn that uses the clobber list. */ 45 46struct clobber_ent 47{ 48 int code_number; /* Counts only insns. */ 49 struct clobber_ent *next; 50}; 51 52static void output_peephole2_scratches (rtx); 53 54/* True for <X>_optab if that optab isn't allowed to fail. */ 55static bool nofail_optabs[NUM_OPTABS]; 56 57static void 58print_code (RTX_CODE code) 59{ 60 const char *p1; 61 for (p1 = GET_RTX_NAME (code); *p1; p1++) 62 putchar (TOUPPER (*p1)); 63} 64 65static void 66gen_rtx_scratch (rtx x, enum rtx_code subroutine_type) 67{ 68 if (subroutine_type == DEFINE_PEEPHOLE2) 69 { 70 printf ("operand%d", XINT (x, 0)); 71 } 72 else 73 { 74 printf ("gen_rtx_SCRATCH (%smode)", GET_MODE_NAME (GET_MODE (x))); 75 } 76} 77 78/* Print a C expression to construct an RTX just like X, 79 substituting any operand references appearing within. */ 80 81static void 82gen_exp (rtx x, enum rtx_code subroutine_type, char *used, md_rtx_info *info) 83{ 84 RTX_CODE code; 85 int i; 86 int len; 87 const char *fmt; 88 const char *sep = ""; 89 90 if (x == 0) 91 { 92 printf ("NULL_RTX"); 93 return; 94 } 95 96 code = GET_CODE (x); 97 98 switch (code) 99 { 100 case MATCH_OPERAND: 101 case MATCH_DUP: 102 if (used) 103 { 104 if (used[XINT (x, 0)]) 105 { 106 printf ("copy_rtx (operand%d)", XINT (x, 0)); 107 return; 108 } 109 used[XINT (x, 0)] = 1; 110 } 111 printf ("operand%d", XINT (x, 0)); 112 return; 113 114 case MATCH_OP_DUP: 115 printf ("gen_rtx_fmt_"); 116 for (i = 0; i < XVECLEN (x, 1); i++) 117 printf ("e"); 118 printf (" (GET_CODE (operand%d), ", XINT (x, 0)); 119 if (GET_MODE (x) == VOIDmode) 120 printf ("GET_MODE (operand%d)", XINT (x, 0)); 121 else 122 printf ("%smode", GET_MODE_NAME (GET_MODE (x))); 123 for (i = 0; i < XVECLEN (x, 1); i++) 124 { 125 printf (",\n\t\t"); 126 gen_exp (XVECEXP (x, 1, i), subroutine_type, used, info); 127 } 128 printf (")"); 129 return; 130 131 case MATCH_OPERATOR: 132 printf ("gen_rtx_fmt_"); 133 for (i = 0; i < XVECLEN (x, 2); i++) 134 printf ("e"); 135 printf (" (GET_CODE (operand%d)", XINT (x, 0)); 136 printf (", %smode", GET_MODE_NAME (GET_MODE (x))); 137 for (i = 0; i < XVECLEN (x, 2); i++) 138 { 139 printf (",\n\t\t"); 140 gen_exp (XVECEXP (x, 2, i), subroutine_type, used, info); 141 } 142 printf (")"); 143 return; 144 145 case MATCH_PARALLEL: 146 case MATCH_PAR_DUP: 147 printf ("operand%d", XINT (x, 0)); 148 return; 149 150 case MATCH_SCRATCH: 151 gen_rtx_scratch (x, subroutine_type); 152 return; 153 154 case PC: 155 printf ("pc_rtx"); 156 return; 157 case RETURN: 158 printf ("ret_rtx"); 159 return; 160 case SIMPLE_RETURN: 161 printf ("simple_return_rtx"); 162 return; 163 case CLOBBER: 164 if (REG_P (XEXP (x, 0))) 165 { 166 printf ("gen_hard_reg_clobber (%smode, %i)", 167 GET_MODE_NAME (GET_MODE (XEXP (x, 0))), 168 REGNO (XEXP (x, 0))); 169 return; 170 } 171 break; 172 173 case CONST_INT: 174 if (INTVAL (x) == 0) 175 printf ("const0_rtx"); 176 else if (INTVAL (x) == 1) 177 printf ("const1_rtx"); 178 else if (INTVAL (x) == -1) 179 printf ("constm1_rtx"); 180 else if (-MAX_SAVED_CONST_INT <= INTVAL (x) 181 && INTVAL (x) <= MAX_SAVED_CONST_INT) 182 printf ("const_int_rtx[MAX_SAVED_CONST_INT + (%d)]", 183 (int) INTVAL (x)); 184 else if (INTVAL (x) == STORE_FLAG_VALUE) 185 printf ("const_true_rtx"); 186 else 187 { 188 printf ("GEN_INT ("); 189 printf ("HOST_WIDE_INT_C ("); 190 printf (HOST_WIDE_INT_PRINT_DEC, INTVAL (x)); 191 printf (")"); 192 printf (")"); 193 } 194 return; 195 196 case CONST_DOUBLE: 197 /* Handle `const_double_zero' rtx. */ 198 if (CONST_DOUBLE_REAL_VALUE (x)->cl == rvc_zero) 199 { 200 printf ("CONST_DOUBLE_ATOF (\"0\", %smode)", 201 GET_MODE_NAME (GET_MODE (x))); 202 return; 203 } 204 /* Fall through. */ 205 case CONST_FIXED: 206 case CONST_WIDE_INT: 207 /* These shouldn't be written in MD files. Instead, the appropriate 208 routines in varasm.cc should be called. */ 209 gcc_unreachable (); 210 211 default: 212 break; 213 } 214 215 printf ("gen_rtx_"); 216 print_code (code); 217 printf (" ("); 218 if (!always_void_p (code)) 219 { 220 printf ("%smode", GET_MODE_NAME (GET_MODE (x))); 221 sep = ",\n\t"; 222 } 223 224 fmt = GET_RTX_FORMAT (code); 225 len = GET_RTX_LENGTH (code); 226 for (i = 0; i < len; i++) 227 { 228 if (fmt[i] == '0') 229 break; 230 fputs (sep, stdout); 231 switch (fmt[i]) 232 { 233 case 'e': case 'u': 234 gen_exp (XEXP (x, i), subroutine_type, used, info); 235 break; 236 237 case 'i': 238 printf ("%u", XINT (x, i)); 239 break; 240 241 case 'r': 242 printf ("%u", REGNO (x)); 243 break; 244 245 case 'p': 246 /* We don't have a way of parsing polynomial offsets yet, 247 and hopefully never will. */ 248 printf ("%d", SUBREG_BYTE (x).to_constant ()); 249 break; 250 251 case 's': 252 printf ("\"%s\"", XSTR (x, i)); 253 break; 254 255 case 'E': 256 { 257 int j; 258 printf ("gen_rtvec (%d", XVECLEN (x, i)); 259 for (j = 0; j < XVECLEN (x, i); j++) 260 { 261 printf (",\n\t\t"); 262 gen_exp (XVECEXP (x, i, j), subroutine_type, used, info); 263 } 264 printf (")"); 265 break; 266 } 267 268 default: 269 gcc_unreachable (); 270 } 271 sep = ",\n\t"; 272 } 273 printf (")"); 274} 275 276/* Output code to emit the instruction patterns in VEC, with each element 277 becoming a separate instruction. USED is as for gen_exp. */ 278 279static void 280gen_emit_seq (rtvec vec, char *used, md_rtx_info *info) 281{ 282 for (int i = 0, len = GET_NUM_ELEM (vec); i < len; ++i) 283 { 284 bool last_p = (i == len - 1); 285 rtx next = RTVEC_ELT (vec, i); 286 if (const char *name = get_emit_function (next)) 287 { 288 printf (" %s (", name); 289 gen_exp (next, DEFINE_EXPAND, used, info); 290 printf (");\n"); 291 if (!last_p && needs_barrier_p (next)) 292 printf (" emit_barrier ();"); 293 } 294 else 295 { 296 printf (" emit ("); 297 gen_exp (next, DEFINE_EXPAND, used, info); 298 printf (", %s);\n", last_p ? "false" : "true"); 299 } 300 } 301} 302 303/* Emit the given C code to the output file. The code is allowed to 304 fail if CAN_FAIL_P. NAME describes what we're generating, 305 for use in error messages. */ 306 307static void 308emit_c_code (const char *code, bool can_fail_p, const char *name) 309{ 310 if (can_fail_p) 311 printf ("#define FAIL return (end_sequence (), _val)\n"); 312 else 313 printf ("#define FAIL _Pragma (\"GCC error \\\"%s cannot FAIL\\\"\")" 314 " (void)0\n", name); 315 printf ("#define DONE return (_val = get_insns (), " 316 "end_sequence (), _val)\n"); 317 318 rtx_reader_ptr->print_md_ptr_loc (code); 319 printf ("%s\n", code); 320 321 printf ("#undef DONE\n"); 322 printf ("#undef FAIL\n"); 323} 324 325/* Generate the `gen_...' function for a DEFINE_INSN. */ 326 327static void 328gen_insn (md_rtx_info *info) 329{ 330 struct pattern_stats stats; 331 int i; 332 333 /* See if the pattern for this insn ends with a group of CLOBBERs of (hard) 334 registers or MATCH_SCRATCHes. If so, store away the information for 335 later. */ 336 337 rtx insn = info->def; 338 if (XVEC (insn, 1)) 339 { 340 int has_hard_reg = 0; 341 342 for (i = XVECLEN (insn, 1) - 1; i > 0; i--) 343 { 344 if (GET_CODE (XVECEXP (insn, 1, i)) != CLOBBER) 345 break; 346 347 if (REG_P (XEXP (XVECEXP (insn, 1, i), 0))) 348 has_hard_reg = 1; 349 else if (GET_CODE (XEXP (XVECEXP (insn, 1, i), 0)) != MATCH_SCRATCH) 350 break; 351 } 352 353 if (i != XVECLEN (insn, 1) - 1) 354 { 355 struct clobber_pat *p; 356 struct clobber_ent *link = XNEW (struct clobber_ent); 357 int j; 358 359 link->code_number = info->index; 360 361 /* See if any previous CLOBBER_LIST entry is the same as this 362 one. */ 363 364 for (p = clobber_list; p; p = p->next) 365 { 366 if (p->first_clobber != i + 1 367 || XVECLEN (p->pattern, 1) != XVECLEN (insn, 1)) 368 continue; 369 370 for (j = i + 1; j < XVECLEN (insn, 1); j++) 371 { 372 rtx old_rtx = XEXP (XVECEXP (p->pattern, 1, j), 0); 373 rtx new_rtx = XEXP (XVECEXP (insn, 1, j), 0); 374 375 /* OLD and NEW_INSN are the same if both are to be a SCRATCH 376 of the same mode, 377 or if both are registers of the same mode and number. */ 378 if (! (GET_CODE (old_rtx) == GET_CODE (new_rtx) 379 && GET_MODE (old_rtx) == GET_MODE (new_rtx) 380 && ((GET_CODE (old_rtx) == MATCH_SCRATCH 381 && GET_CODE (new_rtx) == MATCH_SCRATCH) 382 || (REG_P (old_rtx) && REG_P (new_rtx) 383 && REGNO (old_rtx) == REGNO (new_rtx))))) 384 break; 385 } 386 387 if (j == XVECLEN (insn, 1)) 388 break; 389 } 390 391 if (p == 0) 392 { 393 p = XNEW (struct clobber_pat); 394 395 p->insns = 0; 396 p->pattern = insn; 397 p->first_clobber = i + 1; 398 p->next = clobber_list; 399 p->has_hard_reg = has_hard_reg; 400 clobber_list = p; 401 } 402 403 link->next = p->insns; 404 p->insns = link; 405 } 406 } 407 408 /* Don't mention instructions whose names are the null string 409 or begin with '*'. They are in the machine description just 410 to be recognized. */ 411 if (XSTR (insn, 0)[0] == 0 || XSTR (insn, 0)[0] == '*') 412 return; 413 414 printf ("/* %s:%d */\n", info->loc.filename, info->loc.lineno); 415 416 /* Find out how many operands this function has. */ 417 get_pattern_stats (&stats, XVEC (insn, 1)); 418 if (stats.max_dup_opno > stats.max_opno) 419 fatal_at (info->loc, "match_dup operand number has no match_operand"); 420 421 /* Output the function name and argument declarations. */ 422 printf ("rtx\ngen_%s (", XSTR (insn, 0)); 423 if (stats.num_generator_args) 424 for (i = 0; i < stats.num_generator_args; i++) 425 if (i) 426 printf (",\n\trtx operand%d ATTRIBUTE_UNUSED", i); 427 else 428 printf ("rtx operand%d ATTRIBUTE_UNUSED", i); 429 else 430 printf ("void"); 431 printf (")\n"); 432 printf ("{\n"); 433 434 /* Output code to construct and return the rtl for the instruction body. */ 435 436 rtx pattern = add_implicit_parallel (XVEC (insn, 1)); 437 /* ??? This is the traditional behavior, but seems suspect. */ 438 char *used = (XVECLEN (insn, 1) == 1 439 ? NULL 440 : XCNEWVEC (char, stats.num_generator_args)); 441 printf (" return "); 442 gen_exp (pattern, DEFINE_INSN, used, info); 443 printf (";\n}\n\n"); 444 XDELETEVEC (used); 445} 446 447/* Generate the `gen_...' function for a DEFINE_EXPAND. */ 448 449static void 450gen_expand (md_rtx_info *info) 451{ 452 struct pattern_stats stats; 453 int i; 454 char *used; 455 456 rtx expand = info->def; 457 if (strlen (XSTR (expand, 0)) == 0) 458 fatal_at (info->loc, "define_expand lacks a name"); 459 if (XVEC (expand, 1) == 0) 460 fatal_at (info->loc, "define_expand for %s lacks a pattern", 461 XSTR (expand, 0)); 462 463 /* Find out how many operands this function has. */ 464 get_pattern_stats (&stats, XVEC (expand, 1)); 465 if (stats.min_scratch_opno != -1 466 && stats.min_scratch_opno <= MAX (stats.max_opno, stats.max_dup_opno)) 467 fatal_at (info->loc, "define_expand for %s needs to have match_scratch " 468 "numbers above all other operands", XSTR (expand, 0)); 469 470 /* Output the function name and argument declarations. */ 471 printf ("rtx\ngen_%s (", XSTR (expand, 0)); 472 if (stats.num_generator_args) 473 for (i = 0; i < stats.num_generator_args; i++) 474 if (i) 475 printf (",\n\trtx operand%d", i); 476 else 477 printf ("rtx operand%d", i); 478 else 479 printf ("void"); 480 printf (")\n"); 481 printf ("{\n"); 482 483 /* If we don't have any C code to write, only one insn is being written, 484 and no MATCH_DUPs are present, we can just return the desired insn 485 like we do for a DEFINE_INSN. This saves memory. */ 486 if ((XSTR (expand, 3) == 0 || *XSTR (expand, 3) == '\0') 487 && stats.max_opno >= stats.max_dup_opno 488 && XVECLEN (expand, 1) == 1) 489 { 490 printf (" return "); 491 gen_exp (XVECEXP (expand, 1, 0), DEFINE_EXPAND, NULL, info); 492 printf (";\n}\n\n"); 493 return; 494 } 495 496 /* For each operand referred to only with MATCH_DUPs, 497 make a local variable. */ 498 for (i = stats.num_generator_args; i <= stats.max_dup_opno; i++) 499 printf (" rtx operand%d;\n", i); 500 printf (" rtx_insn *_val = 0;\n"); 501 printf (" start_sequence ();\n"); 502 503 /* The fourth operand of DEFINE_EXPAND is some code to be executed 504 before the actual construction. 505 This code expects to refer to `operands' 506 just as the output-code in a DEFINE_INSN does, 507 but here `operands' is an automatic array. 508 So copy the operand values there before executing it. */ 509 if (XSTR (expand, 3) && *XSTR (expand, 3)) 510 { 511 printf (" {\n"); 512 if (stats.num_operand_vars > 0) 513 printf (" rtx operands[%d];\n", stats.num_operand_vars); 514 515 /* Output code to copy the arguments into `operands'. */ 516 for (i = 0; i < stats.num_generator_args; i++) 517 printf (" operands[%d] = operand%d;\n", i, i); 518 519 /* Output the special code to be executed before the sequence 520 is generated. */ 521 optab_pattern p; 522 bool can_fail_p = true; 523 if (find_optab (&p, XSTR (expand, 0))) 524 { 525 gcc_assert (p.op < NUM_OPTABS); 526 if (nofail_optabs[p.op]) 527 can_fail_p = false; 528 } 529 emit_c_code (XSTR (expand, 3), can_fail_p, XSTR (expand, 0)); 530 531 /* Output code to copy the arguments back out of `operands' 532 (unless we aren't going to use them at all). */ 533 if (XVEC (expand, 1) != 0) 534 { 535 for (i = 0; i <= MAX (stats.max_opno, stats.max_dup_opno); i++) 536 { 537 printf (" operand%d = operands[%d];\n", i, i); 538 printf (" (void) operand%d;\n", i); 539 } 540 } 541 printf (" }\n"); 542 } 543 544 used = XCNEWVEC (char, stats.num_operand_vars); 545 gen_emit_seq (XVEC (expand, 1), used, info); 546 XDELETEVEC (used); 547 548 /* Call `get_insns' to extract the list of all the 549 insns emitted within this gen_... function. */ 550 551 printf (" _val = get_insns ();\n"); 552 printf (" end_sequence ();\n"); 553 printf (" return _val;\n}\n\n"); 554} 555 556/* Like gen_expand, but generates insns resulting from splitting SPLIT. */ 557 558static void 559gen_split (md_rtx_info *info) 560{ 561 struct pattern_stats stats; 562 int i; 563 rtx split = info->def; 564 const char *const name = 565 ((GET_CODE (split) == DEFINE_PEEPHOLE2) ? "peephole2" : "split"); 566 const char *unused; 567 char *used; 568 569 if (XVEC (split, 0) == 0) 570 fatal_at (info->loc, "%s lacks a pattern", 571 GET_RTX_NAME (GET_CODE (split))); 572 else if (XVEC (split, 2) == 0) 573 fatal_at (info->loc, "%s lacks a replacement pattern", 574 GET_RTX_NAME (GET_CODE (split))); 575 576 /* Find out how many operands this function has. */ 577 578 get_pattern_stats (&stats, XVEC (split, 2)); 579 unused = (stats.num_operand_vars == 0 ? " ATTRIBUTE_UNUSED" : ""); 580 used = XCNEWVEC (char, stats.num_operand_vars); 581 582 /* Output the prototype, function name and argument declarations. */ 583 if (GET_CODE (split) == DEFINE_PEEPHOLE2) 584 { 585 printf ("extern rtx_insn *gen_%s_%d (rtx_insn *, rtx *);\n", 586 name, info->index); 587 printf ("rtx_insn *\ngen_%s_%d (rtx_insn *curr_insn ATTRIBUTE_UNUSED," 588 " rtx *operands%s)\n", 589 name, info->index, unused); 590 } 591 else 592 { 593 printf ("extern rtx_insn *gen_split_%d (rtx_insn *, rtx *);\n", 594 info->index); 595 printf ("rtx_insn *\ngen_split_%d " 596 "(rtx_insn *curr_insn ATTRIBUTE_UNUSED, rtx *operands%s)\n", 597 info->index, unused); 598 } 599 printf ("{\n"); 600 601 /* Declare all local variables. */ 602 for (i = 0; i < stats.num_operand_vars; i++) 603 printf (" rtx operand%d;\n", i); 604 printf (" rtx_insn *_val = NULL;\n"); 605 606 if (GET_CODE (split) == DEFINE_PEEPHOLE2) 607 output_peephole2_scratches (split); 608 609 const char *fn = info->loc.filename; 610 for (const char *p = fn; *p; p++) 611 if (*p == '/') 612 fn = p + 1; 613 614 printf (" if (dump_file)\n"); 615 printf (" fprintf (dump_file, \"Splitting with gen_%s_%d (%s:%d)\\n\");\n", 616 name, info->index, fn, info->loc.lineno); 617 618 printf (" start_sequence ();\n"); 619 620 /* The fourth operand of DEFINE_SPLIT is some code to be executed 621 before the actual construction. */ 622 623 if (XSTR (split, 3)) 624 emit_c_code (XSTR (split, 3), true, name); 625 626 /* Output code to copy the arguments back out of `operands' */ 627 for (i = 0; i < stats.num_operand_vars; i++) 628 { 629 printf (" operand%d = operands[%d];\n", i, i); 630 printf (" (void) operand%d;\n", i); 631 } 632 633 gen_emit_seq (XVEC (split, 2), used, info); 634 635 /* Call `get_insns' to make a list of all the 636 insns emitted within this gen_... function. */ 637 638 printf (" _val = get_insns ();\n"); 639 printf (" end_sequence ();\n"); 640 printf (" return _val;\n}\n\n"); 641 642 free (used); 643} 644 645/* Write a function, `add_clobbers', that is given a PARALLEL of sufficient 646 size for the insn and an INSN_CODE, and inserts the required CLOBBERs at 647 the end of the vector. */ 648 649static void 650output_add_clobbers (md_rtx_info *info) 651{ 652 struct clobber_pat *clobber; 653 struct clobber_ent *ent; 654 int i; 655 656 printf ("\n\nvoid\nadd_clobbers (rtx pattern ATTRIBUTE_UNUSED, int insn_code_number)\n"); 657 printf ("{\n"); 658 printf (" switch (insn_code_number)\n"); 659 printf (" {\n"); 660 661 for (clobber = clobber_list; clobber; clobber = clobber->next) 662 { 663 for (ent = clobber->insns; ent; ent = ent->next) 664 printf (" case %d:\n", ent->code_number); 665 666 for (i = clobber->first_clobber; i < XVECLEN (clobber->pattern, 1); i++) 667 { 668 printf (" XVECEXP (pattern, 0, %d) = ", i); 669 gen_exp (XVECEXP (clobber->pattern, 1, i), 670 GET_CODE (clobber->pattern), NULL, info); 671 printf (";\n"); 672 } 673 674 printf (" break;\n\n"); 675 } 676 677 printf (" default:\n"); 678 printf (" gcc_unreachable ();\n"); 679 printf (" }\n"); 680 printf ("}\n"); 681} 682 683/* Write a function, `added_clobbers_hard_reg_p' that is given an insn_code 684 number that will have clobbers added (as indicated by `recog') and returns 685 1 if those include a clobber of a hard reg or 0 if all of them just clobber 686 SCRATCH. */ 687 688static void 689output_added_clobbers_hard_reg_p (void) 690{ 691 struct clobber_pat *clobber; 692 struct clobber_ent *ent; 693 int clobber_p, used; 694 695 printf ("\n\nint\nadded_clobbers_hard_reg_p (int insn_code_number)\n"); 696 printf ("{\n"); 697 printf (" switch (insn_code_number)\n"); 698 printf (" {\n"); 699 700 for (clobber_p = 0; clobber_p <= 1; clobber_p++) 701 { 702 used = 0; 703 for (clobber = clobber_list; clobber; clobber = clobber->next) 704 if (clobber->has_hard_reg == clobber_p) 705 for (ent = clobber->insns; ent; ent = ent->next) 706 { 707 printf (" case %d:\n", ent->code_number); 708 used++; 709 } 710 711 if (used) 712 printf (" return %d;\n\n", clobber_p); 713 } 714 715 printf (" default:\n"); 716 printf (" gcc_unreachable ();\n"); 717 printf (" }\n"); 718 printf ("}\n"); 719} 720 721/* Generate code to invoke find_free_register () as needed for the 722 scratch registers used by the peephole2 pattern in SPLIT. */ 723 724static void 725output_peephole2_scratches (rtx split) 726{ 727 int i; 728 int insn_nr = 0; 729 bool first = true; 730 731 for (i = 0; i < XVECLEN (split, 0); i++) 732 { 733 rtx elt = XVECEXP (split, 0, i); 734 if (GET_CODE (elt) == MATCH_SCRATCH) 735 { 736 int last_insn_nr = insn_nr; 737 int cur_insn_nr = insn_nr; 738 int j; 739 for (j = i + 1; j < XVECLEN (split, 0); j++) 740 if (GET_CODE (XVECEXP (split, 0, j)) == MATCH_DUP) 741 { 742 if (XINT (XVECEXP (split, 0, j), 0) == XINT (elt, 0)) 743 last_insn_nr = cur_insn_nr; 744 } 745 else if (GET_CODE (XVECEXP (split, 0, j)) != MATCH_SCRATCH) 746 cur_insn_nr++; 747 748 if (first) 749 { 750 printf (" HARD_REG_SET _regs_allocated;\n"); 751 printf (" CLEAR_HARD_REG_SET (_regs_allocated);\n"); 752 first = false; 753 } 754 755 printf (" if ((operands[%d] = peep2_find_free_register (%d, %d, \"%s\", %smode, &_regs_allocated)) == NULL_RTX)\n\ 756 return NULL;\n", 757 XINT (elt, 0), 758 insn_nr, last_insn_nr, 759 XSTR (elt, 1), 760 GET_MODE_NAME (GET_MODE (elt))); 761 762 } 763 else if (GET_CODE (elt) != MATCH_DUP) 764 insn_nr++; 765 } 766} 767 768/* Print "arg<N>" parameter declarations for each argument N of ONAME. */ 769 770static void 771print_overload_arguments (overloaded_name *oname) 772{ 773 for (unsigned int i = 0; i < oname->arg_types.length (); ++i) 774 printf ("%s%s arg%d", i == 0 ? "" : ", ", oname->arg_types[i], i); 775} 776 777/* Print code to test whether INSTANCE should be chosen, given that 778 argument N of the overload is available as "arg<N>". */ 779 780static void 781print_overload_test (overloaded_instance *instance) 782{ 783 for (unsigned int i = 0; i < instance->arg_values.length (); ++i) 784 printf ("%sarg%d == %s", i == 0 ? " if (" : "\n && ", 785 i, instance->arg_values[i]); 786 printf (")\n"); 787} 788 789/* Emit a maybe_code_for_* function for ONAME. */ 790 791static void 792handle_overloaded_code_for (overloaded_name *oname) 793{ 794 /* Print the function prototype. */ 795 printf ("\ninsn_code\nmaybe_code_for_%s (", oname->name); 796 print_overload_arguments (oname); 797 printf (")\n{\n"); 798 799 /* Use a sequence of "if" statements for each instance. */ 800 for (overloaded_instance *instance = oname->first_instance; 801 instance; instance = instance->next) 802 { 803 print_overload_test (instance); 804 printf (" return CODE_FOR_%s;\n", instance->name); 805 } 806 807 /* Return null if no match was found. */ 808 printf (" return CODE_FOR_nothing;\n}\n"); 809} 810 811/* Emit a maybe_gen_* function for ONAME. */ 812 813static void 814handle_overloaded_gen (overloaded_name *oname) 815{ 816 unsigned HOST_WIDE_INT seen = 0; 817 /* All patterns must have the same number of operands. */ 818 for (overloaded_instance *instance = oname->first_instance->next; 819 instance; instance = instance->next) 820 { 821 pattern_stats stats; 822 get_pattern_stats (&stats, XVEC (instance->insn, 1)); 823 unsigned HOST_WIDE_INT mask 824 = HOST_WIDE_INT_1U << stats.num_generator_args; 825 if (seen & mask) 826 continue; 827 828 seen |= mask; 829 830 /* Print the function prototype. */ 831 printf ("\nrtx\nmaybe_gen_%s (", oname->name); 832 print_overload_arguments (oname); 833 for (int i = 0; i < stats.num_generator_args; ++i) 834 printf (", rtx x%d", i); 835 printf (")\n{\n"); 836 837 /* Use maybe_code_for_*, instead of duplicating the selection 838 logic here. */ 839 printf (" insn_code code = maybe_code_for_%s (", oname->name); 840 for (unsigned int i = 0; i < oname->arg_types.length (); ++i) 841 printf ("%sarg%d", i == 0 ? "" : ", ", i); 842 printf (");\n" 843 " if (code != CODE_FOR_nothing)\n" 844 " {\n" 845 " gcc_assert (insn_data[code].n_generator_args == %d);\n" 846 " return GEN_FCN (code) (", stats.num_generator_args); 847 for (int i = 0; i < stats.num_generator_args; ++i) 848 printf ("%sx%d", i == 0 ? "" : ", ", i); 849 printf (");\n" 850 " }\n" 851 " else\n" 852 " return NULL_RTX;\n" 853 "}\n"); 854 } 855} 856 857int 858main (int argc, const char **argv) 859{ 860 progname = "genemit"; 861 862 if (!init_rtx_reader_args (argc, argv)) 863 return (FATAL_EXIT_CODE); 864 865#define DEF_INTERNAL_OPTAB_FN(NAME, FLAGS, OPTAB, TYPE) \ 866 nofail_optabs[OPTAB##_optab] = true; 867#include "internal-fn.def" 868 869 /* Assign sequential codes to all entries in the machine description 870 in parallel with the tables in insn-output.cc. */ 871 872 printf ("/* Generated automatically by the program `genemit'\n\ 873from the machine description file `md'. */\n\n"); 874 875 printf ("#define IN_TARGET_CODE 1\n"); 876 printf ("#include \"config.h\"\n"); 877 printf ("#include \"system.h\"\n"); 878 printf ("#include \"coretypes.h\"\n"); 879 printf ("#include \"backend.h\"\n"); 880 printf ("#include \"predict.h\"\n"); 881 printf ("#include \"tree.h\"\n"); 882 printf ("#include \"rtl.h\"\n"); 883 printf ("#include \"alias.h\"\n"); 884 printf ("#include \"varasm.h\"\n"); 885 printf ("#include \"stor-layout.h\"\n"); 886 printf ("#include \"calls.h\"\n"); 887 printf ("#include \"memmodel.h\"\n"); 888 printf ("#include \"tm_p.h\"\n"); 889 printf ("#include \"flags.h\"\n"); 890 printf ("#include \"insn-config.h\"\n"); 891 printf ("#include \"expmed.h\"\n"); 892 printf ("#include \"dojump.h\"\n"); 893 printf ("#include \"explow.h\"\n"); 894 printf ("#include \"emit-rtl.h\"\n"); 895 printf ("#include \"stmt.h\"\n"); 896 printf ("#include \"expr.h\"\n"); 897 printf ("#include \"insn-codes.h\"\n"); 898 printf ("#include \"optabs.h\"\n"); 899 printf ("#include \"dfp.h\"\n"); 900 printf ("#include \"output.h\"\n"); 901 printf ("#include \"recog.h\"\n"); 902 printf ("#include \"df.h\"\n"); 903 printf ("#include \"resource.h\"\n"); 904 printf ("#include \"reload.h\"\n"); 905 printf ("#include \"diagnostic-core.h\"\n"); 906 printf ("#include \"regs.h\"\n"); 907 printf ("#include \"tm-constrs.h\"\n"); 908 printf ("#include \"ggc.h\"\n"); 909 printf ("#include \"target.h\"\n\n"); 910 911 /* Read the machine description. */ 912 913 md_rtx_info info; 914 while (read_md_rtx (&info)) 915 switch (GET_CODE (info.def)) 916 { 917 case DEFINE_INSN: 918 gen_insn (&info); 919 break; 920 921 case DEFINE_EXPAND: 922 printf ("/* %s:%d */\n", info.loc.filename, info.loc.lineno); 923 gen_expand (&info); 924 break; 925 926 case DEFINE_SPLIT: 927 printf ("/* %s:%d */\n", info.loc.filename, info.loc.lineno); 928 gen_split (&info); 929 break; 930 931 case DEFINE_PEEPHOLE2: 932 printf ("/* %s:%d */\n", info.loc.filename, info.loc.lineno); 933 gen_split (&info); 934 break; 935 936 default: 937 break; 938 } 939 940 /* Write out the routines to add CLOBBERs to a pattern and say whether they 941 clobber a hard reg. */ 942 output_add_clobbers (&info); 943 output_added_clobbers_hard_reg_p (); 944 945 for (overloaded_name *oname = rtx_reader_ptr->get_overloads (); 946 oname; oname = oname->next) 947 { 948 handle_overloaded_code_for (oname); 949 handle_overloaded_gen (oname); 950 } 951 952 fflush (stdout); 953 return (ferror (stdout) != 0 ? FATAL_EXIT_CODE : SUCCESS_EXIT_CODE); 954} 955